diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0cffa367ecdfe4ad8dd473a4a216e371bd231b89..b8abe511d42f3bbbf01fd80f525f0978cbb573ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,173 +1,124 @@
-#
-# Simple CMakeLists for Sonic Robo Blast 2
-#
-PROJECT(SRB2)
-
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
-
-#
-# Dependencies
-#
-FIND_PACKAGE(SDL)
-FIND_PACKAGE(SDL_mixer)
-FIND_PACKAGE(PNG)
-
-#
-# Common stuff
-#
-
-# not added defines:
-# -DHAVE_PNG - does not build (incorrect use of PNG_EXPORT etc.)
-ADD_DEFINITIONS(-DDIRECTFULLSCREEN -DSDL -DHAVE_MIXER -DNOHW -DHW3SOUND -DHAVE_BLUA -DNOASM)
-
-SET(SDL_DIR sdl) # may be set to SDL2 optionally
-
-SET(COMMON_SRCS
-	src/${SDL_DIR}/dosstr.c
-	src/${SDL_DIR}/endtxt.c
-	src/${SDL_DIR}/hwsym_sdl.c
-	src/${SDL_DIR}/i_cdmus.c
-	src/${SDL_DIR}/i_main.c
-	src/${SDL_DIR}/i_net.c
-	src/${SDL_DIR}/i_system.c
-	src/${SDL_DIR}/i_video.c
-	src/${SDL_DIR}/mixer_sound.c
-	src/am_map.c
-	src/b_bot.c
-	src/blua/lapi.c
-	src/blua/lauxlib.c
-	src/blua/lbaselib.c
-	src/blua/lcode.c
-	src/blua/ldebug.c
-	src/blua/ldo.c
-	src/blua/ldump.c
-	src/blua/lfunc.c
-	src/blua/lgc.c
-	src/blua/linit.c
-	src/blua/llex.c
-	src/blua/lmem.c
-	src/blua/lobject.c
-	src/blua/lopcodes.c
-	src/blua/lparser.c
-	src/blua/lstate.c
-	src/blua/lstring.c
-	src/blua/lstrlib.c
-	src/blua/ltable.c
-	src/blua/ltablib.c
-	src/blua/ltm.c
-	src/blua/lundump.c
-	src/blua/lvm.c
-	src/blua/lzio.c
-	src/command.c
-	src/comptime.c
-	src/console.c
-	src/d_clisrv.c
-	src/d_main.c
-	src/d_net.c
-	src/d_netcmd.c
-	src/d_netfil.c
-	src/dehacked.c
-	src/f_finale.c
-	src/f_wipe.c
-	src/filesrch.c
-	src/g_game.c
-	src/g_input.c
-	src/hardware/hw3sound.c
-	src/hu_stuff.c
-	src/i_tcp.c
-	src/info.c
-	src/lua_baselib.c
-	src/lua_consolelib.c
-	src/lua_hooklib.c
-	src/lua_hudlib.c
-	src/lua_infolib.c
-	src/lua_maplib.c
-	src/lua_mathlib.c
-	src/lua_mobjlib.c
-	src/lua_playerlib.c
-	src/lua_script.c
-	src/lua_skinlib.c
-	src/lua_thinkerlib.c
-	src/lzf.c
-	src/m_anigif.c
-	src/m_argv.c
-	src/m_bbox.c
-	src/m_cheat.c
-	src/m_cond.c
-	src/m_fixed.c
-	src/m_menu.c
-	src/m_misc.c
-	src/m_queue.c
-	src/m_random.c
-	src/md5.c
-	src/mserv.c
-	src/p_ceilng.c
-	src/p_enemy.c
-	src/p_fab.c
-	src/p_floor.c
-	src/p_inter.c
-	src/p_lights.c
-	src/p_map.c
-	src/p_maputl.c
-	src/p_mobj.c
-	src/p_polyobj.c
-	src/p_saveg.c
-	src/p_setup.c
-	src/p_sight.c
-	src/p_spec.c
-	src/p_telept.c
-	src/p_tick.c
-	src/p_user.c
-	src/r_bsp.c
-	src/r_data.c
-	src/r_draw.c
-	src/r_main.c
-	src/r_plane.c
-	src/r_segs.c
-	src/r_sky.c
-	src/r_splats.c
-	src/r_things.c
-	src/s_sound.c
-	src/screen.c
-	src/sounds.c
-	src/st_stuff.c
-	src/string.c
-	src/tables.c
-	src/v_video.c
-	src/w_wad.c
-	src/y_inter.c
-	src/z_zone.c
-)
-
-#
-# Platform-specific stuff
-#
-
-MACRO(EXTRALIB NAME)
-	FIND_LIBRARY(${NAME}_LIBRARY NAMES ${NAME})
-	IF(${NAME}_LIBRARY)
-		MESSAGE(STATUS "Found lib${NAME}: ${${NAME}_LIBRARY}")
-		SET(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${${NAME}_LIBRARY})
-	ELSE(${NAME}_LIBRARY)
-		MESSAGE(FATAL_ERROR "Could not find lib${NAME}!")
-	ENDIF(${NAME}_LIBRARY)
-ENDMACRO(EXTRALIB)
-
-IF(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-	ADD_DEFINITIONS(-DUNIXCOMMON -DLINUX -DFREEBSD)
-	EXTRALIB(kvm)
-ELSEIF(${CMAKE_SYSTEM} MATCHES "Linux")
-	ADD_DEFINITIONS(-DUNIXCOMMON -DLINUX)
-	EXTRALIB(m)
-	EXTRALIB(rt)
-ELSE(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-	ADD_DEFINITIONS(-DUNIXCOMMON -DLINUX)
-	MESSAGE(WARNING "No specific settings for you system, it may be not supported!")
-ENDIF(${CMAKE_SYSTEM} MATCHES "FreeBSD")
-
-#
-# Targets
-#
-INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${SDL_MIXER_INCLUDE_DIRS})
-ADD_EXECUTABLE(SRB2 ${COMMON_SRCS})
-TARGET_LINK_LIBRARIES(SRB2 ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES} ${EXTRA_LIBRARIES})
+cmake_minimum_required(VERSION 3.0)
+project(SRB2
+	VERSION 2.1.14
+	LANGUAGES C)
+
+# Set up CMAKE path
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+### Useful functions
+
+# Prepend sources with current source directory
+function(prepend_sources SOURCE_FILES)
+	foreach(SOURCE_FILE ${${SOURCE_FILES}})
+		set(MODIFIED ${MODIFIED} ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE})
+	endforeach()
+	set(${SOURCE_FILES} ${MODIFIED} PARENT_SCOPE)
+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)
+    if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
+        MESSAGE(ERROR ": Framework ${fwname} not found")
+    else()
+        TARGET_LINK_LIBRARIES(${appname} PRIVATE "${FRAMEWORK_${fwname}}/${fwname}")
+        MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
+    endif()
+endmacro()
+
+# Macro to copy Windows DLLs to Debug/Release folder for easy debugging
+# Note: this is general purpose, we could copy anything. Just using for DLLs on MSVC though
+macro(copy_files_to_build_dir target dlllist_var)
+	if(MSVC)
+		# http://stackoverflow.com/a/26983405/3064195
+		foreach(dlllist_item ${${dlllist_var}})
+			get_filename_component(dllname ${dlllist_item} NAME)
+			add_custom_command(TARGET ${target} POST_BUILD
+				COMMAND ${CMAKE_COMMAND} -E copy_if_different
+				${dlllist_item}
+				${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/${dllname}
+			)
+		endforeach()
+	endif()
+endmacro()
+
+# 64-bit check
+if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+	message(STATUS "Target is 64-bit")
+	set(SRB2_SYSTEM_BITS 64)
+else()
+	set(SRB2_SYSTEM_BITS 32)
+endif()
+
+if(MSVC)
+	message(WARNING "!! MSVC BUILDS OF SRB2 CANNOT PLAY MULTIPLAYER !! You're more than welcome to try and fix this!")
+endif()
+
+# OS macros
+if (UNIX)
+	add_definitions(-DUNIXCOMMON)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCC)
+	find_program(OBJCOPY objcopy)
+endif()
+
+if(${CMAKE_SYSTEM} MATCHES "Linux")
+	add_definitions(-DLINUX)
+	if(${SRB2_SYSTEM_BITS} EQUAL 64)
+		add_definitions(-DLINUX64)
+	endif()
+endif()
+
+if(${CMAKE_SYSTEM} MATCHES "Darwin")
+	add_definitions(-DMACOSX)
+	if(${CMAKE_C_COMPILER_ID} MATCHES "Clang")
+		set(CLANG ON)
+	endif()
+endif()
+
+# Set EXE names so the assets CMakeLists can refer to its target
+set(SRB2_SDL2_EXE_NAME srb2)
+set(SRB2_WIN_EXE_NAME srb2dd)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
+
+add_subdirectory(src)
+add_subdirectory(assets)
+
+
+## config.h generation
+set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary")
+include(GitUtilities)
+git_describe(SRB2_COMP_REVISION "${CMAKE_CURRENT_SOURCE_DIR}")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/config.h)
+
+##### PACKAGE CONFIGURATION #####
+
+if(${CMAKE_SYSTEM} MATCHES "Windows")
+	set(CPACK_GENERATOR "ZIP")
+endif()
+if(${CMAKE_SYSTEM} MATCHES "Linux")
+	set(CPACK_GENERATOR "TGZ")
+endif()
+if(${CMAKE_SYSTEM} MATCHES "Darwin")
+	set(CPACK_GENERATOR "DragNDrop")
+endif()
+
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Sonic Robo Blast 2")
+set(CPACK_PACKAGE_VENDOR "Sonic Team Jr.")
+#set(CPACK_PACKAGE_DESCRIPTION_FILE )
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+set(CPACK_PACKAGE_VERSION_MAJOR ${SRB2_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${SRB2_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${SRB2_VERSION_PATCH})
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMAKE_VERSION_MAJOR}.${CMAKE_VERSION_MINOR}")
+include(CPack)
diff --git a/assets/.gitignore b/assets/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..37bb465dc2db82f22a8bfeacbcde73069b7eb711
--- /dev/null
+++ b/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+*.*
diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3ce133c6a67fde3d3ea55170bc7b8b24938fa8a6
--- /dev/null
+++ b/assets/CMakeLists.txt
@@ -0,0 +1,37 @@
+## Assets Target Configuration ##
+
+# MD5 generation
+set(SRB2_ASSET_ALL
+	${CMAKE_CURRENT_SOURCE_DIR}/srb2.srb
+	${CMAKE_CURRENT_SOURCE_DIR}/player.dta
+	${CMAKE_CURRENT_SOURCE_DIR}/rings.dta
+	${CMAKE_CURRENT_SOURCE_DIR}/zones.dta
+	${CMAKE_CURRENT_SOURCE_DIR}/patch.dta
+	${CMAKE_CURRENT_SOURCE_DIR}/music.dta
+)
+
+set(SRB2_ASSET_HASHED
+	srb2.srb
+	player.dta
+	rings.dta
+	zones.dta
+	patch.dta
+)
+
+foreach(SRB2_ASSET ${SRB2_ASSET_HASHED})
+	file(MD5 ${CMAKE_CURRENT_SOURCE_DIR}/${SRB2_ASSET} "SRB2_ASSET_${SRB2_ASSET}_HASH")
+	set(SRB2_ASSET_${SRB2_ASSET}_HASH ${SRB2_ASSET_${SRB2_ASSET}_HASH} PARENT_SCOPE)
+endforeach()
+
+# Installation
+
+if(CLANG)
+	get_target_property(outname ${SRB2_SDL2_EXE_NAME} OUTPUT_NAME)
+	install(FILES ${SRB2_ASSET_ALL}
+		DESTINATION "${outname}.app/Contents/Resources"
+	)
+else()
+	install(FILES ${SRB2_ASSET_ALL}
+		DESTINATION .
+	)
+endif()
diff --git a/cmake/Modules/CMakeASM_YASMInformation.cmake b/cmake/Modules/CMakeASM_YASMInformation.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..1765180853bb2d23217a1eb785f97737411e68b1
--- /dev/null
+++ b/cmake/Modules/CMakeASM_YASMInformation.cmake
@@ -0,0 +1,46 @@
+
+#=============================================================================
+# Copyright 2010 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# support for the yasm assembler
+
+set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS nasm yasm asm)
+
+if(NOT CMAKE_ASM_YASM_OBJECT_FORMAT)
+  if(WIN32)
+    if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8)
+      set(CMAKE_ASM_YASM_OBJECT_FORMAT win64)
+    else()
+      set(CMAKE_ASM_YASM_OBJECT_FORMAT win32)
+    endif()
+  elseif(APPLE)
+    if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8)
+      set(CMAKE_ASM_YASM_OBJECT_FORMAT macho64)
+    else()
+      set(CMAKE_ASM_YASM_OBJECT_FORMAT macho)
+    endif()
+  else()
+    if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8)
+      set(CMAKE_ASM_YASM_OBJECT_FORMAT elf64)
+    else()
+      set(CMAKE_ASM_YASM_OBJECT_FORMAT elf)
+    endif()
+  endif()
+endif()
+
+set(CMAKE_ASM_YASM_COMPILE_OBJECT "<CMAKE_ASM_YASM_COMPILER> <FLAGS> -f ${CMAKE_ASM_YASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
+
+# Load the generic ASMInformation file:
+set(ASM_DIALECT "_YASM")
+include(CMakeASMInformation)
+set(ASM_DIALECT)
diff --git a/cmake/Modules/CMakeDetermineASM_YASMCompiler.cmake b/cmake/Modules/CMakeDetermineASM_YASMCompiler.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a5e7c9e5801121f04411e5f1b1c6efa98736bcc1
--- /dev/null
+++ b/cmake/Modules/CMakeDetermineASM_YASMCompiler.cmake
@@ -0,0 +1,27 @@
+
+#=============================================================================
+# Copyright 2010 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# Find the nasm assembler. yasm (http://www.tortall.net/projects/yasm/) is nasm compatible
+
+set(CMAKE_ASM_YASM_COMPILER_LIST nasm yasm)
+
+if(NOT CMAKE_ASM_YASM_COMPILER)
+  find_program(CMAKE_ASM_YASM_COMPILER yasm
+    "$ENV{ProgramFiles}/YASM")
+endif()
+
+# Load the generic DetermineASM compiler file with the DIALECT set properly:
+set(ASM_DIALECT "_YASM")
+include(CMakeDetermineASMCompiler)
+set(ASM_DIALECT)
diff --git a/cmake/Modules/CMakeTestASM_YASMCompiler.cmake b/cmake/Modules/CMakeTestASM_YASMCompiler.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..745f7125c4a2f7a003c488b89d977b75a8eb3ebc
--- /dev/null
+++ b/cmake/Modules/CMakeTestASM_YASMCompiler.cmake
@@ -0,0 +1,23 @@
+
+#=============================================================================
+# Copyright 2010 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# This file is used by EnableLanguage in cmGlobalGenerator to
+# determine that the selected ASM_NASM "compiler" works.
+# For assembler this can only check whether the compiler has been found,
+# because otherwise there would have to be a separate assembler source file
+# for each assembler on every architecture.
+
+set(ASM_DIALECT "_YASM")
+include(CMakeTestASMCompiler)
+set(ASM_DIALECT)
diff --git a/cmake/Modules/FindGME.cmake b/cmake/Modules/FindGME.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..3b0c68de735e67458ce4652c600b5768c8124046
--- /dev/null
+++ b/cmake/Modules/FindGME.cmake
@@ -0,0 +1,23 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(GME_PKGCONF GME)
+
+find_path(GME_INCLUDE_DIR
+	NAMES gme.h
+	PATHS
+		${GME_PKGCONF_INCLUDE_DIRS}
+		/usr/include/gme
+		/usr/local/include/gme
+)
+
+find_library(GME_LIBRARY
+	NAMES gme
+	PATHS
+		${GME_PKGCONF_LIBRARY_DIRS}
+		/usr/lib
+		/usr/local/lib
+)
+
+set(GME_PROCESS_INCLUDES GME_INCLUDE_DIR)
+set(GME_PROCESS_LIBS GME_LIBRARY)
+libfind_process(GME)
\ No newline at end of file
diff --git a/cmake/Modules/FindSDL2.cmake b/cmake/Modules/FindSDL2.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..faa556a883aae61ac482c304f32200a996b982de
--- /dev/null
+++ b/cmake/Modules/FindSDL2.cmake
@@ -0,0 +1,34 @@
+# Find SDL2
+# Once done, this will define
+# 
+#  SDL2_FOUND - system has SDL2
+#  SDL2_INCLUDE_DIRS - SDL2 include directories
+#  SDL2_LIBRARIES - link libraries
+
+include(LibFindMacros)
+
+libfind_pkg_check_modules(SDL2_PKGCONF SDL2)
+
+# includes
+find_path(SDL2_INCLUDE_DIR
+	NAMES SDL.h
+	PATHS
+		${SDL2_PKGCONF_INCLUDE_DIRS}
+		"/usr/include/SDL2"
+		"/usr/local/include/SDL2"
+)
+
+# library
+find_library(SDL2_LIBRARY
+	NAMES SDL2
+	PATHS
+		${SDL2_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+
+# set include dir variables
+set(SDL2_PROCESS_INCLUDES SDL2_INCLUDE_DIR)
+set(SDL2_PROCESS_LIBS SDL2_LIBRARY)
+libfind_process(SDL2)
diff --git a/cmake/Modules/FindSDL2_main.cmake b/cmake/Modules/FindSDL2_main.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..280e51e2e47b9555584af340b62d880422a21c3e
--- /dev/null
+++ b/cmake/Modules/FindSDL2_main.cmake
@@ -0,0 +1,34 @@
+# 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
+
+include(LibFindMacros)
+
+libfind_pkg_check_modules(SDL2_MAIN_PKGCONF SDL2)
+
+# includes
+find_path(SDL2_MAIN_INCLUDE_DIR
+	NAMES SDL.h
+	PATHS
+		${SDL2_MAIN_PKGCONF_INCLUDE_DIRS}
+		"/usr/include/SDL2"
+		"/usr/local/include/SDL2"
+)
+
+# library
+find_library(SDL2_MAIN_LIBRARY
+	NAMES SDL2_main
+	PATHS
+		${SDL2_MAIN_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+
+# set include dir variables
+set(SDL2_MAIN_PROCESS_INCLUDES SDL2_MAIN_INCLUDE_DIR)
+set(SDL2_MAIN_PROCESS_LIBS SDL2_MAIN_LIBRARY)
+libfind_process(SDL2_MAIN)
diff --git a/cmake/Modules/FindSDL2_mixer.cmake b/cmake/Modules/FindSDL2_mixer.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..59b4823ed8ddb4406fd8dc8036675025c43d6fff
--- /dev/null
+++ b/cmake/Modules/FindSDL2_mixer.cmake
@@ -0,0 +1,34 @@
+# 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
+
+include(LibFindMacros)
+
+libfind_pkg_check_modules(SDL2_MIXER_PKGCONF SDL2_mixer)
+
+# includes
+find_path(SDL2_MIXER_INCLUDE_DIR
+	NAMES SDL_mixer.h
+	PATHS
+		${SDL2_MIXER_PKGCONF_INCLUDE_DIRS}
+		"/usr/include/SDL2"
+		"/usr/local/include/SDL2"
+)
+
+# library
+find_library(SDL2_MIXER_LIBRARY
+	NAMES SDL2_mixer
+	PATHS
+		${SDL2_MIXER_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+
+# set include dir variables
+set(SDL2_MIXER_PROCESS_INCLUDES SDL2_MIXER_INCLUDE_DIR)
+set(SDL2_MIXER_PROCESS_LIBS SDL2_MIXER_LIBRARY)
+libfind_process(SDL2_MIXER)
diff --git a/cmake/Modules/GitUtilities.cmake b/cmake/Modules/GitUtilities.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..de4015b0d1e45be3afd1c858c373db4b3d36277c
--- /dev/null
+++ b/cmake/Modules/GitUtilities.cmake
@@ -0,0 +1,22 @@
+# Git utilities
+
+if(__GitUtilities)
+	return()
+endif()
+
+set(__GitUtilities ON)
+
+function(git_describe variable path)
+	execute_process(COMMAND "${GIT_EXECUTABLE}" "describe"
+		WORKING_DIRECTORY "${path}"
+		RESULT_VARIABLE result
+		OUTPUT_VARIABLE output
+		ERROR_QUIET
+		OUTPUT_STRIP_TRAILING_WHITESPACE
+	)
+	#if(NOT result EQUAL 0)
+	#	set(${variable} "GITERROR-${result}-NOTFOUND" CACHE STRING "revision" FORCE)
+	#endif()
+
+	set(${variable} "${output}" PARENT_SCOPE)
+endfunction()
diff --git a/cmake/Modules/LibFindMacros.cmake b/cmake/Modules/LibFindMacros.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f6800aa7bd277e85ffa4297d27fbc980f0fda281
--- /dev/null
+++ b/cmake/Modules/LibFindMacros.cmake
@@ -0,0 +1,265 @@
+# Version 2.2
+# Public Domain, originally written by Lasse Kärkkäinen <tronic>
+# Maintained at https://github.com/Tronic/cmake-modules
+# Please send your improvements as pull requests on Github.
+
+# Find another package and make it a dependency of the current package.
+# This also automatically forwards the "REQUIRED" argument.
+# Usage: libfind_package(<prefix> <another package> [extra args to find_package])
+macro (libfind_package PREFIX PKG)
+  set(${PREFIX}_args ${PKG} ${ARGN})
+  if (${PREFIX}_FIND_REQUIRED)
+    set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
+  endif()
+  find_package(${${PREFIX}_args})
+  set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
+  unset(${PREFIX}_args)
+endmacro()
+
+# A simple wrapper to make pkg-config searches a bit easier.
+# Works the same as CMake's internal pkg_check_modules but is always quiet.
+macro (libfind_pkg_check_modules)
+  find_package(PkgConfig QUIET)
+  if (PKG_CONFIG_FOUND)
+    pkg_check_modules(${ARGN} QUIET)
+  endif()
+endmacro()
+
+# Avoid useless copy&pasta by doing what most simple libraries do anyway:
+# pkg-config, find headers, find library.
+# Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args])
+# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
+function (libfind_pkg_detect PREFIX)
+  # Parse arguments
+  set(argname pkgargs)
+  foreach (i ${ARGN})
+    if ("${i}" STREQUAL "FIND_PATH")
+      set(argname pathargs)
+    elseif ("${i}" STREQUAL "FIND_LIBRARY")
+      set(argname libraryargs)
+    else()
+      set(${argname} ${${argname}} ${i})
+    endif()
+  endforeach()
+  if (NOT pkgargs)
+    message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
+  endif()
+  # Find library
+  libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
+  if (pathargs)
+    find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
+  endif()
+  if (libraryargs)
+    find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
+  endif()
+endfunction()
+
+# Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION.
+# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
+# Fourth argument "QUIET" may be used for silently testing different define names.
+# This function does nothing if the version variable is already defined.
+function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
+  # Skip processing if we already have a version or if the include dir was not found
+  if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
+    return()
+  endif()
+  set(quiet ${${PREFIX}_FIND_QUIETLY})
+  # Process optional arguments
+  foreach(arg ${ARGN})
+    if (arg STREQUAL "QUIET")
+      set(quiet TRUE)
+    else()
+      message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
+    endif()
+  endforeach()
+  # Read the header and parse for version number
+  set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+  if (NOT EXISTS ${filename})
+    if (NOT quiet)
+      message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+    endif()
+    return()
+  endif()
+  file(READ "${filename}" header)
+  string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
+  # No regex match?
+  if (match STREQUAL header)
+    if (NOT quiet)
+      message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+    endif()
+    return()
+  endif()
+  # Export the version string
+  set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
+endfunction()
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+function (libfind_process PREFIX)
+  # Skip processing if already processed during this configuration run
+  if (${PREFIX}_FOUND)
+    return()
+  endif()
+
+  set(found TRUE)  # Start with the assumption that the package was found
+
+  # Did we find any files? Did we miss includes? These are for formatting better error messages.
+  set(some_files FALSE)
+  set(missing_headers FALSE)
+
+  # Shorthands for some variables that we need often
+  set(quiet ${${PREFIX}_FIND_QUIETLY})
+  set(required ${${PREFIX}_FIND_REQUIRED})
+  set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
+  set(findver "${${PREFIX}_FIND_VERSION}")
+  set(version "${${PREFIX}_VERSION}")
+
+  # Lists of config option names (all, includes, libs)
+  unset(configopts)
+  set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
+  set(libraryopts ${${PREFIX}_PROCESS_LIBS})
+
+  # 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!
+      list(APPEND includeopts ${${i}_INCLUDE_OPTS})
+      list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
+    else()
+      # If plural forms don't exist or they equal singular forms
+      if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
+          ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
+        # Singular forms can be used
+        if (DEFINED ${i}_INCLUDE_DIR)
+          list(APPEND includeopts ${i}_INCLUDE_DIR)
+        endif()
+        if (DEFINED ${i}_LIBRARY)
+          list(APPEND libraryopts ${i}_LIBRARY)
+        endif()
+      else()
+        # Oh no, we don't know the option names
+        message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
+      endif()
+    endif()
+  endforeach()
+  
+  if (includeopts)
+    list(REMOVE_DUPLICATES includeopts)
+  endif()
+  
+  if (libraryopts)
+    list(REMOVE_DUPLICATES libraryopts)
+  endif()
+
+  string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
+  if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
+    message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
+  endif()
+
+  # Include/library names separated by spaces (notice: not CMake lists)
+  unset(includes)
+  unset(libs)
+
+  # Process all includes and set found false if any are missing
+  foreach (i ${includeopts})
+    list(APPEND configopts ${i})
+    if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+      list(APPEND includes "${${i}}")
+    else()
+      set(found FALSE)
+      set(missing_headers TRUE)
+    endif()
+  endforeach()
+
+  # Process all libraries and set found false if any are missing
+  foreach (i ${libraryopts})
+    list(APPEND configopts ${i})
+    if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+      list(APPEND libs "${${i}}")
+    else()
+      set (found FALSE)
+    endif()
+  endforeach()
+
+  # Version checks
+  if (found AND findver)
+    if (NOT version)
+      message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
+    elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
+      set(found FALSE)
+      set(version_unsuitable TRUE)
+    endif()
+  endif()
+
+  # If all-OK, hide all config options, export variables, print status and exit
+  if (found)
+    foreach (i ${configopts})
+      mark_as_advanced(${i})
+    endforeach()
+    if (NOT quiet)
+      message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+      if (LIBFIND_DEBUG)
+        message(STATUS "  ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
+        message(STATUS "  ${PREFIX}_INCLUDE_OPTS=${includeopts}")
+        message(STATUS "  ${PREFIX}_INCLUDE_DIRS=${includes}")
+        message(STATUS "  ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
+        message(STATUS "  ${PREFIX}_LIBRARIES=${libs}")
+      endif()
+      set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
+      set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
+      set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
+      set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
+      set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
+    endif()
+    return()    
+  endif()
+
+  # Format messages for debug info and the type of error
+  set(vars "Relevant CMake configuration variables:\n")
+  foreach (i ${configopts})
+    mark_as_advanced(CLEAR ${i})
+    set(val ${${i}})
+    if ("${val}" STREQUAL "${i}-NOTFOUND")
+      set (val "<not found>")
+    elseif (val AND NOT EXISTS ${val})
+      set (val "${val}  (does not exist)")
+    else()
+      set(some_files TRUE)
+    endif()
+    set(vars "${vars}  ${i}=${val}\n")
+  endforeach()
+  set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
+  if (version_unsuitable)
+    set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
+    if (exactver)
+      set(msg "${msg} only version ${findver} is acceptable.")
+    else()
+      set(msg "${msg} version ${findver} is the minimum requirement.")
+    endif()
+  else()
+    if (missing_headers)
+      set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
+    elseif (some_files)
+      set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
+      if(findver)
+        set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
+      endif()
+    else()
+      set(msg "We were unable to find package ${PREFIX}.")
+    endif()
+  endif()
+
+  # Fatal error out if REQUIRED
+  if (required)
+    set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
+    message(FATAL_ERROR "${msg}\n${vars}")
+  endif()
+  # Otherwise just print a nasty warning
+  if (NOT quiet)
+    message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
+  endif()
+endfunction()
diff --git a/readme.txt b/readme.txt
index 8a09f0bc5e54edf4b92518742cd5223114d9c3be..c1898d491f0291bbfad2bd09b8b2cbc7b673e9ee 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,4 +1,4 @@
-Here it is! SRB2 v2.1.12 source code!
+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)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..74f97048b3f5332070a14b05cf6f167f79267797
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,399 @@
+# SRB2 Core
+
+# Core sources
+set(SRB2_CORE_SOURCES
+	am_map.c
+	b_bot.c
+	command.c
+	comptime.c
+	console.c
+	d_clisrv.c
+	d_main.c
+	d_net.c
+	d_netcmd.c
+	d_netfil.c
+	dehacked.c
+	f_finale.c
+	f_wipe.c
+	filesrch.c
+	g_game.c
+	g_input.c
+	hu_stuff.c
+	i_tcp.c
+	info.c
+	lzf.c
+	m_anigif.c
+	m_argv.c
+	m_bbox.c
+	m_cheat.c
+	m_cond.c
+	m_fixed.c
+	m_menu.c
+	m_misc.c
+	m_queue.c
+	m_random.c
+	md5.c
+	mserv.c
+	p_ceilng.c
+	p_enemy.c
+	p_fab.c
+	p_floor.c
+	p_inter.c
+	p_lights.c
+	p_map.c
+	p_maputl.c
+	p_mobj.c
+	p_polyobj.c
+	p_saveg.c
+	p_setup.c
+	p_sight.c
+	p_spec.c
+	p_telept.c
+	p_tick.c
+	p_user.c
+	r_bsp.c
+	r_data.c
+	r_draw.c
+	r_main.c
+	r_plane.c
+	r_segs.c
+	r_sky.c
+	r_splats.c
+	r_things.c
+	s_sound.c
+	screen.c
+	sounds.c
+	st_stuff.c
+	#string.c
+	tables.c
+	v_video.c
+	w_wad.c
+	y_inter.c
+	z_zone.c
+)
+
+set(SRB2_CORE_HEADERS
+	am_map.h
+	b_bot.h
+	byteptr.h
+	command.h
+	console.h
+	d_clisrv.h
+	d_event.h
+	d_main.h
+	d_net.h
+	d_netcmd.h
+	d_netfil.h
+	d_player.h
+	d_think.h
+	d_ticcmd.h
+	dehacked.h
+	doomdata.h
+	doomdef.h
+	doomstat.h
+	doomtype.h
+	endian.h
+	f_finale.h
+	fastcmp.h
+	filesrch.h
+	g_game.h
+	g_input.h
+	g_state.h
+	hu_stuff.h
+	i_joy.h
+	i_net.h
+	i_sound.h
+	i_system.h
+	i_tcp.h
+	i_video.h
+	info.h
+	keys.h
+	lzf.h
+	m_anigif.h
+	m_argv.h
+	m_bbox.h
+	m_cheat.h
+	m_cond.h
+	m_dllist.h
+	m_fixed.h
+	m_menu.h
+	m_misc.h
+	m_queue.h
+	m_random.h
+	m_swap.h
+	md5.h
+	mserv.h
+	p5prof.h
+	p_local.h
+	p_maputl.h
+	p_mobj.h
+	p_polyobj.h
+	p_pspr.h
+	p_saveg.h
+	p_setup.h
+	p_spec.h
+	p_tick.h
+	r_bsp.h
+	r_data.h
+	r_defs.h
+	r_draw.h
+	r_local.h
+	r_main.h
+	r_plane.h
+	r_segs.h
+	r_sky.h
+	r_splats.h
+	r_state.h
+	r_things.h
+	s_sound.h
+	screen.h
+	sounds.h
+	st_stuff.h
+	tables.h
+	v_video.h
+	w_wad.h
+	y_inter.h
+	z_zone.h
+)
+
+prepend_sources(SRB2_CORE_SOURCES)
+prepend_sources(SRB2_CORE_HEADERS)
+
+set(SRB2_CORE_HEADERS ${SRB2_CORE_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+set(SRB2_HWRENDER_SOURCES
+	hardware/hw_bsp.c
+	hardware/hw_cache.c
+	hardware/hw_draw.c
+	hardware/hw_light.c
+	hardware/hw_main.c
+	hardware/hw_md2.c
+	hardware/hw_trick.c
+)
+
+set (SRB2_HWRENDER_HEADERS
+	hardware/hw_data.h
+	hardware/hw_defs.h
+	hardware/hw_dll.h
+	hardware/hw_drv.h
+	hardware/hw_glide.h
+	hardware/hw_glob.h
+	hardware/hw_light.h
+	hardware/hw_main.h
+	hardware/hw_md2.h
+)
+
+prepend_sources(SRB2_HWRENDER_SOURCES)
+prepend_sources(SRB2_HWRENDER_HEADERS)
+
+set(SRB2_R_OPENGL_SOURCES
+	hardware/r_opengl/r_opengl.c
+)
+
+set(SRB2_R_OPENGL_HEADERS
+	hardware/r_opengl/r_opengl.h
+)
+
+prepend_sources(SRB2_R_OPENGL_SOURCES)
+prepend_sources(SRB2_R_OPENGL_HEADERS)
+
+set(SRB2_ASM_SOURCES
+	vid_copy.s
+)
+
+set(SRB2_NASM_SOURCES
+	tmap_mmx.nas
+	tmap.nas
+)
+
+if(MSVC)
+	list(APPEND SRB2_NASM_SOURCES tmap_vc.nas)
+endif()
+
+set(SRB2_NASM_OBJECTS
+	tmap_mmx.obj
+	tmap.obj
+)
+
+if(MSVC)
+	list(APPEND SRB2_NASM_OBJECTS tmap_vc.obj)
+endif()
+
+prepend_sources(SRB2_ASM_SOURCES)
+prepend_sources(SRB2_NASM_SOURCES)
+
+
+### Configuration
+set(SRB2_CONFIG_HAVE_BLUA ON CACHE BOOL
+	"Enable Lua interpreter support")
+set(SRB2_CONFIG_HAVE_PNG ON CACHE BOOL
+	"Enable PNG support. Depends on zlib, so will be disabled if you don't enable that too.")
+set(SRB2_CONFIG_HAVE_ZLIB ON CACHE BOOL
+	"Enable zlib support")
+set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL
+	"Enable GME support")
+set(SRB2_CONFIG_HWRENDER ON CACHE BOOL
+	"Enable hardware rendering through OpenGL")
+set(SRB2_CONFIG_USEASM OFF CACHE BOOL
+	"Enable NASM tmap implementation for software mode speedup.")
+set(SRB2_CONFIG_YASM OFF CACHE BOOL
+	"Use YASM in place of NASM.")
+set(SRB2_CONFIG_STATIC_OPENGL OFF CACHE BOOL
+	"Use statically linked OpenGL. NOT RECOMMENDED.")
+
+if(${SRB2_CONFIG_HAVE_BLUA})
+	add_definitions(-DHAVE_BLUA)
+	set(SRB2_LUA_SOURCES
+		lua_baselib.c
+		lua_consolelib.c
+		lua_hooklib.c
+		lua_hudlib.c
+		lua_infolib.c
+		lua_maplib.c
+		lua_mathlib.c
+		lua_mobjlib.c
+		lua_playerlib.c
+		lua_script.c
+		lua_skinlib.c
+		lua_thinkerlib.c
+	)
+	set(SRB2_LUA_HEADERS
+		lua_hook.h
+		lua_hud.h
+		lua_libs.h
+		lua_script.h
+	)
+
+	prepend_sources(SRB2_LUA_SOURCES)
+	prepend_sources(SRB2_LUA_HEADERS)
+
+	set(SRB2_BLUA_SOURCES
+		blua/lapi.c
+		blua/lauxlib.c
+		blua/lbaselib.c
+		blua/lcode.c
+		blua/ldebug.c
+		blua/ldo.c
+		blua/ldump.c
+		blua/lfunc.c
+		blua/lgc.c
+		blua/linit.c
+		blua/llex.c
+		blua/lmem.c
+		blua/lobject.c
+		blua/lopcodes.c
+		blua/lparser.c
+		blua/lstate.c
+		blua/lstring.c
+		blua/lstrlib.c
+		blua/ltable.c
+		blua/ltablib.c
+		blua/ltm.c
+		blua/lundump.c
+		blua/lvm.c
+		blua/lzio.c
+	)
+	set(SRB2_BLUA_HEADERS
+		blua/lapi.h
+		blua/lauxlib.h
+		blua/lcode.h
+		blua/ldebug.h
+		blua/ldo.h
+		blua/lfunc.h
+		blua/lgc.h
+		blua/llex.h
+		blua/llimits.h
+		blua/lmem.h
+		blua/lobject.h
+		blua/lopcodes.h
+		blua/lparser.h
+		blua/lstate.h
+		blua/lstring.h
+		blua/ltable.h
+		blua/ltm.h
+		blua/lua.h
+		blua/luaconf.h
+		blua/lualib.h
+		blua/lundump.h
+		blua/lvm.h
+		blua/lzio.h
+	)
+	prepend_sources(SRB2_BLUA_SOURCES)
+	prepend_sources(SRB2_BLUA_HEADERS)
+endif()
+
+if(${SRB2_CONFIG_HAVE_GME})
+	find_package(GME)
+	if(${GME_FOUND})
+		set(SRB2_HAVE_GME ON)
+	else()
+		message(WARNING "You have specified that GME is available but it was not found.")
+	endif()
+endif()
+
+if(${SRB2_CONFIG_HAVE_ZLIB})
+	find_package(ZLIB)
+	if(${ZLIB_FOUND})
+		set(SRB2_HAVE_ZLIB ON)
+	else()
+		message(WARNING "You have specified that ZLIB is available but it was not found. SRB2 may not compile correctly.")
+	endif()
+endif()
+
+if(${SRB2_CONFIG_HAVE_PNG} AND ${SRB2_CONFIG_HAVE_ZLIB})
+	if (${ZLIB_FOUND})
+		find_package(PNG)
+		if(${PNG_FOUND})
+			set(SRB2_HAVE_PNG ON)
+			add_definitions(-DHAVE_PNG)
+			add_definitions(-D_LARGEFILE64_SOURCE)
+		else()
+			message(WARNING "You have specified that PNG is available but it was not found. SRB2 may not compile correctly.")
+		endif()
+	endif()
+endif()
+
+if(${SRB2_CONFIG_HWRENDER})
+	add_definitions(-DHWRENDER)
+endif()
+
+if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
+	find_package(OpenGL)
+	if(${OPENGL_FOUND})
+		add_definitions(-DHWRENDER)
+		add_definitions(-DSTATIC_OPENGL)
+	else()
+		message(WARNING "You have specified static opengl but opengl was not found. Not setting HWRENDER.")
+	endif()
+endif()
+
+if(${SRB2_CONFIG_USEASM})
+	if(${SRB2_CONFIG_YASM})
+		set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
+		enable_language(ASM_YASM)
+	else()
+		set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
+		enable_language(ASM_NASM)
+	endif()
+	set(SRB2_USEASM ON)
+	add_definitions(-DUSEASM)
+else()
+	set(SRB2_USEASM OFF)
+	add_definitions(-DNOASM -DNONX86)
+endif()
+
+# Targets
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	add_subdirectory(win32)
+endif()
+
+# Compatibility flag with later versions of GCC
+# We should really fix our code to not need this
+if(NOT CLANG AND NOT MSVC)
+	set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -mno-ms-bitfields)
+endif()
+
+add_definitions(-DCMAKECONFIG)
+
+add_subdirectory(sdl)
diff --git a/src/Makefile b/src/Makefile
index f5d58af3a1aa6c6ed082cf2f3aca581c105108a0..d4cc64a4b6ff79da6672ee10df9ef30f574aca40 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -305,6 +305,10 @@ PNG_LDFLAGS?=$(shell $(PNG_CONFIG) --ldflags)
 endif
 endif
 
+ifdef LINUX
+PNG_CFLAGS+=-D_LARGEFILE64_SOURCE
+endif
+
 LIBS+=$(PNG_LDFLAGS)
 CFLAGS+=$(PNG_CFLAGS)
 endif
diff --git a/src/command.c b/src/command.c
index 09588eb84b9762a8b814ff8b7e25cd243596d5a4..e10787f1b8aec79bf652fd2e87297434ed965801 100644
--- a/src/command.c
+++ b/src/command.c
@@ -379,11 +379,13 @@ void COM_AddCommand(const char *name, com_func_t func)
 	{
 		if (!stricmp(name, cmd->name)) //case insensitive now that we have lower and uppercase!
 		{
+#ifdef HAVE_BLUA
 			// don't I_Error for Lua commands
 			// Lua commands can replace game commands, and they have priority.
 			// BUT, if for some reason we screwed up and made two console commands with the same name,
 			// it's good to have this here so we find out.
 			if (cmd->function != COM_Lua_f)
+#endif
 				I_Error("Command %s already exists\n", name);
 
 			return;
@@ -397,6 +399,7 @@ void COM_AddCommand(const char *name, com_func_t func)
 	com_commands = cmd;
 }
 
+#ifdef HAVE_BLUA
 /** Adds a console command for Lua.
   * No I_Errors allowed; return a negative code instead.
   *
@@ -429,6 +432,7 @@ int COM_AddLuaCommand(const char *name)
 	com_commands = cmd;
 	return 0;
 }
+#endif
 
 /** Tests if a command exists.
   *
@@ -1284,6 +1288,8 @@ void CV_LoadNetVars(UINT8 **p)
 	serverloading = false;
 }
 
+static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth);
+
 void CV_ResetCheatNetVars(void)
 {
 	consvar_t *cvar;
@@ -1291,7 +1297,7 @@ void CV_ResetCheatNetVars(void)
 	// Stealthset everything back to default.
 	for (cvar = consvar_vars; cvar; cvar = cvar->next)
 		if (cvar->flags & CV_CHEAT)
-			Setvalue(cvar, cvar->defaultvalue, true);
+			CV_SetCVar(cvar, cvar->defaultvalue, true);
 }
 
 // Returns true if the variable's current value is its default value
@@ -1428,11 +1434,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
 	INT32 newvalue, max;
 
 	// count pointlimit better
-	if (var == &cv_pointlimit && (gametype == GT_MATCH
-#ifdef CHAOSISNOTDEADYET
-		|| gametype == GT_CHAOS
-#endif
-		))
+	if (var == &cv_pointlimit && (gametype == GT_MATCH))
 		increment *= 50;
 	newvalue = var->value + increment;
 
diff --git a/src/comptime.c b/src/comptime.c
index cd6bfd9bb24d6cbbbd1e3f60258e82de35344037..a4dc5b0f9637e60d761819792ee1f5dd4058656e 100644
--- a/src/comptime.c
+++ b/src/comptime.c
@@ -7,10 +7,16 @@
  *
  */
 
-#ifdef COMPVERSION
+#if (defined(CMAKECONFIG))
+#include "config.h"
+const char *comprevision = SRB2_COMP_REVISION;
+
+#elif (defined(COMPVERSION))
 #include "comptime.h"
+
 #else
 const char *comprevision = "illegal";
+
 #endif
 
 const char *compdate = __DATE__;
diff --git a/src/config.h.in b/src/config.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..7c5b299cfe375b67453121b30f5063c4d70f1e88
--- /dev/null
+++ b/src/config.h.in
@@ -0,0 +1,26 @@
+/** SRB2 CMake Configuration */
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#ifdef CMAKECONFIG
+
+#define ASSET_HASH_SRB2_SRB   "${SRB2_ASSET_srb2.srb_HASH}"
+#define ASSET_HASH_PLAYER_DTA "${SRB2_ASSET_player.dta_HASH}"
+#define ASSET_HASH_RINGS_DTA  "${SRB2_ASSET_rings.dta_HASH}"
+#define ASSET_HASH_ZONES_DTA  "${SRB2_ASSET_zones.dta_HASH}"
+#define ASSET_HASH_PATCH_DTA  "${SRB2_ASSET_patch.dta_HASH}"
+
+#define SRB2_COMP_REVISION    "${SRB2_COMP_REVISION}"
+
+#define CMAKE_ASSETS_DIR      "${CMAKE_SOURCE_DIR}/assets"
+
+#else
+
+#define ASSET_HASH_SRB2_SRB   "c1b9577687f8a795104aef4600720ea7"
+#define ASSET_HASH_ZONES_DTA  "303838c6c534d9540288360fa49cca60"
+#define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799"
+#define ASSET_HASH_RINGS_DTA  "85901ad4bf94637e5753d2ac2c03ea26"
+
+#endif
+#endif
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index e24a1426ab5929fc716116101492a4a76eca197c..c0179ca1be99cff5fb94b2a15b73a81269c02719 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -823,7 +823,7 @@ static inline void resynch_read_ctf(resynchend_pak *p)
 	{
 		if (!playeringame[p->flagplayer[1]])
 			 I_Error("Invalid blue flag player %d who isn't in the game!", (INT32)p->flagplayer[1]);
-		players[p->flagplayer[1]].gotflag = GF_REDFLAG;
+		players[p->flagplayer[1]].gotflag = GF_BLUEFLAG;
 		if (blueflag)
 		{
 			P_RemoveMobj(blueflag);
diff --git a/src/d_main.c b/src/d_main.c
index 4cea94a8178c4f34a35a9622bcaf704660f48210..a959a86328e09d4a501c3c9b2eea52e197ed478d 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -74,6 +74,12 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 #include "m_cond.h" // condition initialization
 #include "fastcmp.h"
 
+#ifdef CMAKECONFIG
+#include "config.h"
+#else
+#include "config.h.in"
+#endif
+
 #ifdef _XBOX
 #include "sdl/SRB2XBOX/xboxhelp.h"
 #endif
@@ -90,6 +96,9 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 #include "hardware/hw3sound.h"
 #endif
 
+// platform independant focus loss
+UINT8 window_notinfocus = false;
+
 //
 // DEMO LOOP
 //
@@ -437,6 +446,17 @@ static void D_Display(void)
 		CON_Drawer();
 
 	M_Drawer(); // menu is drawn even on top of everything
+
+	// focus lost notification goes on top of everything, even the former everything
+	if (window_notinfocus)
+	{
+		M_DrawTextBox((BASEVIDWIDTH/2) - (60), (BASEVIDHEIGHT/2) - (16), 13, 2);
+		if (gamestate == GS_LEVEL && (P_AutoPause() || paused))
+			V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), V_YELLOWMAP, "Game Paused");
+		else
+			V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), V_YELLOWMAP, "Focus Lost");
+	}
+
 	NetUpdate(); // send out any new accumulation
 
 	// It's safe to end the game now.
@@ -635,6 +655,7 @@ void D_AdvanceDemo(void)
 //
 void D_StartTitle(void)
 {
+	INT32 i;
 	if (netgame)
 	{
 		if (gametype == GT_COOP)
@@ -661,6 +682,16 @@ void D_StartTitle(void)
 	SV_StopServer();
 	SV_ResetServer();
 
+	for (i = 0; i < MAXPLAYERS; i++)
+		CL_ClearPlayer(i);
+
+	splitscreen = false;
+	SplitScreen_OnChange();
+	botingame = false;
+	botskin = 0;
+	cv_debug = 0;
+	emeralds = 0;
+
 	// In case someone exits out at the same time they start a time attack run,
 	// reset modeattacking
 	modeattacking = ATTACKING_NONE;
@@ -803,7 +834,7 @@ static void IdentifyVersion(void)
 	D_AddFile(va(pandf,srb2waddir,"rings.dta"));
 
 	// Add our crappy patches to fix our bugs
-	D_AddFile(va(pandf,srb2waddir,"patch.dta"));
+	// D_AddFile(va(pandf,srb2waddir,"patch.dta"));
 
 #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
 	{
@@ -1087,19 +1118,19 @@ void D_SRB2Main(void)
 #endif
 	D_CleanFile();
 
-#if 1 // md5s last updated 11/10/14
+#if 1 // md5s last updated 12/14/14
 
 	// Check MD5s of autoloaded files
-	W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad
-	W_VerifyFileMD5(1, "f39b6c849295e3c81875726e8cc0e2c7"); // zones.dta
-	W_VerifyFileMD5(2, "cfca0f1c73023cbbd8f844f45480f799"); // player.dta
-	W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.dta
-	W_VerifyFileMD5(4, "a45cc59d13dce924f2112b3e4201d0ae"); // patch.dta
+	W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad
+	W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta
+	W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta
+	W_VerifyFileMD5(3, ASSET_HASH_RINGS_DTA); // rings.dta
+	//W_VerifyFileMD5(4, "0c66790502e648bfce90fdc5bb15722e"); // patch.dta
 	// don't check music.dta because people like to modify it, and it doesn't matter if they do
 	// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
 #endif
 
-	mainwads = 5; // there are 5 wads not to unload
+	mainwads = 4; // there are 5 wads not to unload
 
 	cht_Init();
 
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index bcf4e87f8e86bf17048b0c60c3ae3f997f11c2eb..e410713e0848f8589d15b8943b1cc1e6aae42a34 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -277,21 +277,6 @@ consvar_t cv_matchboxes = {"matchboxes", "Normal", CV_NETVAR|CV_CHEAT, matchboxe
 consvar_t cv_specialrings = {"specialrings", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_powerstones = {"powerstones", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
-#ifdef CHAOSISNOTDEADYET
-consvar_t cv_chaos_bluecrawla = {"chaos_bluecrawla", "8", CV_NETVAR, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_redcrawla = {"chaos_redcrawla", "8", CV_NETVAR, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_crawlacommander = {"chaos_crawlacommander", "2", CV_NETVAR, chances_cons_t,
-	NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_jettysynbomber = {"chaos_jettysynbomber", "5", CV_NETVAR, chances_cons_t,
-	NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_jettysyngunner = {"chaos_jettysyngunner", "2", CV_NETVAR, chances_cons_t,
-	NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_eggmobile1 = {"chaos_eggmobile1", "2", CV_NETVAR, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_eggmobile2 = {"chaos_eggmobile2", "2", CV_NETVAR, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_skim = {"chaos_skim", "5", CV_NETVAR, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chaos_spawnrate = {"chaos_spawnrate", "30",CV_NETVAR, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
-#endif
-
 consvar_t cv_recycler =      {"tv_recycler",      "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_teleporters =   {"tv_teleporter",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_superring =     {"tv_superring",     "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -498,18 +483,6 @@ void D_RegisterServerCommands(void)
 	CV_RegisterVar(&cv_competitionboxes);
 	CV_RegisterVar(&cv_matchboxes);
 
-#ifdef CHAOSISNOTDEADYET
-	CV_RegisterVar(&cv_chaos_bluecrawla);
-	CV_RegisterVar(&cv_chaos_redcrawla);
-	CV_RegisterVar(&cv_chaos_crawlacommander);
-	CV_RegisterVar(&cv_chaos_jettysynbomber);
-	CV_RegisterVar(&cv_chaos_jettysyngunner);
-	CV_RegisterVar(&cv_chaos_eggmobile1);
-	CV_RegisterVar(&cv_chaos_eggmobile2);
-	CV_RegisterVar(&cv_chaos_skim);
-	CV_RegisterVar(&cv_chaos_spawnrate);
-#endif
-
 	CV_RegisterVar(&cv_recycler);
 	CV_RegisterVar(&cv_teleporters);
 	CV_RegisterVar(&cv_superring);
@@ -699,6 +672,8 @@ void D_RegisterClientCommands(void)
 	CV_RegisterVar(&cv_invertmouse2);
 	CV_RegisterVar(&cv_mousesens);
 	CV_RegisterVar(&cv_mousesens2);
+	CV_RegisterVar(&cv_mouseysens);
+	CV_RegisterVar(&cv_mouseysens2);
 	CV_RegisterVar(&cv_mousemove);
 	CV_RegisterVar(&cv_mousemove2);
 
@@ -734,9 +709,6 @@ void D_RegisterClientCommands(void)
 	CV_RegisterVar(&cv_scr_width);
 	CV_RegisterVar(&cv_scr_height);
 
-	// p_fab.c
-	CV_RegisterVar(&cv_translucency);
-
 	CV_RegisterVar(&cv_soundtest);
 
 	// ingame object placing
@@ -3374,18 +3346,6 @@ void D_GameTypeChanged(INT32 lastgametype)
 
 		switch (gametype)
 		{
-#ifdef CHAOSISNOTDEADYET
-			case GT_CHAOS:
-				if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
-				{
-					// default settings for chaos: timelimit 2 mins, no pointlimit
-					CV_SetValue(&cv_pointlimit, 0);
-					CV_SetValue(&cv_timelimit, 2);
-				}
-				if (!cv_itemrespawntime.changed)
-					CV_SetValue(&cv_itemrespawntime, 90); // respawn sparingly in chaos
-				break;
-#endif
 			case GT_MATCH:
 			case GT_TEAMMATCH:
 				if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
@@ -3911,14 +3871,18 @@ static void Command_Cheats_f(void)
 {
 	if (COM_CheckParm("off"))
 	{
-		CV_ResetCheatNetVars();
+		if (!(server || (adminplayer == consoleplayer)))
+			CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
+		else
+			CV_ResetCheatNetVars();
 		return;
 	}
 
 	if (CV_CheatsEnabled())
 	{
 		CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed -- Cheats are enabled.\n"));
-		CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.\n"));
+		if (server || (adminplayer == consoleplayer))
+			CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.\n"));
 	}
 	else
 		CONS_Printf(M_GetText("No CHEAT-marked variables are changed -- Cheats are disabled.\n"));
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index c1cc27ceafa942731cac82cdbf0989296e52704f..31a7cf81864bd7872e2752ea6c264cbba6c43303 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -44,6 +44,7 @@ extern consvar_t cv_invertmouse2;
 extern consvar_t cv_alwaysfreelook2;
 extern consvar_t cv_mousemove2;
 extern consvar_t cv_mousesens2;
+extern consvar_t cv_mouseysens2;
 
 // normally in p_mobj but the .h is not read
 extern consvar_t cv_itemrespawntime;
@@ -80,7 +81,6 @@ extern consvar_t cv_useranalog, cv_useranalog2;
 extern consvar_t cv_analog, cv_analog2;
 
 extern consvar_t cv_netstat;
-extern consvar_t cv_translucency;
 extern consvar_t cv_splats;
 
 extern consvar_t cv_countdowntime;
@@ -113,12 +113,6 @@ extern consvar_t cv_ringslinger, cv_soundtest;
 
 extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes;
 
-#ifdef CHAOSISNOTDEADYET
-extern consvar_t cv_chaos_spawnrate, cv_chaos_bluecrawla, cv_chaos_redcrawla;
-extern consvar_t cv_chaos_crawlacommander, cv_chaos_jettysynbomber, cv_chaos_jettysyngunner;
-extern consvar_t cv_chaos_eggmobile1, cv_chaos_eggmobile2, cv_chaos_skim;
-#endif
-
 #ifdef NEWPING
 extern consvar_t cv_maxping;
 #endif
diff --git a/src/dehacked.c b/src/dehacked.c
index a019b4d3eaa1a8160f4a6b54a94c0625aa20127f..fc01bafddc1d116237086a1d0ca0e6b4d4f9d483 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -351,7 +351,7 @@ static void clear_conditionsets(void)
 {
 	UINT8 i;
 	for (i = 0; i < MAXCONDITIONSETS; ++i)
-		M_ClearConditionSet(i);
+		M_ClearConditionSet(i+1);
 }
 
 static void clear_levels(void)
@@ -5128,7 +5128,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_ARROWDOWN",
 
 	// Trapgoyle Demon fire
-	"S_DEMONFIRE",
+	"S_DEMONFIRE1",
+	"S_DEMONFIRE2",
+	"S_DEMONFIRE3",
+	"S_DEMONFIRE4",
+	"S_DEMONFIRE5",
+	"S_DEMONFIRE6",
 
 	"S_GFZFLOWERA",
 	"S_GFZFLOWERA2",
@@ -7138,7 +7143,6 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_NIGHTOPIANHELPER", // the actual helper object that orbits you
 
 	// Utility Objects
-	"MT_CHAOSSPAWNER",
 	"MT_TELEPORTMAN",
 	"MT_ALTVIEWMAN",
 	"MT_CRUMBLEOBJ", // Sound generator for crumbling platform
@@ -7529,6 +7533,17 @@ struct {
 	{"FF_FULLBRIGHT",FF_FULLBRIGHT},
 	{"FF_TRANSMASK",FF_TRANSMASK},
 	{"FF_TRANSSHIFT",FF_TRANSSHIFT},
+	// new preshifted translucency (used in source)
+	{"FF_TRANS10",FF_TRANS10},
+	{"FF_TRANS20",FF_TRANS20},
+	{"FF_TRANS30",FF_TRANS30},
+	{"FF_TRANS40",FF_TRANS40},
+	{"FF_TRANS50",FF_TRANS50},
+	{"FF_TRANS60",FF_TRANS60},
+	{"FF_TRANS70",FF_TRANS70},
+	{"FF_TRANS80",FF_TRANS80},
+	{"FF_TRANS90",FF_TRANS90},
+	// compatibility
 	// Transparency for SOCs is pre-shifted
 	{"TR_TRANS10",tr_trans10<<FF_TRANSSHIFT},
 	{"TR_TRANS20",tr_trans20<<FF_TRANSSHIFT},
@@ -8125,7 +8140,7 @@ static fixed_t find_const(const char **rword)
 		return r;
 	}
 	if (!*(word+1) && // Turn a single A-z symbol into numbers, like sprite frames.
-	 (*word >= 'A' && *word <= 'Z') || (*word >= 'a' && *word <= 'z')) {
+	 ((*word >= 'A' && *word <= 'Z') || (*word >= 'a' && *word <= 'z'))) {
 		r = R_Char2Frame(*word);
 		free(word);
 		return r;
diff --git a/src/doomdef.h b/src/doomdef.h
index c4896a764d7937035552a5096ef2a0f4168e05e9..4a6d6e5764bc48198d034f2e2e98ce8c5ac9ab26 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -144,8 +144,9 @@ extern FILE *logstream;
 #define VERSIONSTRING "Trunk"
 #else
 #define VERSION    201 // Game version
-#define SUBVERSION 12  // more precise version number
-#define VERSIONSTRING "v2.1.12"
+#define SUBVERSION 14  // more precise version number
+#define VERSIONSTRING "v2.1.14"
+#define VERSIONSTRINGW L"v2.1.14"
 // Hey! If you change this, add 1 to the MODVERSION below!
 // Otherwise we can't force updates!
 #endif
@@ -203,7 +204,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 17
+#define MODVERSION 19
 
 
 
@@ -449,10 +450,6 @@ extern const char *compdate, *comptime, *comprevision;
 ///	Dumps the contents of a network save game upon consistency failure for debugging.
 //#define DUMPCONSISTENCY
 
-///	Pre-1.08 Chaos gametype code
-///	\note	Code severely out of date, does not take new enemies/bosses into account.
-//#define CHAOSISNOTDEADYET
-
 ///	Polyobject fake flat code
 #define POLYOBJECTS_PLANES
 
diff --git a/src/doomstat.h b/src/doomstat.h
index b05b3833c61767cfd16c32c2d7b5ec7011a1fed4..44cf6feaabc586a449c1b55ea729a5c0ec401ef2 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -103,6 +103,7 @@ extern boolean digital_disabled;
 
 extern boolean menuactive; // Menu overlaid?
 extern UINT8 paused; // Game paused?
+extern UINT8 window_notinfocus; // are we in focus? (backend independant -- handles auto pausing and display of "focus lost" message)
 
 extern boolean nodrawers;
 extern boolean noblit;
diff --git a/src/doomtype.h b/src/doomtype.h
index 6bc563527775983c185113f01dbca2092ecebd26..ff4199775f03c104ac86f51f23998f167c137ac7 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -100,9 +100,9 @@ typedef long ssize_t;
 
 #if defined (_MSC_VER) || defined (__OS2__)
 	// Microsoft VisualC++
-#ifdef _MSC_VER
+#if (_MSC_VER <= 1800) // MSVC 2013 and back
 	#define snprintf                _snprintf
-#if (_MSC_VER <= 1200)
+#if (_MSC_VER <= 1200) // MSVC 2012 and back
 	#define vsnprintf               _vsnprintf
 #endif
 #endif
diff --git a/src/f_wipe.c b/src/f_wipe.c
index 69e956216225003bdaaaf94920a28e43d5c5354e..8e7c622c43a393276c6c9dffd9b515a36b3114b6 100644
--- a/src/f_wipe.c
+++ b/src/f_wipe.c
@@ -210,8 +210,8 @@ static void F_DoWipe(fademask_t *fademask)
 		UINT32 draw_linestogo, draw_rowstogo;
 
 		// rectangle coordinates, etc.
-		UINT16 scrxpos[fademask->width  + 1];
-		UINT16 scrypos[fademask->height + 1];
+		UINT16* scrxpos = (UINT16*)malloc((fademask->width + 1)  * sizeof(UINT16));
+		UINT16* scrypos = (UINT16*)malloc((fademask->height + 1) * sizeof(UINT16));
 		UINT16 maskx, masky;
 		UINT32 relativepos;
 
@@ -263,6 +263,9 @@ static void F_DoWipe(fademask_t *fademask)
 			if (++maskx >= fademask->width)
 				++masky, maskx = 0;
 		} while (++mask < maskend);
+
+		free(scrxpos);
+		free(scrypos);
 	}
 }
 #endif
diff --git a/src/g_game.c b/src/g_game.c
index 50f30dfcab60091dadfed6b18197df9b33e4f253..c59f23c0787f23de3a7cfe58c1393a638d4b9e4d 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -967,7 +967,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
 
 	// why build a ticcmd if we're paused?
 	// Or, for that matter, if we're being reborn.
-	if (paused || P_MenuActivePause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN))
+	if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN))
 	{
 		cmd->angleturn = (INT16)(localangle >> 16);
 		cmd->aiming = G_ClipAimingPitch(&localaiming);
@@ -1257,7 +1257,7 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
 
 	//why build a ticcmd if we're paused?
 	// Or, for that matter, if we're being reborn.
-	if (paused || P_MenuActivePause() || player->playerstate == PST_REBORN)
+	if (paused || P_AutoPause() || player->playerstate == PST_REBORN)
 	{
 		cmd->angleturn = (INT16)(localangle2 >> 16);
 		cmd->aiming = G_ClipAimingPitch(&localaiming2);
@@ -2299,11 +2299,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
 	// -- DM/Tag/CTF-spectator/etc --
 	// Order: DM->CTF->Coop
 	else if (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF
-	 || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT))
-#ifdef CHAOSISNOTDEADYET
-	 || gametype == GT_CHAOS
-#endif
-	)
+	 || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT)))
 	{
 		if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start
 		&& !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start
@@ -2709,9 +2705,6 @@ INT16 G_TOLFlag(INT32 pgametype)
 	if (pgametype == GT_RACE)         return TOL_RACE;
 	if (pgametype == GT_MATCH)        return TOL_MATCH;
 	if (pgametype == GT_TEAMMATCH)    return TOL_MATCH;
-#ifdef CHAOSISNOTDEADYET
-	if (pgametype == GT_CHAOS)        return TOL_CHAOS;
-#endif
 	if (pgametype == GT_TAG)          return TOL_TAG;
 	if (pgametype == GT_HIDEANDSEEK)  return TOL_TAG;
 	if (pgametype == GT_CTF)          return TOL_CTF;
diff --git a/src/g_input.c b/src/g_input.c
index f8170dd3afae9b44463916af8109188d7df253c6..f12ddb7114c4b935e79877de7195ee248c47f6c2 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -28,6 +28,8 @@ static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"
 // mouse values are used once
 consvar_t cv_mousesens = {"mousesens", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_mousesens2 = {"mousesens2", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mouseysens = {"mouseysens", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mouseysens2 = {"mouseysens2", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_controlperkey = {"controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 INT32 mousex, mousey;
@@ -99,7 +101,7 @@ void G_MapEventsToControls(event_t *ev)
 		case ev_mouse: // buttons are virtual keys
 			mousex = (INT32)(ev->data2*((cv_mousesens.value*cv_mousesens.value)/110.0f + 0.1f));
 			mousey = (INT32)(ev->data3*((cv_mousesens.value*cv_mousesens.value)/110.0f + 0.1f));
-			mlooky = mousey;
+			mlooky = (INT32)(ev->data3*((cv_mouseysens.value*cv_mousesens.value)/110.0f + 0.1f));
 			break;
 
 		case ev_joystick: // buttons are virtual keys
@@ -121,7 +123,7 @@ void G_MapEventsToControls(event_t *ev)
 		case ev_mouse2: // buttons are virtual keys
 			mouse2x = (INT32)(ev->data2*((cv_mousesens2.value*cv_mousesens2.value)/110.0f + 0.1f));
 			mouse2y = (INT32)(ev->data3*((cv_mousesens2.value*cv_mousesens2.value)/110.0f + 0.1f));
-			mlook2y = mouse2y;
+			mlook2y = (INT32)(ev->data3*((cv_mouseysens2.value*cv_mousesens2.value)/110.0f + 0.1f));
 			break;
 
 		default:
diff --git a/src/g_input.h b/src/g_input.h
index 699542a8a4cd08f664ad8dda51c2d0eba64db4e4..eca40591fa100680638867b12c81e4e886b375f3 100644
--- a/src/g_input.h
+++ b/src/g_input.h
@@ -125,7 +125,7 @@ typedef enum
 } gamecontrols_e;
 
 // mouse values are used once
-extern consvar_t cv_mousesens;
+extern consvar_t cv_mousesens, cv_mouseysens;
 
 extern INT32 mousex, mousey;
 extern INT32 mlooky; //mousey with mlookSensitivity
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index 313bc6c2f300d8444ef4de717083ea1436667f53..e6a26e605899307a4796e2a84b3d5408b29c8af4 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -726,7 +726,11 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
 	tga_hdr.image_type = 2;
 	tga_hdr.image_descriptor = 32;
 
-	write(fd, &tga_hdr, sizeof (TGAHeader));
+	if ( -1 == write(fd, &tga_hdr, sizeof (TGAHeader)))
+	{
+		close(fd);
+		return false;
+	}
 	// format to 888 BGR
 	for (i = 0; i < width * height * 3; i+=3)
 	{
@@ -734,7 +738,11 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
 		buf8[i] = buf8[i+2];
 		buf8[i+2] = temp;
 	}
-	write(fd, buffer, width * height * 3);
+	if ( -1 == write(fd, buffer, width * height * 3))
+	{
+		close(fd);
+		return false;
+	}
 	close(fd);
 	return true;
 }
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index 2148751ac9b9ef84374350ab030b6e08ae4a6493..ad62f3910c94096e06af01d91ede9e1e2a5fe60c 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -278,6 +278,7 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[SMALLREDBALL_L], // SPR_TRLS
 	&lspr[NOLIGHT],     // SPR_CBLL
 	&lspr[NOLIGHT],     // SPR_AROW
+	&lspr[NOLIGHT],     // SPR_CFIR
 
 	// Greenflower Scenery
 	&lspr[NOLIGHT],     // SPR_FWR1
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 04f3b820ee0e4026f5f24764ad6d633795e7bece..5842a3cd86ca1dab96dc519314d6c7eadb40bbf8 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -2651,7 +2651,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
 
 	if (nrPlaneVerts > UINT16_MAX) // FIXME: exceeds plVerts size
 	{
-		CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, UINT16_MAX);
+		CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
 		return;
 	}
 
@@ -2766,9 +2766,9 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
 			v3d->tow = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle))));
 		}
 
-		v3d->x = FIXED_TO_FLOAT(polysector->lines[i]->v1->x);
+		v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x);
 		v3d->y = height;
-		v3d->z = FIXED_TO_FLOAT(polysector->lines[i]->v1->y);
+		v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y);
 	}
 
 
@@ -3796,7 +3796,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 		}*/
 
 		// shadow is always half as translucent as the sprite itself
-		if (spr->mobj->flags2 & MF2_SHADOW)
+		if (!cv_translucency.value)
+			; // translucency disabled
+		else if (spr->mobj->flags2 & MF2_SHADOW)
 			sSurf.FlatColor.s.alpha = 0x20;
 		else if (spr->mobj->frame & FF_TRANSMASK)
 		{
diff --git a/src/hardware/r_opengl/ogl_win.c b/src/hardware/r_opengl/ogl_win.c
index 5cc075ceae75bb13b50fba1e0bed4e541aa6c922..eb9a31a7d7f1e909d72e88cc5bc3c166471b73ab 100644
--- a/src/hardware/r_opengl/ogl_win.c
+++ b/src/hardware/r_opengl/ogl_win.c
@@ -39,7 +39,7 @@
 #ifdef DEBUG_TO_FILE
 static unsigned long nb_frames = 0;
 static clock_t my_clock;
-FILE *logstream;
+FILE *gllogstream;
 #endif
 
 static  HDC     hDC           = NULL;       // the window's device context
@@ -81,8 +81,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
 			// Initialize once for each new process.
 			// Return FALSE to fail DLL load.
 #ifdef DEBUG_TO_FILE
-			logstream = fopen("ogllog.txt", "wt");
-			if (logstream == NULL)
+			gllogstream = fopen("ogllog.txt", "wt");
+			if (gllogstream == NULL)
 				return FALSE;
 #endif
 			DisableThreadLibraryCalls(hinstDLL);
@@ -99,10 +99,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
 		case DLL_PROCESS_DETACH:
 			// Perform any necessary cleanup.
 #ifdef DEBUG_TO_FILE
-			if (logstream)
+			if (gllogstream)
 			{
-				fclose(logstream);
-				logstream  = NULL;
+				fclose(gllogstream);
+				gllogstream  = NULL;
 			}
 #endif
 			break;
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 028bc9889eccb920eb4eca47cfce7c764649101e..76543e259806659a0c95652149c4e2979a2ec729 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -168,7 +168,6 @@ static boolean gl13 = false; // whether we can use opengl 1.3 functions
 //                  : else do nothing
 // Returns          :
 // -----------------+
-#if !(defined (HAVE_SDL) && defined (STATIC3DS))
 FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
 {
 #ifdef DEBUG_TO_FILE
@@ -178,13 +177,12 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
 	va_start (arglist, lpFmt);
 	vsnprintf (str, 4096, lpFmt, arglist);
 	va_end   (arglist);
-	if (logstream)
-		fwrite(str, strlen(str), 1, logstream);
+	if (gllogstream)
+		fwrite(str, strlen(str), 1, gllogstream);
 #else
 	(void)lpFmt;
 #endif
 }
-#endif
 
 #ifdef STATIC_OPENGL
 /* 1.0 functions */
@@ -673,7 +671,7 @@ static void GLProject(GLdouble objX, GLdouble objY, GLdouble objZ,
 // -----------------+
 void SetModelView(GLint w, GLint h)
 {
-	DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h);
+//	DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h);
 
 	screen_width = w;
 	screen_height = h;
@@ -714,7 +712,7 @@ void SetStates(void)
 	GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
 #endif
 
-	DBG_Printf("SetStates()\n");
+//	DBG_Printf("SetStates()\n");
 
 	// Hurdler: not necessary, is it?
 	pglShadeModel(GL_SMOOTH);      // iterate vertice colors
diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h
index f4d4f77e00bbf4f38ff2bccac7bee579af7e9001..7ffefbb5881405bcf5a541c0f3218164a91cd581 100644
--- a/src/hardware/r_opengl/r_opengl.h
+++ b/src/hardware/r_opengl/r_opengl.h
@@ -57,9 +57,19 @@
 
 #undef DEBUG_TO_FILE            // maybe defined in previous *.h
 #define DEBUG_TO_FILE           // output debugging msgs to ogllog.txt
-#if defined ( HAVE_SDL ) && !defined ( LOGMESSAGES )
+
+// todo: find some way of getting SDL to log to ogllog.txt, without
+// interfering with r_opengl.dll
+#ifdef HAVE_SDL
 #undef DEBUG_TO_FILE
 #endif
+//#if defined(HAVE_SDL) && !defined(_DEBUG)
+//#undef DEBUG_TO_FILE
+//#endif
+
+#ifdef DEBUG_TO_FILE
+extern FILE             *gllogstream;
+#endif
 
 #ifndef DRIVER_STRING
 //    #define USE_PALETTED_TEXTURE
@@ -117,9 +127,6 @@ extern PFNglGetString pglGetString;
 
 extern const GLubyte    *gl_extensions;
 extern RGBA_t           myPaletteData[];
-#ifndef HAVE_SDL
-extern FILE             *logstream;
-#endif
 extern GLint            screen_width;
 extern GLint            screen_height;
 extern GLbyte           screen_depth;
diff --git a/src/i_tcp.c b/src/i_tcp.c
index df7b3cf2875dd373e1e121c342b012e9125759b1..ba2f814ec787e7c728e90f286daf4a1fd7614111 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -651,7 +651,7 @@ static void SOCK_Send(void)
 					if (broadcastaddress[i].any.sa_family == AF_INET)
 						d = d4;
 #ifdef HAVE_IPV6
-					if (broadcastaddress[i].any.sa_family == AF_INET6)
+					else if (broadcastaddress[i].any.sa_family == AF_INET6)
 						d = d6;
 #endif
 					else
@@ -690,7 +690,7 @@ static void SOCK_Send(void)
 		if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET)
 			d = d4;
 #ifdef HAVE_IPV6
-		if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6)
+		else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6)
 			d = d6;
 #endif
 		else
diff --git a/src/info.c b/src/info.c
index c8f754b54d44acefbbe4ce0e90c73a1983fe8d51..fb30258c31b2ab85a813a3cc9d21d29df3bd58d3 100644
--- a/src/info.c
+++ b/src/info.c
@@ -37,23 +37,23 @@ char sprnames[NUMSPRITES + 1][5] =
 	"STEM","SPIK","SFLM","USPK","STPT","BMNE","SRBX","RRBX","BRBX","SHTV",
 	"PINV","YLTV","BLTV","BKTV","WHTV","GRTV","ELTV","EGGB","MIXU","RECY",
 	"QUES","GBTV","PRUP","PTTV","MTEX","MISL","TORP","ENRG","MINE","JBUL",
-	"TRLS","CBLL","AROW","FWR1","FWR2","FWR3","FWR4","BUS1","BUS2","THZP",
-	"ALRM","GARG","SEWE","DRIP","CRL1","CRL2","CRL3","BCRY","CHAN","FLAM",
-	"ESTA","SMCH","BMCH","SMCE","BMCE","BTBL","STBL","CACT","FLME","DFLM",
-	"XMS1","XMS2","XMS3","BSZ1","BSZ2","BSZ3","BSZ4","BSZ5","BSZ6","BSZ7",
-	"BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN","ELEM",
-	"FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC","COWZ",
-	"RBRD","SPRY","SPRR","SPRB","YSPR","RSPR","RAIN","SNO1","SPLH","SPLA",
-	"SMOK","BUBP","BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL","SCOR",
-	"DRWN","TTAG","GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE","RNGS",
-	"RNGG","PIKB","PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE","TSCR",
-	"COIN","CPRK","GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM","KOOP",
-	"BFLM","MAXE","MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL","NSPK",
-	"NBMP","HOOP","NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2","BOM3",
-	"BOM4","ROIA","ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII",
-	"ROIJ","ROIK","ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR",
-	"SRBA","SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ",
-	"SRBK","SRBL","SRBM","SRBN","SRBO",
+	"TRLS","CBLL","AROW","CFIR","FWR1","FWR2","FWR3","FWR4","BUS1","BUS2",
+	"THZP","ALRM","GARG","SEWE","DRIP","CRL1","CRL2","CRL3","BCRY","CHAN",
+	"FLAM","ESTA","SMCH","BMCH","SMCE","BMCE","BTBL","STBL","CACT","FLME",
+	"DFLM","XMS1","XMS2","XMS3","BSZ1","BSZ2","BSZ3","BSZ4","BSZ5","BSZ6",
+	"BSZ7","BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN",
+	"ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC",
+	"COWZ","RBRD","SPRY","SPRR","SPRB","YSPR","RSPR","RAIN","SNO1","SPLH",
+	"SPLA","SMOK","BUBP","BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL",
+	"SCOR","DRWN","TTAG","GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE",
+	"RNGS","RNGG","PIKB","PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE",
+	"TSCR","COIN","CPRK","GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM",
+	"KOOP","BFLM","MAXE","MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL",
+	"NSPK","NBMP","HOOP","NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2",
+	"BOM3","BOM4","ROIA","ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH",
+	"ROII","ROIJ","ROIK","ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG",
+	"GWLR","SRBA","SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI",
+	"SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO",
 };
 
 // Doesn't work with g++, needs actionf_p1 (don't modify this comment)
@@ -61,6 +61,9 @@ state_t states[NUMSTATES] =
 {
 	// frame is masked through FF_FRAMEMASK
 	// FF_FULLBRIGHT (0x8000) activates the fullbright colormap
+	// use FF_TRANS10 - FF_TRANS90 for easy translucency
+	// (or tr_trans10<<FF_TRANSSHIFT if you want to make it hard on yourself)
+
 	// Keep this comment directly above S_NULL.
 	{SPR_NULL, 0,  1, {NULL}, 0, 0, S_NULL}, // S_NULL
 	{SPR_UNKN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_UNKNOWN
@@ -75,7 +78,7 @@ state_t states[NUMSTATES] =
 	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL}, // S_RAISESTATE
 
 	// Thok
-	{SPR_THOK, 0, 8, {NULL}, 0, 0, S_NULL}, // S_THOK
+	{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_THOK
 
 	// Player
 	{SPR_PLAY,     0, 105, {NULL},   0, 0, S_PLAY_TAP1},        // S_PLAY_STND
@@ -235,15 +238,15 @@ state_t states[NUMSTATES] =
 	// THZ Turret
 	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretStop}, 0, 0, S_TURRETFIRE},   // S_TURRET
 	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretFire}, 0, 0, S_TURRET},       // S_TURRETFIRE
-	{SPR_TRET, FF_FULLBRIGHT+1, 7, {A_Pain}, 0, 0, S_TURRETSHOCK2},       // S_TURRETSHOCK1
-	{SPR_TRET, FF_FULLBRIGHT+2, 7, {NULL}, 0, 0, S_TURRETSHOCK3},         // S_TURRETSHOCK2
-	{SPR_TRET, FF_FULLBRIGHT+3, 7, {NULL}, 0, 0, S_TURRETSHOCK4},         // S_TURRETSHOCK3
-	{SPR_TRET, FF_FULLBRIGHT+4, 7, {NULL}, 0, 0, S_TURRETSHOCK5},         // S_TURRETSHOCK4
-	{SPR_TRET, FF_FULLBRIGHT+1, 7, {NULL}, 0, 0, S_TURRETSHOCK6},         // S_TURRETSHOCK5
-	{SPR_TRET, FF_FULLBRIGHT+2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7},       // S_TURRETSHOCK6
-	{SPR_TRET, FF_FULLBRIGHT+3, 7, {NULL}, 0, 0, S_TURRETSHOCK8},         // S_TURRETSHOCK7
-	{SPR_TRET, FF_FULLBRIGHT+4, 7, {NULL}, 0, 0, S_TURRETSHOCK9},         // S_TURRETSHOCK8
-	{SPR_TRET, FF_FULLBRIGHT+4, 7, {A_LinedefExecute}, 32000, 0, S_XPLD1}, // S_TURRETSHOCK9
+	{SPR_TRET, FF_FULLBRIGHT|1, 7, {A_Pain}, 0, 0, S_TURRETSHOCK2},       // S_TURRETSHOCK1
+	{SPR_TRET, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_TURRETSHOCK3},         // S_TURRETSHOCK2
+	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK4},         // S_TURRETSHOCK3
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK5},         // S_TURRETSHOCK4
+	{SPR_TRET, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_TURRETSHOCK6},         // S_TURRETSHOCK5
+	{SPR_TRET, FF_FULLBRIGHT|2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7},       // S_TURRETSHOCK6
+	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK8},         // S_TURRETSHOCK7
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK9},         // S_TURRETSHOCK8
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecute}, 32000, 0, S_XPLD1}, // S_TURRETSHOCK9
 
 	{SPR_TURR, 0, 1, {A_Look}, 1, 0, S_TURRETPOPDOWN8},          // S_TURRETLOOK
 	{SPR_TURR, 0, 0, {A_FaceTarget}, 0, 0, S_TURRETPOPUP1},  // S_TURRETSEE
@@ -415,20 +418,20 @@ state_t states[NUMSTATES] =
 
 	// Boss Explosion
 	{SPR_BOM2, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_BPLD2}, // S_BPLD1
-	{SPR_BOM2, FF_FULLBRIGHT+1, 5, {NULL}, 0, 0, S_BPLD3}, // S_BPLD2
-	{SPR_BOM2, FF_FULLBRIGHT+2, 5, {NULL}, 0, 0, S_BPLD4}, // S_BPLD3
-	{SPR_BOM2, FF_FULLBRIGHT+3, 5, {NULL}, 0, 0, S_BPLD5}, // S_BPLD4
-	{SPR_BOM2, FF_FULLBRIGHT+4, 5, {NULL}, 0, 0, S_BPLD6}, // S_BPLD5
-	{SPR_BOM2, FF_FULLBRIGHT+5, 5, {NULL}, 0, 0, S_BPLD7}, // S_BPLD6
-	{SPR_BOM2, FF_FULLBRIGHT+6, 5, {NULL}, 0, 0, S_NULL},  // S_BPLD7
+	{SPR_BOM2, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_BPLD3}, // S_BPLD2
+	{SPR_BOM2, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_BPLD4}, // S_BPLD3
+	{SPR_BOM2, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_BPLD5}, // S_BPLD4
+	{SPR_BOM2, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_BPLD6}, // S_BPLD5
+	{SPR_BOM2, FF_FULLBRIGHT|5, 5, {NULL}, 0, 0, S_BPLD7}, // S_BPLD6
+	{SPR_BOM2, FF_FULLBRIGHT|6, 5, {NULL}, 0, 0, S_NULL},  // S_BPLD7
 
 	// S3&K Boss Explosion
 	{SPR_BOM3, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION2}, // S_SONIC3KBOSSEXPLOSION1
-	{SPR_BOM3, FF_FULLBRIGHT+1, 1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION3}, // S_SONIC3KBOSSEXPLOSION2
-	{SPR_BOM3, FF_FULLBRIGHT+2, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION4}, // S_SONIC3KBOSSEXPLOSION3
-	{SPR_BOM3, FF_FULLBRIGHT+3, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION5}, // S_SONIC3KBOSSEXPLOSION4
-	{SPR_BOM3, FF_FULLBRIGHT+4, 3, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION6}, // S_SONIC3KBOSSEXPLOSION5
-	{SPR_BOM3, FF_FULLBRIGHT+5, 4, {NULL}, 0, 0, S_NULL}, // S_SONIC3KBOSSEXPLOSION6
+	{SPR_BOM3, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION3}, // S_SONIC3KBOSSEXPLOSION2
+	{SPR_BOM3, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION4}, // S_SONIC3KBOSSEXPLOSION3
+	{SPR_BOM3, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION5}, // S_SONIC3KBOSSEXPLOSION4
+	{SPR_BOM3, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION6}, // S_SONIC3KBOSSEXPLOSION5
+	{SPR_BOM3, FF_FULLBRIGHT|5, 4, {NULL}, 0, 0, S_NULL}, // S_SONIC3KBOSSEXPLOSION6
 
 	{SPR_JETF, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_JETFUME2}, // S_JETFUME1
 	{SPR_NULL, 0,             1, {NULL}, 0, 0, S_JETFUME1}, // S_JETFUME2
@@ -638,7 +641,7 @@ state_t states[NUMSTATES] =
 
 	// Boss 4 Jet flame
 	{SPR_EFIR, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_JETFLAME2}, // S_JETFLAME1
-	{SPR_EFIR, FF_FULLBRIGHT+1, 1, {NULL}, 0, 0, S_JETFLAME1}, // S_JETFLAME2
+	{SPR_EFIR, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETFLAME1}, // S_JETFLAME2
 
 	{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND
 	{SPR_BRAK, 0, 7, {A_Look}, 1, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND2
@@ -713,13 +716,13 @@ state_t states[NUMSTATES] =
 
 	{SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER}, // S_BLACKEGG_HELPER
 
-	{SPR_BGOO, 0, 2, {NULL}, 0, 0, S_BLACKEGG_GOOP2}, // S_BLACKEGG_GOOP1
-	{SPR_BGOO, 1, 2, {NULL}, 0, 0, S_BLACKEGG_GOOP1}, // S_BLACKEGG_GOOP2
-	{SPR_BGOO, 2, 6*TICRATE, {A_GoopSplat}, 0, 0, S_BLACKEGG_GOOP4}, // S_BLACKEGG_GOOP3
-	{SPR_BGOO, 2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP5}, // S_BLACKEGG_GOOP4
-	{SPR_BGOO, 2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP6}, // S_BLACKEGG_GOOP5
-	{SPR_BGOO, 2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP7}, // S_BLACKEGG_GOOP6
-	{SPR_BGOO, 2, 4, {NULL}, 0, 0, S_NULL}, // S_BLACKEGG_GOOP7
+	{SPR_BGOO, FF_TRANS50  , 2, {NULL}, 0, 0, S_BLACKEGG_GOOP2}, // S_BLACKEGG_GOOP1
+	{SPR_BGOO, FF_TRANS50|1, 2, {NULL}, 0, 0, S_BLACKEGG_GOOP1}, // S_BLACKEGG_GOOP2
+	{SPR_BGOO, FF_TRANS50|2, 6*TICRATE, {A_GoopSplat}, 0, 0, S_BLACKEGG_GOOP4}, // S_BLACKEGG_GOOP3
+	{SPR_BGOO, FF_TRANS60|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP5}, // S_BLACKEGG_GOOP4
+	{SPR_BGOO, FF_TRANS70|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP6}, // S_BLACKEGG_GOOP5
+	{SPR_BGOO, FF_TRANS80|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP7}, // S_BLACKEGG_GOOP6
+	{SPR_BGOO, FF_TRANS90|2, 4, {NULL}, 0, 0, S_NULL}, // S_BLACKEGG_GOOP7
 
 	{SPR_BMSL, 0, 1, {NULL}, 0, 0, S_BLACKEGG_MISSILE}, // S_BLACKEGG_MISSILE
 
@@ -773,12 +776,12 @@ state_t states[NUMSTATES] =
 	{SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3}, // S_CYBRAKDEMONMISSILE_EXPLODE2
 	{SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONMISSILE_EXPLODE3
 
-	{SPR_FLME, 0 + FF_FULLBRIGHT, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1
-	{SPR_FLME, 1 + FF_FULLBRIGHT, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2
-	{SPR_FLME, 2 + FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3
-	{SPR_FLME, 2 + FF_FULLBRIGHT, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE
+	{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT  , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1
+	{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2
+	{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3
+	{SPR_FLME, FF_TRANS50|FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE
 
-	{SPR_FLAM, 3 + FF_FULLBRIGHT, 3, {A_SetFuse}, 10*TICRATE, 0, S_FLAME1}, // S_CYBRAKDEMONFLAMEREST
+	{SPR_FLAM, FF_TRANS50|FF_FULLBRIGHT|3, 3, {A_SetFuse}, 10*TICRATE, 0, S_FLAME1}, // S_CYBRAKDEMONFLAMEREST
 
 	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1
 	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2
@@ -831,22 +834,22 @@ state_t states[NUMSTATES] =
 	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE3}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE2
 	{SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE3
 
-	{SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2
-	{SPR_TARG, 1 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4
-	{SPR_TARG, 2 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6
-	{SPR_TARG, 3 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8
-	{SPR_TARG, 4 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10
-	{SPR_TARG, 5 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12
-	{SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13
-	{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL}, // S_CYBRAKDEMONTARGETRETICULE14
-
-	{SPR_HOOP, 0 + FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONTARGETDOT
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|1, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|2, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|3, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|4, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|5, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL}, // S_CYBRAKDEMONTARGETRETICULE14
+
+	{SPR_HOOP, FF_TRANS50|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONTARGETDOT
 
 	{SPR_NPLM, 0, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1,
 	{SPR_NPLM, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
@@ -865,11 +868,11 @@ state_t states[NUMSTATES] =
 	{SPR_NULL, 0, 24, {A_Scream}, 0, 0, S_NULL}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5, // Sound
 
 	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY2}, //S_CYBRAKDEMONNAPALMFLAME_FLY1,
-	{SPR_SFLM, FF_FULLBRIGHT+1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY3}, //S_CYBRAKDEMONNAPALMFLAME_FLY2,
-	{SPR_SFLM, FF_FULLBRIGHT+2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY4}, //S_CYBRAKDEMONNAPALMFLAME_FLY3,
-	{SPR_SFLM, FF_FULLBRIGHT+3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY5}, //S_CYBRAKDEMONNAPALMFLAME_FLY4,
-	{SPR_SFLM, FF_FULLBRIGHT+4, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY6}, //S_CYBRAKDEMONNAPALMFLAME_FLY5,
-	{SPR_SFLM, FF_FULLBRIGHT+5, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY1}, //S_CYBRAKDEMONNAPALMFLAME_FLY6,
+	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY3}, //S_CYBRAKDEMONNAPALMFLAME_FLY2,
+	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY4}, //S_CYBRAKDEMONNAPALMFLAME_FLY3,
+	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY5}, //S_CYBRAKDEMONNAPALMFLAME_FLY4,
+	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY6}, //S_CYBRAKDEMONNAPALMFLAME_FLY5,
+	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY1}, //S_CYBRAKDEMONNAPALMFLAME_FLY6,
 	{SPR_SFLM, FF_FULLBRIGHT,   0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, //S_CYBRAKDEMONNAPALMFLAME_DIE,
 
 	{SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2}, //S_CYBRAKDEMONVILEEXPLOSION1,
@@ -909,18 +912,18 @@ state_t states[NUMSTATES] =
 	{SPR_METL,  5,  4, {NULL},         0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3
 	{SPR_METL,  4,  4, {NULL},         0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4
 
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2},  // S_MSSHIELD_F1
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3},  // S_MSSHIELD_F2
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 2, 1, {NULL}, 0, 0, S_MSSHIELD_F4},  // S_MSSHIELD_F3
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 3, 1, {NULL}, 0, 0, S_MSSHIELD_F5},  // S_MSSHIELD_F4
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 4, 1, {NULL}, 0, 0, S_MSSHIELD_F6},  // S_MSSHIELD_F5
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 5, 1, {NULL}, 0, 0, S_MSSHIELD_F7},  // S_MSSHIELD_F6
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 6, 1, {NULL}, 0, 0, S_MSSHIELD_F8},  // S_MSSHIELD_F7
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 7, 1, {NULL}, 0, 0, S_MSSHIELD_F9},  // S_MSSHIELD_F8
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 8, 1, {NULL}, 0, 0, S_MSSHIELD_F10}, // S_MSSHIELD_F9
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)| 9, 1, {NULL}, 0, 0, S_MSSHIELD_F11}, // S_MSSHIELD_F10
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)|10, 1, {NULL}, 0, 0, S_MSSHIELD_F12}, // S_MSSHIELD_F11
-	{SPR_MSCF, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT)|11, 1, {NULL}, 0, 0, S_MSSHIELD_F1},  // S_MSSHIELD_F12
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2},  // S_MSSHIELD_F1
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3},  // S_MSSHIELD_F2
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 2, 1, {NULL}, 0, 0, S_MSSHIELD_F4},  // S_MSSHIELD_F3
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 3, 1, {NULL}, 0, 0, S_MSSHIELD_F5},  // S_MSSHIELD_F4
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 4, 1, {NULL}, 0, 0, S_MSSHIELD_F6},  // S_MSSHIELD_F5
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 5, 1, {NULL}, 0, 0, S_MSSHIELD_F7},  // S_MSSHIELD_F6
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 6, 1, {NULL}, 0, 0, S_MSSHIELD_F8},  // S_MSSHIELD_F7
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 7, 1, {NULL}, 0, 0, S_MSSHIELD_F9},  // S_MSSHIELD_F8
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 8, 1, {NULL}, 0, 0, S_MSSHIELD_F10}, // S_MSSHIELD_F9
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 9, 1, {NULL}, 0, 0, S_MSSHIELD_F11}, // S_MSSHIELD_F10
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|10, 1, {NULL}, 0, 0, S_MSSHIELD_F12}, // S_MSSHIELD_F11
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|11, 1, {NULL}, 0, 0, S_MSSHIELD_F1},  // S_MSSHIELD_F12
 
 	// Ring
 	{SPR_RING,  0, 1, {NULL}, 0, 0, S_RING2},  // S_RING1
@@ -989,16 +992,16 @@ state_t states[NUMSTATES] =
 
 	// Special Stage Token
 	{SPR_EMMY, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_EMMY2}, // S_EMMY1
-	{SPR_EMMY, FF_FULLBRIGHT+1, 2, {NULL}, 0, 0, S_EMMY3}, // S_EMMY2
-	{SPR_EMMY, FF_FULLBRIGHT+2, 2, {NULL}, 0, 0, S_EMMY4}, // S_EMMY3
-	{SPR_EMMY, FF_FULLBRIGHT+3, 2, {NULL}, 0, 0, S_EMMY5}, // S_EMMY4
-	{SPR_EMMY, FF_FULLBRIGHT+4, 2, {NULL}, 0, 0, S_EMMY6}, // S_EMMY5
-	{SPR_EMMY, FF_FULLBRIGHT+5, 2, {NULL}, 0, 0, S_EMMY7}, // S_EMMY6
-	{SPR_EMMY, FF_FULLBRIGHT+6, 2, {NULL}, 0, 0, S_EMMY1}, // S_EMMY7
+	{SPR_EMMY, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_EMMY3}, // S_EMMY2
+	{SPR_EMMY, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_EMMY4}, // S_EMMY3
+	{SPR_EMMY, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_EMMY5}, // S_EMMY4
+	{SPR_EMMY, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_EMMY6}, // S_EMMY5
+	{SPR_EMMY, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_EMMY7}, // S_EMMY6
+	{SPR_EMMY, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_EMMY1}, // S_EMMY7
 
 	// Special Stage Token
-	{SPR_TOKE, FF_FULLBRIGHT,-1, {NULL}, 0, 0, S_NULL}, // S_TOKEN
-	{SPR_TOKE, FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_MOVINGTOKEN}, // S_MOVINGTOKEN
+	{SPR_TOKE, FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_TOKEN
+	{SPR_TOKE, FF_TRANS50|FF_FULLBRIGHT,  1, {A_CapeChase}, 0, 0, S_MOVINGTOKEN}, // S_MOVINGTOKEN
 
 	// CTF Flags
 	{SPR_RFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REDFLAG
@@ -1034,12 +1037,12 @@ state_t states[NUMSTATES] =
 
 	// Chaos Emeralds
 	{SPR_CEMG, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL}, // S_CEMG1
-	{SPR_CEMG, FF_FULLBRIGHT+1, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG2
-	{SPR_CEMG, FF_FULLBRIGHT+2, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG3
-	{SPR_CEMG, FF_FULLBRIGHT+3, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG4
-	{SPR_CEMG, FF_FULLBRIGHT+4, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG5
-	{SPR_CEMG, FF_FULLBRIGHT+5, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG6
-	{SPR_CEMG, FF_FULLBRIGHT+6, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG7
+	{SPR_CEMG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG2
+	{SPR_CEMG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG3
+	{SPR_CEMG, FF_FULLBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG4
+	{SPR_CEMG, FF_FULLBRIGHT|4, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG5
+	{SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG6
+	{SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG7
 
 	// Emeralds (for hunt)
 	{SPR_EMER, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EMER1
@@ -1132,11 +1135,11 @@ state_t states[NUMSTATES] =
 
 	// Red Shield's Spawn
 	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_SPINFIRE2}, // S_SPINFIRE1
-	{SPR_SFLM, FF_FULLBRIGHT+1, 2, {NULL}, 0, 0, S_SPINFIRE3}, // S_SPINFIRE2
-	{SPR_SFLM, FF_FULLBRIGHT+2, 2, {NULL}, 0, 0, S_SPINFIRE4}, // S_SPINFIRE3
-	{SPR_SFLM, FF_FULLBRIGHT+3, 2, {NULL}, 0, 0, S_SPINFIRE5}, // S_SPINFIRE4
-	{SPR_SFLM, FF_FULLBRIGHT+4, 2, {NULL}, 0, 0, S_SPINFIRE6}, // S_SPINFIRE5
-	{SPR_SFLM, FF_FULLBRIGHT+5, 2, {NULL}, 0, 0, S_SPINFIRE1}, // S_SPINFIRE6
+	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_SPINFIRE3}, // S_SPINFIRE2
+	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SPINFIRE4}, // S_SPINFIRE3
+	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SPINFIRE5}, // S_SPINFIRE4
+	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_SPINFIRE6}, // S_SPINFIRE5
+	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_SPINFIRE1}, // S_SPINFIRE6
 
 	// Floor Spike
 	{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended
@@ -1372,7 +1375,7 @@ state_t states[NUMSTATES] =
 
 	{SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO}, // S_TORPEDO
 
-	{SPR_ENRG, FF_FULLBRIGHT|(tr_trans30<<FF_TRANSSHIFT), 1, {NULL}, 0, 0, S_ENERGYBALL2}, // S_ENERGYBALL1
+	{SPR_ENRG, FF_FULLBRIGHT|FF_TRANS30, 1, {NULL}, 0, 0, S_ENERGYBALL2}, // S_ENERGYBALL1
 	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ENERGYBALL1}, // S_ENERGYBALL2
 
 	// Skim Mine (also dropped by Jetty-Syn bomber)
@@ -1384,11 +1387,11 @@ state_t states[NUMSTATES] =
 
 	// Jetty-Syn Bullet
 	{SPR_JBUL, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_JETBULLET2}, // S_JETBULLET1
-	{SPR_JBUL, FF_FULLBRIGHT+1, 1, {NULL}, 0, 0, S_JETBULLET1}, // S_JETBULLET2
+	{SPR_JBUL, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETBULLET1}, // S_JETBULLET2
 
 	{SPR_TRLS, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_TURRETLASER},          // S_TURRETLASER
-	{SPR_TRLS, FF_FULLBRIGHT+1, 2, {NULL}, 0, 0, S_TURRETLASEREXPLODE2},  // S_TURRETLASEREXPLODE1
-	{SPR_TRLS, FF_FULLBRIGHT+2, 2, {NULL}, 0, 0, S_NULL},                 // S_TURRETLASEREXPLODE2
+	{SPR_TRLS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TURRETLASEREXPLODE2},  // S_TURRETLASEREXPLODE1
+	{SPR_TRLS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL},                 // S_TURRETLASEREXPLODE2
 
 	{SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANNONBALL1
 
@@ -1396,7 +1399,12 @@ state_t states[NUMSTATES] =
 	{SPR_AROW, 1, 1, {A_ArrowCheck}, 0, 0, S_ARROWUP},   // S_ARROWUP
 	{SPR_AROW, 2, 1, {A_ArrowCheck}, 0, 0, S_ARROWDOWN}, // S_ARROWDOWN
 
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_SPINFIRE1}, // S_DEMONFIRE
+	{SPR_CFIR, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_DEMONFIRE2}, // S_DEMONFIRE1
+	{SPR_CFIR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEMONFIRE3}, // S_DEMONFIRE2
+	{SPR_CFIR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEMONFIRE4}, // S_DEMONFIRE3
+	{SPR_CFIR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_DEMONFIRE5}, // S_DEMONFIRE4
+	{SPR_CFIR, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_DEMONFIRE6}, // S_DEMONFIRE5
+	{SPR_CFIR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_DEMONFIRE1}, // S_DEMONFIRE6
 
 	// GFZ Flower
 	{SPR_FWR1, 0, 14, {NULL}, 0, 0, S_GFZFLOWERA2}, // S_GFZFLOWERA
@@ -1430,13 +1438,13 @@ state_t states[NUMSTATES] =
 	{SPR_SEWE, 5, 5, {NULL}, 0, 0, S_SEAWEED1}, // S_SEAWEED6
 
 	// Dripping water
-	{SPR_NULL, 0, 3*TICRATE, {NULL},                  0, 0, S_DRIPA2}, // S_DRIPA1
-	{SPR_DRIP, 0,         2, {NULL},                  0, 0, S_DRIPA3}, // S_DRIPA2
-	{SPR_DRIP, 1,         2, {NULL},                  0, 0, S_DRIPA4}, // S_DRIPA3
-	{SPR_DRIP, 2,         2, {A_SpawnObjectRelative}, 0, MT_WATERDROP, S_DRIPA1}, // S_DRIPA4
-	{SPR_DRIP, 3,        -1, {NULL},                  0, 0, S_DRIPB1}, // S_DRIPB1
-	{SPR_DRIP, 4,         1, {NULL},                  0, 0, S_DRIPC2}, // S_DRIPC1
-	{SPR_DRIP, 5,         1, {NULL},                  0, 0,   S_NULL}, // S_DRIPC2
+	{SPR_NULL, FF_TRANS30  , 3*TICRATE, {NULL},                  0, 0, S_DRIPA2}, // S_DRIPA1
+	{SPR_DRIP, FF_TRANS30  ,         2, {NULL},                  0, 0, S_DRIPA3}, // S_DRIPA2
+	{SPR_DRIP, FF_TRANS30|1,         2, {NULL},                  0, 0, S_DRIPA4}, // S_DRIPA3
+	{SPR_DRIP, FF_TRANS30|2,         2, {A_SpawnObjectRelative}, 0, MT_WATERDROP, S_DRIPA1}, // S_DRIPA4
+	{SPR_DRIP, FF_TRANS30|3,        -1, {NULL},                  0, 0, S_DRIPB1}, // S_DRIPB1
+	{SPR_DRIP, FF_TRANS30|4,         1, {NULL},                  0, 0, S_DRIPC2}, // S_DRIPC1
+	{SPR_DRIP, FF_TRANS30|5,         1, {NULL},                  0, 0,   S_NULL}, // S_DRIPC2
 
 	// Coral 1
 	{SPR_CRL1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1
@@ -1448,16 +1456,16 @@ state_t states[NUMSTATES] =
 	{SPR_CRL3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3
 
 	// Blue Crystal
-	{SPR_BCRY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1
+	{SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1
 
 	// CEZ Chain
 	{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN
 
 	// Flame
-	{SPR_FLAM, FF_FULLBRIGHT,   3, {NULL}, 0, 0, S_FLAME2}, // S_FLAME1
-	{SPR_FLAM, FF_FULLBRIGHT+1, 3, {NULL}, 0, 0, S_FLAME3}, // S_FLAME2
-	{SPR_FLAM, FF_FULLBRIGHT+2, 3, {NULL}, 0, 0, S_FLAME4}, // S_FLAME3
-	{SPR_FLAM, FF_FULLBRIGHT+3, 3, {NULL}, 0, 0, S_FLAME1}, // S_FLAME4
+	{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50,   3, {NULL}, 0, 0, S_FLAME2}, // S_FLAME1
+	{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50|1, 3, {NULL}, 0, 0, S_FLAME3}, // S_FLAME2
+	{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50|2, 3, {NULL}, 0, 0, S_FLAME4}, // S_FLAME3
+	{SPR_FLAM, FF_FULLBRIGHT|FF_TRANS50|3, 3, {NULL}, 0, 0, S_FLAME1}, // S_FLAME4
 
 	// Eggman statue
 	{SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE1
@@ -1513,9 +1521,9 @@ state_t states[NUMSTATES] =
 	{SPR_NULL, 0, 2*TICRATE, {NULL},             0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND
 	{SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTOP}, // S_FLAMEJETSTART
 	{SPR_NULL, 0,         1, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTND}, // S_FLAMEJETSTOP
-	{SPR_FLME, 0,         4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1
-	{SPR_FLME, 1,         5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2
-	{SPR_FLME, 2,        11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME3
+	{SPR_FLME, FF_TRANS50  ,  4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1
+	{SPR_FLME, FF_TRANS60|1,  5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2
+	{SPR_FLME, FF_TRANS70|2, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME3
 
 	// Spinning flame jets
 	// A: Counter-clockwise
@@ -1549,12 +1557,12 @@ state_t states[NUMSTATES] =
 	{SPR_NULL, 0, 1, {A_CapeChase}, 0, (64<<16), S_FJSPINHELPERB3}, // S_FJSPINHELPERB3
 
 	// Blade's flame
-	{SPR_DFLM, FF_FULLBRIGHT|(tr_trans40<<FF_TRANSSHIFT)|1, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2}, // S_FLAMEJETFLAMEB1
-	{SPR_DFLM, FF_FULLBRIGHT|(tr_trans40<<FF_TRANSSHIFT)|2, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2
-	{SPR_DFLM, FF_FULLBRIGHT|(tr_trans40<<FF_TRANSSHIFT)|3,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB4}, // S_FLAMEJETFLAMEB3
-	{SPR_DFLM, FF_FULLBRIGHT|(tr_trans40<<FF_TRANSSHIFT)|4,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB5}, // S_FLAMEJETFLAMEB4
-	{SPR_DFLM, FF_FULLBRIGHT|(tr_trans40<<FF_TRANSSHIFT)|5,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB6}, // S_FLAMEJETFLAMEB5
-	{SPR_DFLM, FF_FULLBRIGHT|(tr_trans40<<FF_TRANSSHIFT)|6,12, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAMEB6
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|1, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2}, // S_FLAMEJETFLAMEB1
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|2, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|3,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB4}, // S_FLAMEJETFLAMEB3
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|4,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB5}, // S_FLAMEJETFLAMEB4
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|5,24, {NULL}, 0, 0, S_FLAMEJETFLAMEB6}, // S_FLAMEJETFLAMEB5
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|6,12, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAMEB6
 
 	// Trapgoyles
 	{SPR_GARG, 0, 67, {NULL},       0, 0, S_TRAPGOYLE_CHECK},  // S_TRAPGOYLE
@@ -1585,10 +1593,10 @@ state_t states[NUMSTATES] =
 
 	// Target/Red Crystal
 	{SPR_RCRY,               0, -1, {NULL},                  0, 0, S_TARGET_IDLE},  // S_TARGET_IDLE
-	{SPR_RCRY, FF_FULLBRIGHT+1,  0, {A_PlaySound},           sfx_ding, 1, S_TARGET_HIT2},  // S_TARGET_HIT1
-	{SPR_RCRY, FF_FULLBRIGHT+1, 45, {A_SetObjectFlags},      MF_PUSHABLE, 2, S_TARGET_RESPAWN},  // S_TARGET_HIT2
+	{SPR_RCRY, FF_FULLBRIGHT|1,  0, {A_PlaySound},           sfx_ding, 1, S_TARGET_HIT2},  // S_TARGET_HIT1
+	{SPR_RCRY, FF_FULLBRIGHT|1, 45, {A_SetObjectFlags},      MF_PUSHABLE, 2, S_TARGET_RESPAWN},  // S_TARGET_HIT2
 	{SPR_RCRY,               1,  0, {A_SpawnObjectRelative}, 0, MT_TARGET, S_NULL},  // S_TARGET_RESPAWN
-	{SPR_RCRY, FF_FULLBRIGHT+1, -1, {A_SetObjectFlags},      MF_PUSHABLE, 1, S_TARGET_ALLDONE},  // S_TARGET_ALLDONE
+	{SPR_RCRY, FF_FULLBRIGHT|1, -1, {A_SetObjectFlags},      MF_PUSHABLE, 1, S_TARGET_ALLDONE},  // S_TARGET_ALLDONE
 
 	// Stalagmites
 	{SPR_STLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_STG0
@@ -1657,142 +1665,142 @@ state_t states[NUMSTATES] =
 
 	// Disco ball
 	{SPR_DBAL, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_DBALL2}, // S_DBALL1
-	{SPR_DBAL, FF_FULLBRIGHT+1, 5, {NULL}, 0, 0, S_DBALL3}, // S_DBALL2
-	{SPR_DBAL, FF_FULLBRIGHT+2, 5, {NULL}, 0, 0, S_DBALL4}, // S_DBALL3
-	{SPR_DBAL, FF_FULLBRIGHT+3, 5, {NULL}, 0, 0, S_DBALL5}, // S_DBALL4
-	{SPR_DBAL, FF_FULLBRIGHT+4, 5, {NULL}, 0, 0, S_DBALL6}, // S_DBALL5
-	{SPR_DBAL, FF_FULLBRIGHT+5, 5, {NULL}, 0, 0, S_DBALL1}, // S_DBALL6
+	{SPR_DBAL, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_DBALL3}, // S_DBALL2
+	{SPR_DBAL, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_DBALL4}, // S_DBALL3
+	{SPR_DBAL, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_DBALL5}, // S_DBALL4
+	{SPR_DBAL, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_DBALL6}, // S_DBALL5
+	{SPR_DBAL, FF_FULLBRIGHT|5, 5, {NULL}, 0, 0, S_DBALL1}, // S_DBALL6
 
 	{SPR_ESTA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE2
 
 	// Shield Orb
-	{SPR_ARMA,  0, 2, {NULL}, 0, 0, S_ARMA2 }, // S_ARMA1
-	{SPR_ARMA,  1, 2, {NULL}, 0, 0, S_ARMA3 }, // S_ARMA2
-	{SPR_ARMA,  2, 2, {NULL}, 0, 0, S_ARMA4 }, // S_ARMA3
-	{SPR_ARMA,  3, 2, {NULL}, 0, 0, S_ARMA5 }, // S_ARMA4
-	{SPR_ARMA,  4, 2, {NULL}, 0, 0, S_ARMA6 }, // S_ARMA5
-	{SPR_ARMA,  5, 2, {NULL}, 0, 0, S_ARMA7 }, // S_ARMA6
-	{SPR_ARMA,  6, 2, {NULL}, 0, 0, S_ARMA8 }, // S_ARMA7
-	{SPR_ARMA,  7, 2, {NULL}, 0, 0, S_ARMA9 }, // S_ARMA8
-	{SPR_ARMA,  8, 2, {NULL}, 0, 0, S_ARMA10}, // S_ARMA9
-	{SPR_ARMA,  9, 2, {NULL}, 0, 0, S_ARMA11}, // S_ARMA10
-	{SPR_ARMA, 10, 2, {NULL}, 0, 0, S_ARMA12}, // S_ARMA11
-	{SPR_ARMA, 11, 2, {NULL}, 0, 0, S_ARMA13}, // S_ARMA12
-	{SPR_ARMA, 12, 2, {NULL}, 0, 0, S_ARMA14}, // S_ARMA13
-	{SPR_ARMA, 13, 2, {NULL}, 0, 0, S_ARMA15}, // S_ARMA14
-	{SPR_ARMA, 14, 2, {NULL}, 0, 0, S_ARMA16}, // S_ARMA15
-	{SPR_ARMA, 15, 2, {NULL}, 0, 0, S_ARMA1 }, // S_ARMA16
-
-	{SPR_ARMF,  0+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF2 }, // S_ARMF1
-	{SPR_ARMF,  1+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF3 }, // S_ARMF2
-	{SPR_ARMF,  2+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF4 }, // S_ARMF3
-	{SPR_ARMF,  3+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF5 }, // S_ARMF4
-	{SPR_ARMF,  4+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF6 }, // S_ARMF5
-	{SPR_ARMF,  5+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF7 }, // S_ARMF6
-	{SPR_ARMF,  6+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF8 }, // S_ARMF7
-	{SPR_ARMF,  7+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF9 }, // S_ARMF8
-	{SPR_ARMF,  8+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF10}, // S_ARMF9
-	{SPR_ARMF,  9+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF11}, // S_ARMF10
-	{SPR_ARMF, 10+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF12}, // S_ARMF11
-	{SPR_ARMF, 11+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF13}, // S_ARMF12
-	{SPR_ARMF, 12+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF14}, // S_ARMF13
-	{SPR_ARMF, 13+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF15}, // S_ARMF14
-	{SPR_ARMF, 14+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF16}, // S_ARMF15
-	{SPR_ARMF, 15+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ARMF1 }, // S_ARMF16
-
-	{SPR_ARMB,  0+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB2 }, // S_ARMB1
-	{SPR_ARMB,  1+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB3 }, // S_ARMB2
-	{SPR_ARMB,  2+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB4 }, // S_ARMB3
-	{SPR_ARMB,  3+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB5 }, // S_ARMB4
-	{SPR_ARMB,  4+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB6 }, // S_ARMB5
-	{SPR_ARMB,  5+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB7 }, // S_ARMB6
-	{SPR_ARMB,  6+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB8 }, // S_ARMB7
-	{SPR_ARMB,  7+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB9 }, // S_ARMB8
-	{SPR_ARMB,  8+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB10}, // S_ARMB9
-	{SPR_ARMB,  9+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB11}, // S_ARMB10
-	{SPR_ARMB, 10+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB12}, // S_ARMB11
-	{SPR_ARMB, 11+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB13}, // S_ARMB12
-	{SPR_ARMB, 12+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB14}, // S_ARMB13
-	{SPR_ARMB, 13+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB15}, // S_ARMB14
-	{SPR_ARMB, 14+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB16}, // S_ARMB15
-	{SPR_ARMB, 15+FF_FULLBRIGHT, 3, {NULL}, 1, 0, S_ARMB1 }, // S_ARMB16
-
-	{SPR_WIND, 0, 2, {NULL}, 0, 0, S_WIND2}, // S_WIND1
-	{SPR_WIND, 1, 2, {NULL}, 0, 0, S_WIND3}, // S_WIND2
-	{SPR_WIND, 2, 2, {NULL}, 0, 0, S_WIND4}, // S_WIND3
-	{SPR_WIND, 3, 2, {NULL}, 0, 0, S_WIND5}, // S_WIND4
-	{SPR_WIND, 4, 2, {NULL}, 0, 0, S_WIND6}, // S_WIND5
-	{SPR_WIND, 5, 2, {NULL}, 0, 0, S_WIND7}, // S_WIND6
-	{SPR_WIND, 6, 2, {NULL}, 0, 0, S_WIND8}, // S_WIND7
-	{SPR_WIND, 7, 2, {NULL}, 0, 0, S_WIND1}, // S_WIND8
-
-	{SPR_MAGN,  0+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN2 }, // S_MAGN1
-	{SPR_MAGN,  1+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN3 }, // S_MAGN2
-	{SPR_MAGN,  2+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN4 }, // S_MAGN3
-	{SPR_MAGN,  3+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN5 }, // S_MAGN4
-	{SPR_MAGN,  4+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN6 }, // S_MAGN5
-	{SPR_MAGN,  5+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN7 }, // S_MAGN6
-	{SPR_MAGN,  6+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN8 }, // S_MAGN7
-	{SPR_MAGN,  7+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN9 }, // S_MAGN8
-	{SPR_MAGN,  8+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN10}, // S_MAGN9
-	{SPR_MAGN,  9+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN11}, // S_MAGN10
-	{SPR_MAGN, 10+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN12}, // S_MAGN11
-	{SPR_MAGN, 11+FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN12
-
-	{SPR_FORC, 0, 3, {NULL}, 0, 0, S_FORC2 }, // S_FORC1
-	{SPR_FORC, 1, 3, {NULL}, 0, 0, S_FORC3 }, // S_FORC2
-	{SPR_FORC, 2, 3, {NULL}, 0, 0, S_FORC4 }, // S_FORC3
-	{SPR_FORC, 3, 3, {NULL}, 0, 0, S_FORC5 }, // S_FORC4
-	{SPR_FORC, 4, 3, {NULL}, 0, 0, S_FORC6 }, // S_FORC5
-	{SPR_FORC, 5, 3, {NULL}, 0, 0, S_FORC7 }, // S_FORC6
-	{SPR_FORC, 6, 3, {NULL}, 0, 0, S_FORC8 }, // S_FORC7
-	{SPR_FORC, 7, 3, {NULL}, 0, 0, S_FORC9 }, // S_FORC8
-	{SPR_FORC, 8, 3, {NULL}, 0, 0, S_FORC10}, // S_FORC9
-	{SPR_FORC, 9, 3, {NULL}, 0, 0, S_FORC1 }, // S_FORC10
-
-	{SPR_FORC,10, 3, {NULL}, 0, 0, S_FORC12}, // S_FORC11
-	{SPR_FORC,11, 3, {NULL}, 0, 0, S_FORC13}, // S_FORC12
-	{SPR_FORC,12, 3, {NULL}, 0, 0, S_FORC14}, // S_FORC13
-	{SPR_FORC,13, 3, {NULL}, 0, 0, S_FORC15}, // S_FORC14
-	{SPR_FORC,14, 3, {NULL}, 0, 0, S_FORC16}, // S_FORC15
-	{SPR_FORC,15, 3, {NULL}, 0, 0, S_FORC17}, // S_FORC16
-	{SPR_FORC,16, 3, {NULL}, 0, 0, S_FORC18}, // S_FORC17
-	{SPR_FORC,17, 3, {NULL}, 0, 0, S_FORC19}, // S_FORC18
-	{SPR_FORC,18, 3, {NULL}, 0, 0, S_FORC20}, // S_FORC19
-	{SPR_FORC,19, 3, {NULL}, 0, 0, S_FORC11}, // S_FORC20
-
-	{SPR_ELEM,  0, 4, {NULL}, 0, 0, S_ELEM2 }, // S_ELEM1
-	{SPR_ELEM,  1, 4, {NULL}, 0, 0, S_ELEM3 }, // S_ELEM2
-	{SPR_ELEM,  2, 4, {NULL}, 0, 0, S_ELEM4 }, // S_ELEM3
-	{SPR_ELEM,  3, 4, {NULL}, 0, 0, S_ELEM5 }, // S_ELEM4
-	{SPR_ELEM,  4, 4, {NULL}, 0, 0, S_ELEM6 }, // S_ELEM5
-	{SPR_ELEM,  5, 4, {NULL}, 0, 0, S_ELEM7 }, // S_ELEM6
-	{SPR_ELEM,  6, 4, {NULL}, 0, 0, S_ELEM8 }, // S_ELEM7
-	{SPR_ELEM,  7, 4, {NULL}, 0, 0, S_ELEM9 }, // S_ELEM8
-	{SPR_ELEM,  8, 4, {NULL}, 0, 0, S_ELEM10}, // S_ELEM9
-	{SPR_ELEM,  9, 4, {NULL}, 0, 0, S_ELEM11}, // S_ELEM10
-	{SPR_ELEM, 10, 4, {NULL}, 0, 0, S_ELEM12}, // S_ELEM11
-	{SPR_ELEM, 11, 4, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM12
-
-	{SPR_ELEM, 12+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF2}, // S_ELEMF1
-	{SPR_ELEM, 13+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF3}, // S_ELEMF2
-	{SPR_ELEM, 14+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF4}, // S_ELEMF3
-	{SPR_ELEM, 15+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF5}, // S_ELEMF4
-	{SPR_ELEM, 16+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF6}, // S_ELEMF5
-	{SPR_ELEM, 17+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF7}, // S_ELEMF6
-	{SPR_ELEM, 18+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF8}, // S_ELEMF7
-	{SPR_ELEM, 19+FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_ELEMF1}, // S_ELEMF8
-
-	{SPR_PITY, 0, 1, {NULL}, 0, 0, S_PITY2 }, // S_PITY1
-	{SPR_PITY, 1, 1, {NULL}, 0, 0, S_PITY3 }, // S_PITY2
-	{SPR_PITY, 0, 1, {NULL}, 0, 0, S_PITY4 }, // S_PITY3
-	{SPR_PITY, 2, 1, {NULL}, 0, 0, S_PITY5 }, // S_PITY4
-	{SPR_PITY, 0, 1, {NULL}, 0, 0, S_PITY6 }, // S_PITY5
-	{SPR_PITY, 3, 1, {NULL}, 0, 0, S_PITY7 }, // S_PITY6
-	{SPR_PITY, 0, 1, {NULL}, 0, 0, S_PITY8 }, // S_PITY7
-	{SPR_PITY, 4, 1, {NULL}, 0, 0, S_PITY9 }, // S_PITY8
-	{SPR_PITY, 0, 1, {NULL}, 0, 0, S_PITY10}, // S_PITY9
-	{SPR_PITY, 5, 1, {NULL}, 0, 0, S_PITY1 }, // S_PITY10
+	{SPR_ARMA, FF_TRANS40   , 2, {NULL}, 0, 0, S_ARMA2 }, // S_ARMA1
+	{SPR_ARMA, FF_TRANS40| 1, 2, {NULL}, 0, 0, S_ARMA3 }, // S_ARMA2
+	{SPR_ARMA, FF_TRANS40| 2, 2, {NULL}, 0, 0, S_ARMA4 }, // S_ARMA3
+	{SPR_ARMA, FF_TRANS40| 3, 2, {NULL}, 0, 0, S_ARMA5 }, // S_ARMA4
+	{SPR_ARMA, FF_TRANS40| 4, 2, {NULL}, 0, 0, S_ARMA6 }, // S_ARMA5
+	{SPR_ARMA, FF_TRANS40| 5, 2, {NULL}, 0, 0, S_ARMA7 }, // S_ARMA6
+	{SPR_ARMA, FF_TRANS40| 6, 2, {NULL}, 0, 0, S_ARMA8 }, // S_ARMA7
+	{SPR_ARMA, FF_TRANS40| 7, 2, {NULL}, 0, 0, S_ARMA9 }, // S_ARMA8
+	{SPR_ARMA, FF_TRANS40| 8, 2, {NULL}, 0, 0, S_ARMA10}, // S_ARMA9
+	{SPR_ARMA, FF_TRANS40| 9, 2, {NULL}, 0, 0, S_ARMA11}, // S_ARMA10
+	{SPR_ARMA, FF_TRANS40|10, 2, {NULL}, 0, 0, S_ARMA12}, // S_ARMA11
+	{SPR_ARMA, FF_TRANS40|11, 2, {NULL}, 0, 0, S_ARMA13}, // S_ARMA12
+	{SPR_ARMA, FF_TRANS40|12, 2, {NULL}, 0, 0, S_ARMA14}, // S_ARMA13
+	{SPR_ARMA, FF_TRANS40|13, 2, {NULL}, 0, 0, S_ARMA15}, // S_ARMA14
+	{SPR_ARMA, FF_TRANS40|14, 2, {NULL}, 0, 0, S_ARMA16}, // S_ARMA15
+	{SPR_ARMA, FF_TRANS40|15, 2, {NULL}, 0, 0, S_ARMA1 }, // S_ARMA16
+
+	{SPR_ARMF, FF_FULLBRIGHT   , 3, {NULL}, 0, 0, S_ARMF2 }, // S_ARMF1
+	{SPR_ARMF, FF_FULLBRIGHT| 1, 3, {NULL}, 0, 0, S_ARMF3 }, // S_ARMF2
+	{SPR_ARMF, FF_FULLBRIGHT| 2, 3, {NULL}, 0, 0, S_ARMF4 }, // S_ARMF3
+	{SPR_ARMF, FF_FULLBRIGHT| 3, 3, {NULL}, 0, 0, S_ARMF5 }, // S_ARMF4
+	{SPR_ARMF, FF_FULLBRIGHT| 4, 3, {NULL}, 0, 0, S_ARMF6 }, // S_ARMF5
+	{SPR_ARMF, FF_FULLBRIGHT| 5, 3, {NULL}, 0, 0, S_ARMF7 }, // S_ARMF6
+	{SPR_ARMF, FF_FULLBRIGHT| 6, 3, {NULL}, 0, 0, S_ARMF8 }, // S_ARMF7
+	{SPR_ARMF, FF_FULLBRIGHT| 7, 3, {NULL}, 0, 0, S_ARMF9 }, // S_ARMF8
+	{SPR_ARMF, FF_FULLBRIGHT| 8, 3, {NULL}, 0, 0, S_ARMF10}, // S_ARMF9
+	{SPR_ARMF, FF_FULLBRIGHT| 9, 3, {NULL}, 0, 0, S_ARMF11}, // S_ARMF10
+	{SPR_ARMF, FF_FULLBRIGHT|10, 3, {NULL}, 0, 0, S_ARMF12}, // S_ARMF11
+	{SPR_ARMF, FF_FULLBRIGHT|11, 3, {NULL}, 0, 0, S_ARMF13}, // S_ARMF12
+	{SPR_ARMF, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ARMF14}, // S_ARMF13
+	{SPR_ARMF, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ARMF15}, // S_ARMF14
+	{SPR_ARMF, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ARMF16}, // S_ARMF15
+	{SPR_ARMF, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ARMF1 }, // S_ARMF16
+
+	{SPR_ARMB, FF_FULLBRIGHT| 0, 3, {NULL}, 1, 0, S_ARMB2 }, // S_ARMB1
+	{SPR_ARMB, FF_FULLBRIGHT| 1, 3, {NULL}, 1, 0, S_ARMB3 }, // S_ARMB2
+	{SPR_ARMB, FF_FULLBRIGHT| 2, 3, {NULL}, 1, 0, S_ARMB4 }, // S_ARMB3
+	{SPR_ARMB, FF_FULLBRIGHT| 3, 3, {NULL}, 1, 0, S_ARMB5 }, // S_ARMB4
+	{SPR_ARMB, FF_FULLBRIGHT| 4, 3, {NULL}, 1, 0, S_ARMB6 }, // S_ARMB5
+	{SPR_ARMB, FF_FULLBRIGHT| 5, 3, {NULL}, 1, 0, S_ARMB7 }, // S_ARMB6
+	{SPR_ARMB, FF_FULLBRIGHT| 6, 3, {NULL}, 1, 0, S_ARMB8 }, // S_ARMB7
+	{SPR_ARMB, FF_FULLBRIGHT| 7, 3, {NULL}, 1, 0, S_ARMB9 }, // S_ARMB8
+	{SPR_ARMB, FF_FULLBRIGHT| 8, 3, {NULL}, 1, 0, S_ARMB10}, // S_ARMB9
+	{SPR_ARMB, FF_FULLBRIGHT| 9, 3, {NULL}, 1, 0, S_ARMB11}, // S_ARMB10
+	{SPR_ARMB, FF_FULLBRIGHT|10, 3, {NULL}, 1, 0, S_ARMB12}, // S_ARMB11
+	{SPR_ARMB, FF_FULLBRIGHT|11, 3, {NULL}, 1, 0, S_ARMB13}, // S_ARMB12
+	{SPR_ARMB, FF_FULLBRIGHT|12, 3, {NULL}, 1, 0, S_ARMB14}, // S_ARMB13
+	{SPR_ARMB, FF_FULLBRIGHT|13, 3, {NULL}, 1, 0, S_ARMB15}, // S_ARMB14
+	{SPR_ARMB, FF_FULLBRIGHT|14, 3, {NULL}, 1, 0, S_ARMB16}, // S_ARMB15
+	{SPR_ARMB, FF_FULLBRIGHT|15, 3, {NULL}, 1, 0, S_ARMB1 }, // S_ARMB16
+
+	{SPR_WIND, FF_TRANS70  , 2, {NULL}, 0, 0, S_WIND2}, // S_WIND1
+	{SPR_WIND, FF_TRANS70|1, 2, {NULL}, 0, 0, S_WIND3}, // S_WIND2
+	{SPR_WIND, FF_TRANS70|2, 2, {NULL}, 0, 0, S_WIND4}, // S_WIND3
+	{SPR_WIND, FF_TRANS70|3, 2, {NULL}, 0, 0, S_WIND5}, // S_WIND4
+	{SPR_WIND, FF_TRANS70|4, 2, {NULL}, 0, 0, S_WIND6}, // S_WIND5
+	{SPR_WIND, FF_TRANS70|5, 2, {NULL}, 0, 0, S_WIND7}, // S_WIND6
+	{SPR_WIND, FF_TRANS70|6, 2, {NULL}, 0, 0, S_WIND8}, // S_WIND7
+	{SPR_WIND, FF_TRANS70|7, 2, {NULL}, 0, 0, S_WIND1}, // S_WIND8
+
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40   , 2, {NULL}, 0, 0, S_MAGN2 }, // S_MAGN1
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 1, 2, {NULL}, 0, 0, S_MAGN3 }, // S_MAGN2
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 2, 2, {NULL}, 0, 0, S_MAGN4 }, // S_MAGN3
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 3, 2, {NULL}, 0, 0, S_MAGN5 }, // S_MAGN4
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 4, 2, {NULL}, 0, 0, S_MAGN6 }, // S_MAGN5
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 5, 2, {NULL}, 0, 0, S_MAGN7 }, // S_MAGN6
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 6, 2, {NULL}, 0, 0, S_MAGN8 }, // S_MAGN7
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 7, 2, {NULL}, 0, 0, S_MAGN9 }, // S_MAGN8
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 8, 2, {NULL}, 0, 0, S_MAGN10}, // S_MAGN9
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_MAGN11}, // S_MAGN10
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_MAGN12}, // S_MAGN11
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN12
+
+	{SPR_FORC, FF_TRANS50  , 3, {NULL}, 0, 0, S_FORC2 }, // S_FORC1
+	{SPR_FORC, FF_TRANS50|1, 3, {NULL}, 0, 0, S_FORC3 }, // S_FORC2
+	{SPR_FORC, FF_TRANS50|2, 3, {NULL}, 0, 0, S_FORC4 }, // S_FORC3
+	{SPR_FORC, FF_TRANS50|3, 3, {NULL}, 0, 0, S_FORC5 }, // S_FORC4
+	{SPR_FORC, FF_TRANS50|4, 3, {NULL}, 0, 0, S_FORC6 }, // S_FORC5
+	{SPR_FORC, FF_TRANS50|5, 3, {NULL}, 0, 0, S_FORC7 }, // S_FORC6
+	{SPR_FORC, FF_TRANS50|6, 3, {NULL}, 0, 0, S_FORC8 }, // S_FORC7
+	{SPR_FORC, FF_TRANS50|7, 3, {NULL}, 0, 0, S_FORC9 }, // S_FORC8
+	{SPR_FORC, FF_TRANS50|8, 3, {NULL}, 0, 0, S_FORC10}, // S_FORC9
+	{SPR_FORC, FF_TRANS50|9, 3, {NULL}, 0, 0, S_FORC1 }, // S_FORC10
+
+	{SPR_FORC, FF_TRANS50|10, 3, {NULL}, 0, 0, S_FORC12}, // S_FORC11
+	{SPR_FORC, FF_TRANS50|11, 3, {NULL}, 0, 0, S_FORC13}, // S_FORC12
+	{SPR_FORC, FF_TRANS50|12, 3, {NULL}, 0, 0, S_FORC14}, // S_FORC13
+	{SPR_FORC, FF_TRANS50|13, 3, {NULL}, 0, 0, S_FORC15}, // S_FORC14
+	{SPR_FORC, FF_TRANS50|14, 3, {NULL}, 0, 0, S_FORC16}, // S_FORC15
+	{SPR_FORC, FF_TRANS50|15, 3, {NULL}, 0, 0, S_FORC17}, // S_FORC16
+	{SPR_FORC, FF_TRANS50|16, 3, {NULL}, 0, 0, S_FORC18}, // S_FORC17
+	{SPR_FORC, FF_TRANS50|17, 3, {NULL}, 0, 0, S_FORC19}, // S_FORC18
+	{SPR_FORC, FF_TRANS50|18, 3, {NULL}, 0, 0, S_FORC20}, // S_FORC19
+	{SPR_FORC, FF_TRANS50|19, 3, {NULL}, 0, 0, S_FORC11}, // S_FORC20
+
+	{SPR_ELEM, FF_TRANS50   , 4, {NULL}, 0, 0, S_ELEM2 }, // S_ELEM1
+	{SPR_ELEM, FF_TRANS50| 1, 4, {NULL}, 0, 0, S_ELEM3 }, // S_ELEM2
+	{SPR_ELEM, FF_TRANS50| 2, 4, {NULL}, 0, 0, S_ELEM4 }, // S_ELEM3
+	{SPR_ELEM, FF_TRANS50| 3, 4, {NULL}, 0, 0, S_ELEM5 }, // S_ELEM4
+	{SPR_ELEM, FF_TRANS50| 4, 4, {NULL}, 0, 0, S_ELEM6 }, // S_ELEM5
+	{SPR_ELEM, FF_TRANS50| 5, 4, {NULL}, 0, 0, S_ELEM7 }, // S_ELEM6
+	{SPR_ELEM, FF_TRANS50| 6, 4, {NULL}, 0, 0, S_ELEM8 }, // S_ELEM7
+	{SPR_ELEM, FF_TRANS50| 7, 4, {NULL}, 0, 0, S_ELEM9 }, // S_ELEM8
+	{SPR_ELEM, FF_TRANS50| 8, 4, {NULL}, 0, 0, S_ELEM10}, // S_ELEM9
+	{SPR_ELEM, FF_TRANS50| 9, 4, {NULL}, 0, 0, S_ELEM11}, // S_ELEM10
+	{SPR_ELEM, FF_TRANS50|10, 4, {NULL}, 0, 0, S_ELEM12}, // S_ELEM11
+	{SPR_ELEM, FF_TRANS50|11, 4, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM12
+
+	{SPR_ELEM, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ELEMF2}, // S_ELEMF1
+	{SPR_ELEM, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ELEMF3}, // S_ELEMF2
+	{SPR_ELEM, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ELEMF4}, // S_ELEMF3
+	{SPR_ELEM, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ELEMF5}, // S_ELEMF4
+	{SPR_ELEM, FF_FULLBRIGHT|16, 3, {NULL}, 0, 0, S_ELEMF6}, // S_ELEMF5
+	{SPR_ELEM, FF_FULLBRIGHT|17, 3, {NULL}, 0, 0, S_ELEMF7}, // S_ELEMF6
+	{SPR_ELEM, FF_FULLBRIGHT|18, 3, {NULL}, 0, 0, S_ELEMF8}, // S_ELEMF7
+	{SPR_ELEM, FF_FULLBRIGHT|19, 3, {NULL}, 0, 0, S_ELEMF1}, // S_ELEMF8
+
+	{SPR_PITY, FF_TRANS20  , 1, {NULL}, 0, 0, S_PITY2 }, // S_PITY1
+	{SPR_PITY, FF_TRANS20|1, 1, {NULL}, 0, 0, S_PITY3 }, // S_PITY2
+	{SPR_PITY, FF_TRANS20  , 1, {NULL}, 0, 0, S_PITY4 }, // S_PITY3
+	{SPR_PITY, FF_TRANS20|2, 1, {NULL}, 0, 0, S_PITY5 }, // S_PITY4
+	{SPR_PITY, FF_TRANS20  , 1, {NULL}, 0, 0, S_PITY6 }, // S_PITY5
+	{SPR_PITY, FF_TRANS20|3, 1, {NULL}, 0, 0, S_PITY7 }, // S_PITY6
+	{SPR_PITY, FF_TRANS20  , 1, {NULL}, 0, 0, S_PITY8 }, // S_PITY7
+	{SPR_PITY, FF_TRANS20|4, 1, {NULL}, 0, 0, S_PITY9 }, // S_PITY8
+	{SPR_PITY, FF_TRANS20  , 1, {NULL}, 0, 0, S_PITY10}, // S_PITY9
+	{SPR_PITY, FF_TRANS20|5, 1, {NULL}, 0, 0, S_PITY1 }, // S_PITY10
 
 	// Invincibility Sparkles
 	{SPR_IVSP, 0, 1, {NULL}, 0, 0, S_IVSP2},   // S_IVSP1
@@ -1915,8 +1923,8 @@ state_t states[NUMSTATES] =
 	{SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1},   // S_RDIAG8
 
 	// Rain
-	{SPR_RAIN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
-	{SPR_RAIN, 0, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
+	{SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
+	{SPR_RAIN, FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
 
 	// Snowflake
 	{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1
@@ -1924,61 +1932,61 @@ state_t states[NUMSTATES] =
 	{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW3
 
 	// Water Splish
-	{SPR_SPLH, 0, 2, {NULL}, 0, 0, S_SPLISH2}, // S_SPLISH1
-	{SPR_SPLH, 1, 2, {NULL}, 0, 0, S_SPLISH3}, // S_SPLISH2
-	{SPR_SPLH, 2, 2, {NULL}, 0, 0, S_SPLISH4}, // S_SPLISH3
-	{SPR_SPLH, 3, 2, {NULL}, 0, 0, S_SPLISH5}, // S_SPLISH4
-	{SPR_SPLH, 4, 2, {NULL}, 0, 0, S_SPLISH6}, // S_SPLISH5
-	{SPR_SPLH, 5, 2, {NULL}, 0, 0, S_SPLISH7}, // S_SPLISH6
-	{SPR_SPLH, 6, 2, {NULL}, 0, 0, S_SPLISH8}, // S_SPLISH7
-	{SPR_SPLH, 7, 2, {NULL}, 0, 0, S_SPLISH9}, // S_SPLISH8
-	{SPR_SPLH, 8, 2, {NULL}, 0, 0, S_NULL},    // S_SPLISH9
+	{SPR_SPLH, FF_TRANS50  , 2, {NULL}, 0, 0, S_SPLISH2}, // S_SPLISH1
+	{SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3}, // S_SPLISH2
+	{SPR_SPLH, FF_TRANS50|2, 2, {NULL}, 0, 0, S_SPLISH4}, // S_SPLISH3
+	{SPR_SPLH, FF_TRANS50|3, 2, {NULL}, 0, 0, S_SPLISH5}, // S_SPLISH4
+	{SPR_SPLH, FF_TRANS50|4, 2, {NULL}, 0, 0, S_SPLISH6}, // S_SPLISH5
+	{SPR_SPLH, FF_TRANS50|5, 2, {NULL}, 0, 0, S_SPLISH7}, // S_SPLISH6
+	{SPR_SPLH, FF_TRANS50|6, 2, {NULL}, 0, 0, S_SPLISH8}, // S_SPLISH7
+	{SPR_SPLH, FF_TRANS50|7, 2, {NULL}, 0, 0, S_SPLISH9}, // S_SPLISH8
+	{SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL},    // S_SPLISH9
 
 	// Water Splash
-	{SPR_SPLA, 0, 3, {NULL}, 0, 0, S_SPLASH2},    // S_SPLASH1
-	{SPR_SPLA, 1, 3, {NULL}, 0, 0, S_SPLASH3},    // S_SPLASH2
-	{SPR_SPLA, 2, 3, {NULL}, 0, 0, S_RAINRETURN}, // S_SPLASH3
+	{SPR_SPLA, FF_TRANS50  , 3, {NULL}, 0, 0, S_SPLASH2},    // S_SPLASH1
+	{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3},    // S_SPLASH2
+	{SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN}, // S_SPLASH3
 
 	// Smoke
-	{SPR_SMOK, 0, 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1
-	{SPR_SMOK, 1, 5, {NULL}, 0, 0, S_SMOKE3}, // S_SMOKE2
-	{SPR_SMOK, 2, 6, {NULL}, 0, 0, S_SMOKE4}, // S_SMOKE3
-	{SPR_SMOK, 3, 7, {NULL}, 0, 0, S_SMOKE5}, // S_SMOKE4
-	{SPR_SMOK, 4, 8, {NULL}, 0, 0, S_NULL},   // S_SMOKE5
+	{SPR_SMOK, FF_TRANS50  , 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1
+	{SPR_SMOK, FF_TRANS50|1, 5, {NULL}, 0, 0, S_SMOKE3}, // S_SMOKE2
+	{SPR_SMOK, FF_TRANS50|2, 6, {NULL}, 0, 0, S_SMOKE4}, // S_SMOKE3
+	{SPR_SMOK, FF_TRANS50|3, 7, {NULL}, 0, 0, S_SMOKE5}, // S_SMOKE4
+	{SPR_SMOK, FF_TRANS50|4, 8, {NULL}, 0, 0, S_NULL},   // S_SMOKE5
 
 	// Bubbles
-	{SPR_BUBP, 0, 1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE1},  // S_SMALLBUBBLE
-	{SPR_BUBP, 0, 1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE},   // S_SMALLBUBBLE1
-	{SPR_BUBO, 0, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE1}, // S_MEDIUMBUBBLE
-	{SPR_BUBO, 0, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE},  // S_MEDIUMBUBBLE1
+	{SPR_BUBP, FF_TRANS50, 1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE1},  // S_SMALLBUBBLE
+	{SPR_BUBP, FF_TRANS50, 1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE},   // S_SMALLBUBBLE1
+	{SPR_BUBO, FF_TRANS50, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE1}, // S_MEDIUMBUBBLE
+	{SPR_BUBO, FF_TRANS50, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE},  // S_MEDIUMBUBBLE1
 
 	// Extra Large Bubble (breathable)
-	{SPR_BUBN, FF_FULLBRIGHT, 16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_LARGEBUBBLE
-	{SPR_BUBM, FF_FULLBRIGHT, 16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_EXTRALARGEBUBBLE
+	{SPR_BUBN, FF_TRANS50|FF_FULLBRIGHT, 16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_LARGEBUBBLE
+	{SPR_BUBM, FF_TRANS50|FF_FULLBRIGHT, 16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_EXTRALARGEBUBBLE
 
 	// Extra Large Bubble goes POP!
 	{SPR_POPP, 0, 16, {NULL}, 0, 0, S_NULL}, // S_POP1
 
-	{SPR_TFOG, FF_FULLBRIGHT,    2, {NULL}, 0, 0, S_FOG2},  // S_FOG1
-	{SPR_TFOG, FF_FULLBRIGHT+1,  2, {NULL}, 0, 0, S_FOG3},  // S_FOG2
-	{SPR_TFOG, FF_FULLBRIGHT+2,  2, {NULL}, 0, 0, S_FOG4},  // S_FOG3
-	{SPR_TFOG, FF_FULLBRIGHT+3,  2, {NULL}, 0, 0, S_FOG5},  // S_FOG4
-	{SPR_TFOG, FF_FULLBRIGHT+4,  2, {NULL}, 0, 0, S_FOG6},  // S_FOG5
-	{SPR_TFOG, FF_FULLBRIGHT+5,  2, {NULL}, 0, 0, S_FOG7},  // S_FOG6
-	{SPR_TFOG, FF_FULLBRIGHT+6,  2, {NULL}, 0, 0, S_FOG8},  // S_FOG7
-	{SPR_TFOG, FF_FULLBRIGHT+7,  2, {NULL}, 0, 0, S_FOG9},  // S_FOG8
-	{SPR_TFOG, FF_FULLBRIGHT+8,  2, {NULL}, 0, 0, S_FOG10}, // S_FOG9
-	{SPR_TFOG, FF_FULLBRIGHT+9,  2, {NULL}, 0, 0, S_FOG11}, // S_FOG10
-	{SPR_TFOG, FF_FULLBRIGHT+10, 2, {NULL}, 0, 0, S_FOG12}, // S_FOG11
-	{SPR_TFOG, FF_FULLBRIGHT+11, 2, {NULL}, 0, 0, S_FOG13}, // S_FOG12
-	{SPR_TFOG, FF_FULLBRIGHT+12, 2, {NULL}, 0, 0, S_FOG14}, // S_FOG13
-	{SPR_TFOG, FF_FULLBRIGHT+13, 2, {NULL}, 0, 0, S_NULL},  // S_FOG14
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50,    2, {NULL}, 0, 0, S_FOG2},  // S_FOG1
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|1,  2, {NULL}, 0, 0, S_FOG3},  // S_FOG2
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|2,  2, {NULL}, 0, 0, S_FOG4},  // S_FOG3
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|3,  2, {NULL}, 0, 0, S_FOG5},  // S_FOG4
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|4,  2, {NULL}, 0, 0, S_FOG6},  // S_FOG5
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|5,  2, {NULL}, 0, 0, S_FOG7},  // S_FOG6
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|6,  2, {NULL}, 0, 0, S_FOG8},  // S_FOG7
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|7,  2, {NULL}, 0, 0, S_FOG9},  // S_FOG8
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|8,  2, {NULL}, 0, 0, S_FOG10}, // S_FOG9
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|9,  2, {NULL}, 0, 0, S_FOG11}, // S_FOG10
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|10, 2, {NULL}, 0, 0, S_FOG12}, // S_FOG11
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|11, 2, {NULL}, 0, 0, S_FOG13}, // S_FOG12
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|12, 2, {NULL}, 0, 0, S_FOG14}, // S_FOG13
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|13, 2, {NULL}, 0, 0, S_NULL},  // S_FOG14
 
 	// Flower Seed
 	{SPR_SEED, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_SEED
 
 	// Particle sprite
-	{SPR_PRTL, FF_FULLBRIGHT, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE
+	{SPR_PRTL, FF_FULLBRIGHT|FF_TRANS70, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE
 	{SPR_NULL,     0,         1, {A_ParticleSpawn}, 0, 0, S_PARTICLEGEN}, // S_PARTICLEGEN
 
 	{SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRA  - 100
@@ -2011,12 +2019,12 @@ state_t states[NUMSTATES] =
 
 	// Red Rings (thrown)
 	{SPR_RRNG, FF_FULLBRIGHT,   1, {A_ThrownRing}, 0, 0, S_RRNG2}, // S_RRNG1
-	{SPR_RRNG, FF_FULLBRIGHT+1, 1, {A_ThrownRing}, 0, 0, S_RRNG3}, // S_RRNG2
-	{SPR_RRNG, FF_FULLBRIGHT+2, 1, {A_ThrownRing}, 0, 0, S_RRNG4}, // S_RRNG3
-	{SPR_RRNG, FF_FULLBRIGHT+3, 1, {A_ThrownRing}, 0, 0, S_RRNG5}, // S_RRNG4
-	{SPR_RRNG, FF_FULLBRIGHT+4, 1, {A_ThrownRing}, 0, 0, S_RRNG6}, // S_RRNG5
-	{SPR_RRNG, FF_FULLBRIGHT+5, 1, {A_ThrownRing}, 0, 0, S_RRNG7}, // S_RRNG6
-	{SPR_RRNG, FF_FULLBRIGHT+6, 1, {A_ThrownRing}, 0, 0, S_RRNG1}, // S_RRNG7
+	{SPR_RRNG, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_RRNG3}, // S_RRNG2
+	{SPR_RRNG, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_RRNG4}, // S_RRNG3
+	{SPR_RRNG, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_RRNG5}, // S_RRNG4
+	{SPR_RRNG, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_RRNG6}, // S_RRNG5
+	{SPR_RRNG, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_RRNG7}, // S_RRNG6
+	{SPR_RRNG, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_RRNG1}, // S_RRNG7
 
 	// Bounce Ring
 	{SPR_RNGB, 0, 1, {NULL}, 0, 0, S_BOUNCERING2},   // S_BOUNCERING1
@@ -2499,14 +2507,14 @@ state_t states[NUMSTATES] =
 
 	// Coin
 	{SPR_COIN, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_COIN2}, // S_COIN1
-	{SPR_COIN, FF_FULLBRIGHT+1, 5, {NULL}, 0, 0, S_COIN3}, // S_COIN2
-	{SPR_COIN, FF_FULLBRIGHT+2, 5, {NULL}, 0, 0, S_COIN1}, // S_COIN3
+	{SPR_COIN, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COIN3}, // S_COIN2
+	{SPR_COIN, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COIN1}, // S_COIN3
 
 	// Coin Sparkle
 	{SPR_CPRK, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_COINSPARKLE2}, // S_COINSPARKLE1
-	{SPR_CPRK, FF_FULLBRIGHT+1, 5, {NULL}, 0, 0, S_COINSPARKLE3}, // S_COINSPARKLE2
-	{SPR_CPRK, FF_FULLBRIGHT+2, 5, {NULL}, 0, 0, S_COINSPARKLE4}, // S_COINSPARKLE3
-	{SPR_CPRK, FF_FULLBRIGHT+3, 5, {NULL}, 0, 0, S_NULL},         // S_COINSPARKLE4
+	{SPR_CPRK, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COINSPARKLE3}, // S_COINSPARKLE2
+	{SPR_CPRK, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COINSPARKLE4}, // S_COINSPARKLE3
+	{SPR_CPRK, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL},         // S_COINSPARKLE4
 
 	// Goomba
 	{SPR_GOOM, 0, 6, {A_Look}, 0, 0, S_GOOMBA1B}, // S_GOOMBA1
@@ -2542,12 +2550,12 @@ state_t states[NUMSTATES] =
 
 	// Thrown Mario Fireball
 	{SPR_FBLL, FF_FULLBRIGHT,   3, {NULL}, 0, 0, S_FIREBALL2},    // S_FIREBALL1
-	{SPR_FBLL, FF_FULLBRIGHT+1, 3, {NULL}, 0, 0, S_FIREBALL3},    // S_FIREBALL2
-	{SPR_FBLL, FF_FULLBRIGHT+2, 3, {NULL}, 0, 0, S_FIREBALL4},    // S_FIREBALL3
-	{SPR_FBLL, FF_FULLBRIGHT+3, 3, {NULL}, 0, 0, S_FIREBALL1},    // S_FIREBALL4
-	{SPR_FBLL, FF_FULLBRIGHT+4, 3, {NULL}, 0, 0, S_FIREBALLEXP2}, // S_FIREBALLEXP1
-	{SPR_FBLL, FF_FULLBRIGHT+5, 3, {NULL}, 0, 0, S_FIREBALLEXP3}, // S_FIREBALLEXP2
-	{SPR_FBLL, FF_FULLBRIGHT+6, 3, {NULL}, 0, 0, S_NULL},         // S_FIREBALLEXP3
+	{SPR_FBLL, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_FIREBALL3},    // S_FIREBALL2
+	{SPR_FBLL, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_FIREBALL4},    // S_FIREBALL3
+	{SPR_FBLL, FF_FULLBRIGHT|3, 3, {NULL}, 0, 0, S_FIREBALL1},    // S_FIREBALL4
+	{SPR_FBLL, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_FIREBALLEXP2}, // S_FIREBALLEXP1
+	{SPR_FBLL, FF_FULLBRIGHT|5, 3, {NULL}, 0, 0, S_FIREBALLEXP3}, // S_FIREBALLEXP2
+	{SPR_FBLL, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL},         // S_FIREBALLEXP3
 
 	// Turtle Shell
 	{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL},  // S_SHELL
@@ -2558,11 +2566,11 @@ state_t states[NUMSTATES] =
 
 	// Puma (Mario fireball)
 	{SPR_PUMA, FF_FULLBRIGHT,   3, {A_FishJump}, 0, 0, S_PUMA2}, // S_PUMA1
-	{SPR_PUMA, FF_FULLBRIGHT+1, 3, {A_FishJump}, 0, 0, S_PUMA3}, // S_PUMA2
-	{SPR_PUMA, FF_FULLBRIGHT+2, 3, {A_FishJump}, 0, 0, S_PUMA1}, // S_PUMA3
-	{SPR_PUMA, FF_FULLBRIGHT+3, 3, {A_FishJump}, 0, 0, S_PUMA5}, // S_PUMA4
-	{SPR_PUMA, FF_FULLBRIGHT+4, 3, {A_FishJump}, 0, 0, S_PUMA6}, // S_PUMA5
-	{SPR_PUMA, FF_FULLBRIGHT+5, 3, {A_FishJump}, 0, 0, S_PUMA4}, // S_PUMA6
+	{SPR_PUMA, FF_FULLBRIGHT|1, 3, {A_FishJump}, 0, 0, S_PUMA3}, // S_PUMA2
+	{SPR_PUMA, FF_FULLBRIGHT|2, 3, {A_FishJump}, 0, 0, S_PUMA1}, // S_PUMA3
+	{SPR_PUMA, FF_FULLBRIGHT|3, 3, {A_FishJump}, 0, 0, S_PUMA5}, // S_PUMA4
+	{SPR_PUMA, FF_FULLBRIGHT|4, 3, {A_FishJump}, 0, 0, S_PUMA6}, // S_PUMA5
+	{SPR_PUMA, FF_FULLBRIGHT|5, 3, {A_FishJump}, 0, 0, S_PUMA4}, // S_PUMA6
 
 	// Hammer
 	{SPR_HAMM, 0, 3, {NULL}, 0, 0, S_HAMMER2}, // S_HAMMER1
@@ -2707,15 +2715,15 @@ state_t states[NUMSTATES] =
 
 	// Nights Sparkle
 	{SPR_NSPK, FF_FULLBRIGHT, 140, {NULL}, 0, 0, S_NIGHTSPARKLE2},   // S_NIGHTSPARKLE1
-	{SPR_NSPK, FF_FULLBRIGHT+1, 7, {NULL}, 0, 0, S_NIGHTSPARKLE3},   // S_NIGHTSPARKLE2
-	{SPR_NSPK, FF_FULLBRIGHT+2, 7, {NULL}, 0, 0, S_NIGHTSPARKLE4},   // S_NIGHTSPARKLE3
-	{SPR_NSPK, FF_FULLBRIGHT+3, 7, {NULL}, 0, 0, S_NULL},            // S_NIGHTSPARKLE4
+	{SPR_NSPK, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_NIGHTSPARKLE3},   // S_NIGHTSPARKLE2
+	{SPR_NSPK, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_NIGHTSPARKLE4},   // S_NIGHTSPARKLE3
+	{SPR_NSPK, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_NULL},            // S_NIGHTSPARKLE4
 
 	// Red Sparkle
-	{SPR_NSPK, FF_FULLBRIGHT+4, 140, {NULL}, 0, 0, S_NIGHTSPARKLESUPER2}, // S_NIGHTSPARKLESUPER1
-	{SPR_NSPK, FF_FULLBRIGHT+5, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER3},   // S_NIGHTSPARKLESUPER2
-	{SPR_NSPK, FF_FULLBRIGHT+6, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER4},   // S_NIGHTSPARKLESUPER3
-	{SPR_NSPK, FF_FULLBRIGHT+7, 7, {NULL}, 0, 0, S_NULL},                 // S_NIGHTSPARKLESUPER4
+	{SPR_NSPK, FF_FULLBRIGHT|4, 140, {NULL}, 0, 0, S_NIGHTSPARKLESUPER2}, // S_NIGHTSPARKLESUPER1
+	{SPR_NSPK, FF_FULLBRIGHT|5, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER3},   // S_NIGHTSPARKLESUPER2
+	{SPR_NSPK, FF_FULLBRIGHT|6, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER4},   // S_NIGHTSPARKLESUPER3
+	{SPR_NSPK, FF_FULLBRIGHT|7, 7, {NULL}, 0, 0, S_NULL},                 // S_NIGHTSPARKLESUPER4
 
 	// Paraloop helper -- THIS IS WHAT DETERMINES THE TIMER NOW
 	{SPR_NULL, 0, 160, {NULL}, 0, 0, S_NULL}, // S_NIGHTSLOOPHELPER
@@ -2739,25 +2747,25 @@ state_t states[NUMSTATES] =
 	{SPR_HOOP, 2, -1, {NULL}, 0, 0, S_NULL}, // S_HOOP_XMASB
 
 	{SPR_NSCR, FF_FULLBRIGHT,    -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE10
-	{SPR_NSCR, FF_FULLBRIGHT+1,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE20
-	{SPR_NSCR, FF_FULLBRIGHT+2,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE30
-	{SPR_NSCR, FF_FULLBRIGHT+3,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE40
-	{SPR_NSCR, FF_FULLBRIGHT+4,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE50
-	{SPR_NSCR, FF_FULLBRIGHT+5,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE60
-	{SPR_NSCR, FF_FULLBRIGHT+6,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE70
-	{SPR_NSCR, FF_FULLBRIGHT+7,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE80
-	{SPR_NSCR, FF_FULLBRIGHT+8,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90
-	{SPR_NSCR, FF_FULLBRIGHT+9,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100
-	{SPR_NSCR, FF_FULLBRIGHT+10, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE10_2
-	{SPR_NSCR, FF_FULLBRIGHT+11, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE20_2
-	{SPR_NSCR, FF_FULLBRIGHT+12, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE30_2
-	{SPR_NSCR, FF_FULLBRIGHT+13, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE40_2
-	{SPR_NSCR, FF_FULLBRIGHT+14, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE50_2
-	{SPR_NSCR, FF_FULLBRIGHT+15, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE60_2
-	{SPR_NSCR, FF_FULLBRIGHT+16, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE70_2
-	{SPR_NSCR, FF_FULLBRIGHT+17, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE80_2
-	{SPR_NSCR, FF_FULLBRIGHT+18, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90_2
-	{SPR_NSCR, FF_FULLBRIGHT+19, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100_2
+	{SPR_NSCR, FF_FULLBRIGHT|1,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE20
+	{SPR_NSCR, FF_FULLBRIGHT|2,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE30
+	{SPR_NSCR, FF_FULLBRIGHT|3,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE40
+	{SPR_NSCR, FF_FULLBRIGHT|4,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE50
+	{SPR_NSCR, FF_FULLBRIGHT|5,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE60
+	{SPR_NSCR, FF_FULLBRIGHT|6,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE70
+	{SPR_NSCR, FF_FULLBRIGHT|7,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE80
+	{SPR_NSCR, FF_FULLBRIGHT|8,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90
+	{SPR_NSCR, FF_FULLBRIGHT|9,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100
+	{SPR_NSCR, FF_FULLBRIGHT|10, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE10_2
+	{SPR_NSCR, FF_FULLBRIGHT|11, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE20_2
+	{SPR_NSCR, FF_FULLBRIGHT|12, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE30_2
+	{SPR_NSCR, FF_FULLBRIGHT|13, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE40_2
+	{SPR_NSCR, FF_FULLBRIGHT|14, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE50_2
+	{SPR_NSCR, FF_FULLBRIGHT|15, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE60_2
+	{SPR_NSCR, FF_FULLBRIGHT|16, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE70_2
+	{SPR_NSCR, FF_FULLBRIGHT|17, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE80_2
+	{SPR_NSCR, FF_FULLBRIGHT|18, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90_2
+	{SPR_NSCR, FF_FULLBRIGHT|19, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100_2
 
 	{SPR_NWNG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSWING
 	{SPR_NWNG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSWING_XMAS
@@ -2778,21 +2786,21 @@ state_t states[NUMSTATES] =
 
 	// Orbiting Chaos Emeralds for NiGHTS
 	{SPR_CEMG, FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1
-	{SPR_CEMG, FF_FULLBRIGHT+1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2
-	{SPR_CEMG, FF_FULLBRIGHT+2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3
-	{SPR_CEMG, FF_FULLBRIGHT+3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4
-	{SPR_CEMG, FF_FULLBRIGHT+4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5
-	{SPR_CEMG, FF_FULLBRIGHT+5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6
-	{SPR_CEMG, FF_FULLBRIGHT+6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7
-	{SPR_CEMG, FF_FULLBRIGHT+7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8
-	{SPR_CEMG, FF_FULLBRIGHT+8, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM9
-	{SPR_CEMG, FF_FULLBRIGHT+9, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM10
-	{SPR_CEMG, FF_FULLBRIGHT+10, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM11
-	{SPR_CEMG, FF_FULLBRIGHT+11, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM12
-	{SPR_CEMG, FF_FULLBRIGHT+12, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM13
-	{SPR_CEMG, FF_FULLBRIGHT+13, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM14
-	{SPR_CEMG, FF_FULLBRIGHT+14, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM15
-	{SPR_CEMG, FF_FULLBRIGHT+15, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM16
+	{SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2
+	{SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3
+	{SPR_CEMG, FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4
+	{SPR_CEMG, FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5
+	{SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6
+	{SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7
+	{SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8
+	{SPR_CEMG, FF_FULLBRIGHT|8, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM9
+	{SPR_CEMG, FF_FULLBRIGHT|9, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM10
+	{SPR_CEMG, FF_FULLBRIGHT|10, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM11
+	{SPR_CEMG, FF_FULLBRIGHT|11, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM12
+	{SPR_CEMG, FF_FULLBRIGHT|12, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM13
+	{SPR_CEMG, FF_FULLBRIGHT|13, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM14
+	{SPR_CEMG, FF_FULLBRIGHT|14, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM15
+	{SPR_CEMG, FF_FULLBRIGHT|15, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM16
 
 	// Flicky helper for NiGHTS
 	{SPR_BIRD, 0, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER2}, // S_NIGHTOPIANHELPER1
@@ -2818,22 +2826,22 @@ state_t states[NUMSTATES] =
 	{SPR_SUPT, 8,    16, {NULL}, 0, 0, S_NIGHTSDRONE1}, // S_SUPERTRANS9
 
 	// Spark
-	{SPR_SPRK, 0, 1, {NULL}, 0, 0, S_SPRK2},  // S_SPRK1
-	{SPR_SPRK, 1, 1, {NULL}, 0, 0, S_SPRK3},  // S_SPRK2
-	{SPR_SPRK, 2, 1, {NULL}, 0, 0, S_SPRK4},  // S_SPRK3
-	{SPR_SPRK, 3, 1, {NULL}, 0, 0, S_SPRK5},  // S_SPRK4
-	{SPR_SPRK, 0, 1, {NULL}, 0, 0, S_SPRK6},  // S_SPRK5
-	{SPR_SPRK, 1, 1, {NULL}, 0, 0, S_SPRK7},  // S_SPRK6
-	{SPR_SPRK, 2, 1, {NULL}, 0, 0, S_SPRK8},  // S_SPRK7
-	{SPR_SPRK, 3, 1, {NULL}, 0, 0, S_SPRK9},  // S_SPRK8
-	{SPR_SPRK, 0, 1, {NULL}, 0, 0, S_SPRK10}, // S_SPRK9
-	{SPR_SPRK, 1, 1, {NULL}, 0, 0, S_SPRK11}, // S_SPRK10
-	{SPR_SPRK, 2, 1, {NULL}, 0, 0, S_SPRK12}, // S_SPRK11
-	{SPR_SPRK, 3, 1, {NULL}, 0, 0, S_SPRK13}, // S_SPRK12
-	{SPR_SPRK, 0, 1, {NULL}, 0, 0, S_SPRK14}, // S_SPRK13
-	{SPR_SPRK, 1, 1, {NULL}, 0, 0, S_SPRK15}, // S_SPRK14
-	{SPR_SPRK, 2, 1, {NULL}, 0, 0, S_SPRK16}, // S_SPRK15
-	{SPR_SPRK, 3, 1, {NULL}, 0, 0, S_NULL},   // S_SPRK16
+	{SPR_SPRK, FF_TRANS40  , 1, {NULL}, 0, 0, S_SPRK2},  // S_SPRK1
+	{SPR_SPRK, FF_TRANS50|1, 1, {NULL}, 0, 0, S_SPRK3},  // S_SPRK2
+	{SPR_SPRK, FF_TRANS50|2, 1, {NULL}, 0, 0, S_SPRK4},  // S_SPRK3
+	{SPR_SPRK, FF_TRANS50|3, 1, {NULL}, 0, 0, S_SPRK5},  // S_SPRK4
+	{SPR_SPRK, FF_TRANS60  , 1, {NULL}, 0, 0, S_SPRK6},  // S_SPRK5
+	{SPR_SPRK, FF_TRANS60|1, 1, {NULL}, 0, 0, S_SPRK7},  // S_SPRK6
+	{SPR_SPRK, FF_TRANS60|2, 1, {NULL}, 0, 0, S_SPRK8},  // S_SPRK7
+	{SPR_SPRK, FF_TRANS70|3, 1, {NULL}, 0, 0, S_SPRK9},  // S_SPRK8
+	{SPR_SPRK, FF_TRANS70  , 1, {NULL}, 0, 0, S_SPRK10}, // S_SPRK9
+	{SPR_SPRK, FF_TRANS70|1, 1, {NULL}, 0, 0, S_SPRK11}, // S_SPRK10
+	{SPR_SPRK, FF_TRANS80|2, 1, {NULL}, 0, 0, S_SPRK12}, // S_SPRK11
+	{SPR_SPRK, FF_TRANS80|3, 1, {NULL}, 0, 0, S_SPRK13}, // S_SPRK12
+	{SPR_SPRK, FF_TRANS80  , 1, {NULL}, 0, 0, S_SPRK14}, // S_SPRK13
+	{SPR_SPRK, FF_TRANS90|1, 1, {NULL}, 0, 0, S_SPRK15}, // S_SPRK14
+	{SPR_SPRK, FF_TRANS90|2, 1, {NULL}, 0, 0, S_SPRK16}, // S_SPRK15
+	{SPR_SPRK, FF_TRANS90|3, 1, {NULL}, 0, 0, S_NULL},   // S_SPRK16
 
 	// Robot Explosion
 	{SPR_BOM1, 0, 1, {A_Scream}, 0, 0, S_XPLD2}, // S_XPLD1
@@ -7367,7 +7375,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_DEMONFIRE
 		-1,             // doomednum
-		S_DEMONFIRE,    // spawnstate
+		S_DEMONFIRE1,   // spawnstate
 		1,              // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -12940,33 +12948,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_CHAOSSPAWNER
-		750,            // doomednum
-		S_INVISIBLE,    // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		1,              // speed
-		8*FRACUNIT,     // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		4,              // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY, // flags
-		S_NULL          // raisestate
-	},
-
 	{           // MT_TELEPORTMAN
 		751,            // doomednum
 		S_INVISIBLE,    // spawnstate
diff --git a/src/info.h b/src/info.h
index bc9b7f8fb0827bf4e83aeaa4183804f30110810c..0c73281df34d7061803ac16f0aa23cd0d0c70dab 100644
--- a/src/info.h
+++ b/src/info.h
@@ -355,6 +355,7 @@ typedef enum sprite
 	SPR_TRLS,
 	SPR_CBLL, // Cannonball
 	SPR_AROW, // Arrow
+	SPR_CFIR, // Colored fire of various sorts
 
 	// Greenflower Scenery
 	SPR_FWR1,
@@ -1907,7 +1908,12 @@ typedef enum state
 	S_ARROWDOWN,
 
 	// Trapgoyle Demon fire
-	S_DEMONFIRE,
+	S_DEMONFIRE1,
+	S_DEMONFIRE2,
+	S_DEMONFIRE3,
+	S_DEMONFIRE4,
+	S_DEMONFIRE5,
+	S_DEMONFIRE6,
 
 	S_GFZFLOWERA,
 	S_GFZFLOWERA2,
@@ -3934,7 +3940,6 @@ typedef enum mobj_type
 	MT_NIGHTOPIANHELPER, // the actual helper object that orbits you
 
 	// Utility Objects
-	MT_CHAOSSPAWNER,
 	MT_TELEPORTMAN,
 	MT_ALTVIEWMAN,
 	MT_CRUMBLEOBJ, // Sound generator for crumbling platform
diff --git a/src/m_menu.c b/src/m_menu.c
index b8be38e825dc6816c487e4f7a0278ab46719df56..06aaac0ef0d7629d9e8ea572c04b089b87a63a48 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -387,9 +387,6 @@ CV_PossibleValue_t gametype_cons_t[] =
 	{GT_HIDEANDSEEK, "Hide and Seek"},
 
 	{GT_CTF, "CTF"},
-#ifdef CHAOSISNOTDEADYET
-	{GT_CHAOS, "Chaos"},
-#endif
 	{0, NULL}
 };
 consvar_t cv_newgametype = {"newgametype", "Co-op", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL};
@@ -1129,7 +1126,9 @@ static menuitem_t OP_MouseOptionsMenu[] =
 	{IT_STRING | IT_CVAR, NULL, "Mouse Move",       &cv_mousemove,        40},
 	{IT_STRING | IT_CVAR, NULL, "Invert Mouse",     &cv_invertmouse,      50},
 	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
-	                      NULL, "Mouse Speed",      &cv_mousesens,        60},
+	                      NULL, "Mouse X Speed",    &cv_mousesens,        60},
+	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
+	                      NULL, "Mouse Y Speed",    &cv_mouseysens,        70},
 };
 
 static menuitem_t OP_Mouse2OptionsMenu[] =
@@ -1139,9 +1138,11 @@ static menuitem_t OP_Mouse2OptionsMenu[] =
 	                                                &cv_mouse2port,       20},
 	{IT_STRING | IT_CVAR, NULL, "Always MouseLook", &cv_alwaysfreelook2,  30},
 	{IT_STRING | IT_CVAR, NULL, "Mouse Move",       &cv_mousemove2,       40},
-	{IT_STRING | IT_CVAR, NULL, "Invert Mouse",    &cv_invertmouse2,      50},
+	{IT_STRING | IT_CVAR, NULL, "Invert Mouse",     &cv_invertmouse2,     50},
 	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
-	                      NULL, "Mouse Speed",     &cv_mousesens2,        60},
+	                      NULL, "Mouse X Speed",    &cv_mousesens2,       60},
+	{IT_STRING | IT_CVAR | IT_CV_SLIDER,
+	                      NULL, "Mouse Y Speed",    &cv_mouseysens2,      70},
 };
 
 static menuitem_t OP_VideoOptionsMenu[] =
@@ -1901,9 +1902,6 @@ static void Newgametype_OnChange(void)
 			(cv_newgametype.value == GT_COMPETITION && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_COMPETITION)) ||
 			(cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) ||
 			((cv_newgametype.value == GT_MATCH || cv_newgametype.value == GT_TEAMMATCH) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_MATCH)) ||
-#ifdef CHAOSISNOTDEADYET
-			(cv_newgametype.value == GT_CHAOS && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_CHAOS)) ||
-#endif
 			((cv_newgametype.value == GT_TAG || cv_newgametype.value == GT_HIDEANDSEEK) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_TAG)) ||
 			(cv_newgametype.value == GT_CTF && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_CTF)))
 		{
@@ -3468,11 +3466,6 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
 			if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
 				return true;
 
-#ifdef CHAOSISNOTDEADYET
-			if (gt == GT_CHAOS && (mapheaderinfo[mapnum]->typeoflevel & TOL_CHAOS))
-				return true;
-#endif
-
 			return false;
 
 		case LLM_LEVELSELECT:
diff --git a/src/m_misc.c b/src/m_misc.c
index 73d17c00d8e43e95b01802f314b9b757ecf6efed..57b8c4585166904d7f5ae2e6adb418d79ed10625 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -50,9 +50,11 @@
 #ifdef HAVE_SDL
 #include "sdl/hwsym_sdl.h"
 #ifdef __linux__
+#ifndef _LARGEFILE64_SOURCE
 typedef off_t off64_t;
 #endif
 #endif
+#endif
 
 #if defined (_WIN32)
 #define PRIdS "Iu"
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 54e151123b041237a3bc38d78b12cb2d6ed02f41..18a4ec5ff415be7bee7f5b828fca47ece86ac247 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -2715,14 +2715,6 @@ void A_BossDeath(mobj_t *mo)
 	P_LinedefExecute(LE_BOSSDEAD, mo, NULL);
 	mo->health = 0;
 
-#ifdef CHAOSISNOTDEADYET
-	if (mo->flags2 & MF2_CHAOSBOSS)
-	{
-		P_RemoveMobj(mo);
-		return;
-	}
-#endif
-
 	// Boss is dead (but not necessarily fleeing...)
 	// Lua may use this to ignore bosses after they start fleeing
 	mo->flags2 |= MF2_BOSSDEAD;
@@ -5635,10 +5627,11 @@ void A_MixUp(mobj_t *actor)
 //
 void A_RecyclePowers(mobj_t *actor)
 {
-#ifdef WEIGHTEDRECYCLER
 	INT32 i, j, k, numplayers = 0;
 
+#ifdef WEIGHTEDRECYCLER
 	UINT8 beneficiary = 255;
+#endif
 	UINT8 playerslist[MAXPLAYERS];
 	UINT8 postscramble[MAXPLAYERS];
 
@@ -5651,6 +5644,11 @@ void A_RecyclePowers(mobj_t *actor)
 		return;
 #endif
 
+#if !defined(WEIGHTEDRECYCLER) && !defined(HAVE_BLUA)
+	// actor is used in all scenarios but this one, funny enough
+	(void)actor;
+#endif
+
 	if (!multiplayer)
 		return;
 
@@ -5665,9 +5663,11 @@ void A_RecyclePowers(mobj_t *actor)
 			numplayers++;
 			postscramble[j] = playerslist[j] = (UINT8)i;
 
+#ifdef WEIGHTEDRECYCLER
 			// The guy who started the recycle gets the best result
 			if (actor && actor->target && actor->target->player && &players[i] == actor->target->player)
 				beneficiary = (UINT8)i;
+#endif
 
 			// Save powers
 			for (k = 0; k < NUMPOWERS; k++)
@@ -5684,6 +5684,13 @@ void A_RecyclePowers(mobj_t *actor)
 		return; //nobody to touch!
 
 	//shuffle the post scramble list, whee!
+	// hardcoded 0-1 to 1-0 for two players
+	if (numplayers == 2)
+	{
+		postscramble[0] = playerslist[1];
+		postscramble[1] = playerslist[0];
+	}
+	else
 	for (j = 0; j < numplayers; j++)
 	{
 		UINT8 tempint;
@@ -5694,6 +5701,7 @@ void A_RecyclePowers(mobj_t *actor)
 		postscramble[i] = tempint;
 	}
 
+#ifdef WEIGHTEDRECYCLER
 	//the joys of qsort...
 	if (beneficiary != 255) {
 		qsort(playerslist, numplayers, sizeof(UINT8), P_RecycleCompare);
@@ -5710,6 +5718,7 @@ void A_RecyclePowers(mobj_t *actor)
 			}
 		}
 	}
+#endif
 
 	// now assign!
 	for (i = 0; i < numplayers; i++)
@@ -5737,137 +5746,6 @@ void A_RecyclePowers(mobj_t *actor)
 			P_RestoreMusic(&players[recv_pl]);
 		P_FlashPal(&players[recv_pl], PAL_RECYCLE, 10);
 	}
-#else
-	INT32 i, numplayers = 0;
-
-#ifdef HAVE_BLUA
-	if (LUA_CallAction("A_RecyclePowers", actor))
-		return;
-#endif
-	if (!multiplayer)
-		return;
-
-	numplayers = 0;
-
-	// Count the number of players in the game
-	for (i = 0; i < MAXPLAYERS; i++)
-		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
-			&& !players[i].exiting && !players[i].powers[pw_super] && !((netgame || multiplayer) && players[i].spectator))
-			numplayers++;
-
-	if (numplayers <= 1)
-		return; //nobody to touch!
-
-	else if (numplayers == 2) //simple swap is all that's needed
-	{
-		UINT16 temp[NUMPOWERS];
-		INT32 weapons;
-		INT32 weaponheld;
-
-		INT32 one = -1, two = 0; // default value 0 to make the compiler shut up
-
-		for (i = 0; i < MAXPLAYERS; i++)
-			if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
-				&& !players[i].exiting && !players[i].powers[pw_super] && !((netgame || multiplayer) && players[i].spectator))
-			{
-				if (one == -1)
-					one = i;
-				else
-					two = i;
-			}
-		for (i = 0; i < NUMPOWERS; i++)
-		{
-			if (i == pw_flashing || i == pw_underwater || i == pw_spacetime
-			    || i == pw_tailsfly || i == pw_extralife || i == pw_super || i == pw_nocontrol)
-				continue;
-			temp[i] = players[one].powers[i];
-			players[one].powers[i] = players[two].powers[i];
-			players[two].powers[i] = temp[i];
-		}
-		//1.1: weapons need to be swapped too
-		weapons = players[one].ringweapons;
-		players[one].ringweapons = players[two].ringweapons;
-		players[two].ringweapons = weapons;
-
-		weaponheld = players[one].currentweapon;
-		players[one].currentweapon = players[two].currentweapon;
-		players[two].currentweapon = weaponheld;
-
-		P_SpawnShieldOrb(players[one].mo->player);
-		P_SpawnShieldOrb(players[two].mo->player);
-		P_FlashPal(&players[one], PAL_RECYCLE, 10);
-		P_FlashPal(&players[two], PAL_RECYCLE, 10);
-		//piece o' cake, eh?
-	}
-	else
-	{
-		//well, the cake is a LIE!
-		UINT16 temp[MAXPLAYERS][NUMPOWERS];
-		INT32 weapons[MAXPLAYERS];
-		INT32 weaponheld[MAXPLAYERS];
-		INT32 counter = 0, j = 0, prandom = 0, recyclefrom = 0;
-
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (playeringame[i] && players[i].playerstate == PST_LIVE
-				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super]
-				&& !((netgame || multiplayer) && players[i].spectator))
-			{
-				for (j = 0; j < NUMPOWERS; j++)
-					temp[counter][j] = players[i].powers[j];
-				//1.1: ring weapons too
-				weapons[counter] = players[i].ringweapons;
-				weaponheld[counter] = players[i].currentweapon;
-				counter++;
-			}
-		}
-		counter = 0;
-
-		// Mix them up!
-		for (;;)
-		{
-			if (counter > 255) // fail-safe to avoid endless loop
-				break;
-			prandom = P_Random();
-			prandom %= numplayers; // I love modular arithmetic, don't you?
-			if (prandom) // Make sure it's not a useless mix
-				break;
-			counter++;
-		}
-
-		counter = 0;
-
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (playeringame[i] && players[i].playerstate == PST_LIVE
-				&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super]
-				&& !((netgame || multiplayer) && players[i].spectator))
-			{
-				recyclefrom = (counter + prandom) % numplayers;
-				for (j = 0; j < NUMPOWERS; j++)
-				{
-					if (j == pw_flashing || j == pw_underwater || j == pw_spacetime
-					    || j == pw_tailsfly || j == pw_extralife || j == pw_super || j == pw_nocontrol)
-						continue;
-					players[i].powers[j] = temp[recyclefrom][j];
-				}
-				//1.1: weapon rings too
-				players[i].ringweapons = weapons[recyclefrom];
-				players[i].currentweapon = weaponheld[recyclefrom];
-
-				P_SpawnShieldOrb(players[i].mo->player);
-				P_FlashPal(&players[i], PAL_RECYCLE, 10);
-				counter++;
-			}
-		}
-	}
-	for (i = 0; i < MAXPLAYERS; i++) //just for sneakers/invinc.
-		if (playeringame[i] && players[i].playerstate == PST_LIVE
-			&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super]
-			&& !((netgame || multiplayer) && players[i].spectator))
-			if (P_IsLocalPlayer(players[i].mo->player))
-				P_RestoreMusic(players[i].mo->player);
-#endif
 
 	S_StartSound(NULL, sfx_gravch); //heh, the sound effect I used is already in
 }
@@ -6160,13 +6038,7 @@ void A_Boss2Pogo(mobj_t *actor)
 			goop->momy = FixedMul(FINESINE(fa),ns);
 			goop->momz = FixedMul(4*FRACUNIT, actor->scale);
 
-
-#ifdef CHAOSISNOTDEADYET
-			if (gametype == GT_CHAOS)
-				goop->fuse = 5*TICRATE;
-			else
-#endif
-				goop->fuse = 10*TICRATE;
+			goop->fuse = 10*TICRATE;
 		}
 		actor->reactiontime = 0; // we already shot goop, so don't do it again!
 		if (actor->info->attacksound)
diff --git a/src/p_fab.c b/src/p_fab.c
index 77abccccdeff72d9a39bc9c19374b3c0f6724ea3..7ccb93a94cf145024dd2b124dbdfc555d06f394e 100644
--- a/src/p_fab.c
+++ b/src/p_fab.c
@@ -11,124 +11,5 @@
 /// \brief some new action routines, separated from the original doom
 ///        sources, so that you can include it or remove it easy.
 
-#include "doomdef.h"
-#include "g_game.h"
-#include "p_local.h"
-#include "m_random.h"
-
-static void Translucency_OnChange(void);
-
-/**	\brief cv_translucency
-	console variables to turn on and off translucency
-*/
-consvar_t cv_translucency = {"translucency", "On", CV_CALL|CV_SAVE, CV_OnOff,
-	Translucency_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-/**	\brief Reset Translucency
-*/
-
-static boolean resettrans = false;
-
-/**	\brief	The R_SetTrans function
-	 Set the translucency map for each frame state of mobj
-
-	\param	state1	1st state
-	\param	state2	last state
-	\param	transmap	translucency
-
-	\return	void
-
-
-*/
-static void R_SetTrans(statenum_t state1, statenum_t state2, transnum_t transmap)
-{
-	state_t *state = &states[state1];
-
-	do
-	{
-		state->frame &= ~FF_TRANSMASK;
-		if (!resettrans)
-			state->frame |= (transmap<<FF_TRANSSHIFT);
-		state++;
-	} while (state1++ < state2);
-}
-
-/**	\brief	The P_SetTranslucencies function
-	 hack the translucency in the states for a set of standard doom sprites
-
-	\return	void
-
-
-*/
-static void P_SetTranslucencies(void)
-{
-	R_SetTrans(S_SMOKE1, S_SMOKE5, tr_trans50);
-	R_SetTrans(S_SPLASH1, 0, tr_trans50);
-	R_SetTrans(S_SPLASH2, 0, tr_trans70);
-	R_SetTrans(S_SPLASH3, 0, tr_trans90);
-
-	R_SetTrans(S_DRIPA1, S_DRIPC2, tr_trans30);
-
-	R_SetTrans(S_BLUECRYSTAL1, S_BLUECRYSTAL1, tr_trans30);
-
-	R_SetTrans(S_THOK, 0, tr_trans50); // Thok! mobj
-
-	R_SetTrans(S_FLAME1, S_FLAME4, tr_trans50); // Flame
-
-	R_SetTrans(S_PARTICLE, S_PARTICLE, tr_trans70);
-
-	// Flame jet
-	R_SetTrans(S_FLAMEJETFLAME1, S_FLAMEJETFLAME1, tr_trans50);
-	R_SetTrans(S_FLAMEJETFLAME2, S_FLAMEJETFLAME2, tr_trans60);
-	R_SetTrans(S_FLAMEJETFLAME3, S_FLAMEJETFLAME3, tr_trans70);
-
-	R_SetTrans(S_BLACKEGG_GOOP1, S_BLACKEGG_GOOP3, tr_trans50);
-	R_SetTrans(S_BLACKEGG_GOOP4, 0, tr_trans60);
-	R_SetTrans(S_BLACKEGG_GOOP5, 0, tr_trans70);
-	R_SetTrans(S_BLACKEGG_GOOP6, 0, tr_trans80);
-	R_SetTrans(S_BLACKEGG_GOOP7, 0, tr_trans90);
-
-	R_SetTrans(S_CYBRAKDEMONFLAMESHOT_FLY1, S_CYBRAKDEMONFLAMESHOT_DIE, tr_trans50); // Flame
-	R_SetTrans(S_CYBRAKDEMONFLAMEREST, 0, tr_trans50); // Flame
-	R_SetTrans(S_CYBRAKDEMONTARGETRETICULE1, S_CYBRAKDEMONTARGETRETICULE14, tr_trans50); // Target
-	R_SetTrans(S_CYBRAKDEMONTARGETDOT, S_CYBRAKDEMONTARGETDOT, tr_trans50); // Target
-
-	R_SetTrans(S_FOG1, S_FOG14, tr_trans50);
-
-	// if higher translucency needed, toy around with the other tr_trans variables
-
-	// shield translucencies
-	R_SetTrans(S_ARMA1, S_ARMA16, tr_trans40);
-	R_SetTrans(S_WIND1, S_WIND8,  tr_trans70);
-	R_SetTrans(S_MAGN1, S_MAGN12, tr_trans40);
-	R_SetTrans(S_FORC1, S_FORC20, tr_trans50);
-	R_SetTrans(S_ELEM1, S_ELEM12, tr_trans50);
-	R_SetTrans(S_PITY1, S_PITY10, tr_trans20); // Not sure if Pity Shield should be translucent or not; I mean, the Genesis sprite it's based off of wasn't...
-
-	// translucent spark
-	R_SetTrans(S_SPRK1, S_SPRK1, tr_trans40);
-	R_SetTrans(S_SPRK2, S_SPRK4, tr_trans50);
-	R_SetTrans(S_SPRK5, S_SPRK7, tr_trans60);
-	R_SetTrans(S_SPRK8, S_SPRK10, tr_trans70);
-	R_SetTrans(S_SPRK11, S_SPRK13, tr_trans80);
-	R_SetTrans(S_SPRK14, S_SPRK16, tr_trans90);
-
-	R_SetTrans(S_SMALLBUBBLE, S_SMALLBUBBLE1, tr_trans50);
-	R_SetTrans(S_MEDIUMBUBBLE, S_MEDIUMBUBBLE1, tr_trans50);
-	R_SetTrans(S_LARGEBUBBLE, S_EXTRALARGEBUBBLE, tr_trans50);
-
-	R_SetTrans(S_SPLISH1, S_SPLISH9, tr_trans50);
-	R_SetTrans(S_TOKEN, S_MOVINGTOKEN, tr_trans50);
-	R_SetTrans(S_RAIN1, 0, tr_trans50);
-}
-
-/**	\brief	The Translucency_OnChange function
-	executed when cv_translucency changed
-*/
-static void Translucency_OnChange(void)
-{
-	if (!cv_translucency.value)
-		resettrans = true;
-	P_SetTranslucencies();
-	resettrans = false;
-}
+/// \todo
+///   This file is now unused, please remove at some point
diff --git a/src/p_inter.c b/src/p_inter.c
index 5044b5b81e60c391ba471cc1175f8bd4b67a24f3..8eaa4765a87f7d7d8d828fc1b32a01e2370a302b 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -1590,33 +1590,6 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
 			case MT_SPIKE:
 				str = M_GetText("%s was %s by spikes.\n");
 				break;
-#ifdef CHAOSISNOTDEADYET
-/* These were obviously made for Chaos, and they're extremely out of date.
-   We either need to keep them out of the EXE or update them to contain
-   proper text for all enemies we currently have in the game.
-*/
-			case MT_BLUECRAWLA:
-				str = M_GetText("%s was %s by a blue crawla!\n");
-				break;
-			case MT_REDCRAWLA:
-				str = M_GetText("%s was %s by a red crawla!\n");
-				break;
-			case MT_JETTGUNNER:
-				str = M_GetText("%s was %s by a jetty-syn gunner!\n");
-				break;
-			case MT_JETTBOMBER:
-				str = M_GetText("%s was %s by a jetty-syn bomber!\n");
-				break;
-			case MT_CRAWLACOMMANDER:
-				str = M_GetText("%s was %s by a crawla commander!\n");
-				break;
-			case MT_EGGMOBILE:
-				str = M_GetText("%s was %s by the Egg Mobile!\n");
-				break;
-			case MT_EGGMOBILE2:
-				str = M_GetText("%s was %s by the Egg Slimer!\n");
-				break;
-#endif
 			default:
 				str = M_GetText("%s was %s by an environmental hazard.\n");
 				break;
@@ -1864,11 +1837,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 	{
 		if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording!
 			G_StopMetalRecording();
-#ifdef CHAOSISNOTDEADYET
-		if (gametype == GT_CHAOS)
-			target->player->score /= 2; // Halve the player's score in Chaos Mode
-		else
-#endif
 		if (gametype == GT_MATCH && cv_match_scoring.value == 0 // note, no team match suicide penalty
 			&& ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player)))
 		{ // Suicide penalty
@@ -1896,39 +1864,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 		{
 			INT32 score = 0;
 
-#ifdef CHAOSISNOTDEADYET
-			if (gametype == GT_CHAOS)
-			{
-				if ((target->flags & MF_ENEMY)
-					&& !(target->flags & MF_MISSILE))
-					source->player->scoreadd++;
-
-				switch (target->type)
-				{
-					case MT_BLUECRAWLA:
-					case MT_GOOMBA:
-						score = 100*source->player->scoreadd;
-						break;
-					case MT_REDCRAWLA:
-					case MT_BLUEGOOMBA:
-						score = 150*source->player->scoreadd;
-						break;
-					case MT_JETTBOMBER:
-						score = 400*source->player->scoreadd;
-						break;
-					case MT_JETTGUNNER:
-						score = 500*source->player->scoreadd;
-						break;
-					case MT_CRAWLACOMMANDER:
-						score = 300*source->player->scoreadd;
-						break;
-					default:
-						score = 100*source->player->scoreadd;
-						break;
-				}
-			}
-			else
-#endif
 			if (maptol & TOL_NIGHTS) // Enemies always worth 200, bosses don't do anything.
 			{
 				if ((target->flags & MF_ENEMY) && !(target->flags & (MF_MISSILE|MF_BOSS)))
@@ -2089,9 +2024,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 	// This determines the kind of object spawned
 	// during the death frame of a thing.
 	if (!mariomode // Don't show birds, etc. in Mario Mode Tails 12-23-2001
-#ifdef CHAOSISNOTDEADYET
-	&& gametype != GT_CHAOS // Or Chaos Mode!
-#endif
 	&& target->flags & MF_ENEMY)
 	{
 		if (cv_soniccd.value)
@@ -2512,11 +2444,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
 		return false;
 
 	// In COOP/RACE/CHAOS, you can't hurt other players unless cv_friendlyfire is on
-	if (!cv_friendlyfire.value && (G_PlatformGametype()
-#ifdef CHAOSISNOTDEADYET
-		|| gametype == GT_CHAOS
-#endif
-		))
+	if (!cv_friendlyfire.value && (G_PlatformGametype()))
 		return false;
 
 	// Tag handling
@@ -2843,17 +2771,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 
 		if (target->health > 1)
 		{
-
-#ifdef CHAOSISNOTDEADYET
-			if (gametype == GT_CHAOS && source && source->player)
-			{
-				player = source->player;
-				if (!((player->pflags & PF_USEDOWN) && player->dashspeed
-				&& (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING)))
-					player->scoreadd++;
-				P_AddPlayerScore(player, 300*player->scoreadd);
-			}
-#endif
 			if (target->info->painsound)
 				S_StartSound(target, target->info->painsound);
 
@@ -2882,14 +2799,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 
 		if (target->health > 1)
 			target->flags2 |= MF2_FRET;
-
-#ifdef CHAOSISNOTDEADYET
-		if (gametype == GT_CHAOS && source && source->player)
-		{
-			source->player->scoreadd++;
-			P_AddPlayerScore(source->player, 300*source->player->scoreadd);
-		}
-#endif
 	}
 #ifdef HAVE_BLUA
 	else if (target->flags & MF_ENEMY)
diff --git a/src/p_local.h b/src/p_local.h
index 9f8918cd81092327de4dd5fdef5deeb9151a47b3..0b27c40f307732e6d3dc4b66b99c02885ad64e7c 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -144,7 +144,7 @@ void P_GivePlayerLives(player_t *player, INT32 numlives);
 UINT8 P_GetNextEmerald(void);
 void P_GiveEmerald(boolean spawnObj);
 void P_ResetScore(player_t *player);
-boolean P_MenuActivePause(void);
+boolean P_AutoPause(void);
 
 void P_DoJumpShield(player_t *player);
 void P_BlackOw(player_t *player);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index e85e25b052948f6b882c3d769f1aa73b428855ba..cac4bc24bc4b326b18ff79f21107f53a7419b205 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1354,50 +1354,143 @@ static void P_SceneryXYMovement(mobj_t *mo)
 	P_SceneryXYFriction(mo, oldx, oldy);
 }
 
-static void P_RingZMovement(mobj_t *mo)
+//
+// P_AdjustMobjFloorZ_FFloors
+//
+// Utility function for P_ZMovement and related
+// Adjusts mo->floorz/mo->ceiling accordingly for FFloors
+//
+// "motype" determines what behaviour to use exactly
+// This is to keep things consistent in case these various object types NEED to be different
+//
+// motype options:
+// 0 - normal
+// 1 - forces false check for water (rings)
+// 2 - forces false check for water + different quicksand behaviour (scenery)
+//
+static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype)
 {
+	ffloor_t *rover;
+	fixed_t delta1, delta2, thingtop;
+
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
-	// Intercept the stupid 'fall through 3dfloors' bug
-	if (mo->subsector->sector->ffloors)
+	thingtop = mo->z + mo->height;
+
+	for (rover = sector->ffloors; rover; rover = rover->next)
 	{
-		ffloor_t *rover;
-		fixed_t delta1, delta2;
-		INT32 thingtop = mo->z + mo->height;
+		if (!(rover->flags & FF_EXISTS))
+			continue;
 
-		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
+		if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should be affected
+			;
+		else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only
+			continue;
+		else if (rover->flags & FF_QUICKSAND) // quicksand
+			;
+		else if (!((rover->flags & FF_BLOCKPLAYER && mo->player) // solid to players?
+			    || (rover->flags & FF_BLOCKOTHERS && !mo->player))) // solid to others?
+			continue;
+		if (rover->flags & FF_QUICKSAND)
 		{
-			if (!(rover->flags & FF_EXISTS))
-				continue;
-
-			if ((!(rover->flags & FF_BLOCKOTHERS || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE)))
-				continue;
-
-			if (rover->flags & FF_QUICKSAND)
+			switch (motype)
 			{
-				if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
-				{
-					if (mo->floorz < mo->z)
+				case 2: // scenery does things differently for some reason
+					if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
+					{
 						mo->floorz = mo->z;
-				}
-				continue;
+						continue;
+					}
+					break;
+				default:
+					if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
+					{
+						if (mo->floorz < mo->z)
+							mo->floorz = mo->z;
+					}
+					continue; // This is so you can jump/spring up through quicksand from below.
 			}
+		}
 
-			delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2)
-				&& (!(rover->flags & FF_REVERSEPLATFORM)))
-			{
-				mo->floorz = *rover->topheight;
-			}
-			if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
-				&& (/*mo->z + mo->height <= *rover->bottomheight ||*/ !(rover->flags & FF_PLATFORM)))
-			{
-				mo->ceilingz = *rover->bottomheight;
-			}
+		delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
+		delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
+		if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2)
+			&& !(rover->flags & FF_REVERSEPLATFORM))
+		{
+			mo->floorz = *rover->topheight;
+		}
+		if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
+			&& !(rover->flags & FF_PLATFORM))
+		{
+			mo->ceilingz = *rover->bottomheight;
+		}
+	}
+}
+
+//
+// P_AdjustMobjFloorZ_PolyObjs
+//
+// Utility function for P_ZMovement and related
+// Adjusts mo->floorz/mo->ceiling accordingly for PolyObjs
+//
+static void P_AdjustMobjFloorZ_PolyObjs(mobj_t *mo, subsector_t *subsec)
+{
+	polyobj_t *po = subsec->polyList;
+	sector_t *polysec;
+	fixed_t delta1, delta2, thingtop;
+	fixed_t polytop, polybottom;
+
+	I_Assert(mo != NULL);
+	I_Assert(!P_MobjWasRemoved(mo));
+
+	thingtop = mo->z + mo->height;
+
+	while(po)
+	{
+		if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID))
+		{
+			po = (polyobj_t *)(po->link.next);
+			continue;
+		}
+
+		// We're inside it! Yess...
+		polysec = po->lines[0]->backsector;
+
+		if (po->flags & POF_CLIPPLANES)
+		{
+			polytop = polysec->ceilingheight;
+			polybottom = polysec->floorheight;
+		}
+		else
+		{
+			polytop = INT32_MAX;
+			polybottom = INT32_MIN;
 		}
+
+		delta1 = mo->z - (polybottom + ((polytop - polybottom)/2));
+		delta2 = thingtop - (polybottom + ((polytop - polybottom)/2));
+
+		if (polytop > mo->floorz && abs(delta1) < abs(delta2))
+			mo->floorz = polytop;
+
+		if (polybottom < mo->ceilingz && abs(delta1) >= abs(delta2))
+			mo->ceilingz = polybottom;
+
+		po = (polyobj_t *)(po->link.next);
 	}
+}
+
+static void P_RingZMovement(mobj_t *mo)
+{
+	I_Assert(mo != NULL);
+	I_Assert(!P_MobjWasRemoved(mo));
+
+	// Intercept the stupid 'fall through 3dfloors' bug
+	if (mo->subsector->sector->ffloors)
+		P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 1);
+	if (mo->subsector->polyList)
+		P_AdjustMobjFloorZ_PolyObjs(mo, mo->subsector);
 
 	// adjust height
 	if (mo->pmomz && mo->z != mo->floorz)
@@ -1443,7 +1536,7 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover)
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
-	if ((rover->flags & FF_SWIMMABLE) && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
+	if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
 		&& !(rover->master->flags & ML_BLOCKMONSTERS)
 		&& ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > *rover->topheight - FixedMul(16*FRACUNIT, mo->scale)))
 			return true;
@@ -1464,55 +1557,9 @@ static boolean P_ZMovement(mobj_t *mo)
 
 	// Intercept the stupid 'fall through 3dfloors' bug
 	if (mo->subsector->sector->ffloors)
-	{
-		ffloor_t *rover;
-		fixed_t delta1, delta2, thingtop = mo->z + mo->height;
-
-		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
-		{
-#if 0 // I question the utility of having four seperate z movement functions.
-			if (!(rover->flags & FF_EXISTS)
-				|| (!((((rover->flags & FF_BLOCKPLAYER) && mo->player)
-				|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player)) || rover->flags & FF_QUICKSAND)
-				|| (rover->flags & FF_SWIMMABLE)))
-			{
-				continue;
-			}
-#else
-			if (!(rover->flags & FF_EXISTS))
-				continue;
-
-			if (mo->player && P_CheckSolidLava(mo, rover)) // only the player should be affected
-				;
-			else if (!((((rover->flags & FF_BLOCKPLAYER) && mo->player)
-				|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
-				|| rover->flags & FF_QUICKSAND))
-				continue;
-#endif
-			if (rover->flags & FF_QUICKSAND)
-			{
-				if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
-				{
-					if (mo->floorz < mo->z)
-						mo->floorz = mo->z;
-				}
-				continue;
-			}
-
-			delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2)
-				&& (!(rover->flags & FF_REVERSEPLATFORM)))
-			{
-				mo->floorz = *rover->topheight;
-			}
-			if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
-				&& (/*mo->z + mo->height <= *rover->bottomheight ||*/ !(rover->flags & FF_PLATFORM)))
-			{
-				mo->ceilingz = *rover->bottomheight;
-			}
-		}
-	}
+		P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0);
+	if (mo->subsector->polyList)
+		P_AdjustMobjFloorZ_PolyObjs(mo, mo->subsector);
 
 	// adjust height
 	if (mo->pmomz && mo->z != mo->floorz)
@@ -1922,45 +1969,9 @@ static void P_PlayerZMovement(mobj_t *mo)
 
 	// Intercept the stupid 'fall through 3dfloors' bug
 	if (mo->subsector->sector->ffloors)
-	{
-		ffloor_t *rover;
-		fixed_t delta1, delta2;
-		INT32 thingtop = mo->z + mo->height;
-
-		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
-		{
-			if (!(rover->flags & FF_EXISTS))
-				continue;
-
-			if (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))
-				;
-			else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
-				continue;
-
-			if (rover->flags & FF_QUICKSAND)
-			{
-				if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
-				{
-					if (mo->floorz < mo->z)
-						mo->floorz = mo->z;
-				}
-				continue; // This is so you can jump/spring up through quicksand from below.
-			}
-
-			delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2)
-				&& (!(rover->flags & FF_REVERSEPLATFORM)))
-			{
-				mo->floorz = *rover->topheight;
-			}
-			if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
-				&& (/*mo->z + mo->height <= *rover->bottomheight ||*/ !(rover->flags & FF_PLATFORM)))
-			{
-				mo->ceilingz = *rover->bottomheight;
-			}
-		}
-	}
+		P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0);
+	if (mo->subsector->polyList)
+		P_AdjustMobjFloorZ_PolyObjs(mo, mo->subsector);
 
 	// check for smooth step up
 	if ((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height > mo->ceilingz)
@@ -2052,27 +2063,25 @@ static void P_PlayerZMovement(mobj_t *mo)
 
 								while(po)
 								{
-									if (!P_MobjInsidePolyobj(po, mo))
+									if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID))
 									{
 										po = (polyobj_t *)(po->link.next);
 										continue;
 									}
 
+									// We're inside it! Yess...
 									polysec = po->lines[0]->backsector;
 
 									// Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red
-									if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && (po->flags & POF_SOLID) && po->thinker)
+									if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && po->thinker)
 										stopmovecut = true;
 
-									if (!(po->flags & POF_LDEXEC)
-										|| !(po->flags & POF_SOLID))
+									if (!(po->flags & POF_LDEXEC))
 									{
 										po = (polyobj_t *)(po->link.next);
 										continue;
 									}
 
-									// We're inside it! Yess...
-
 									if (mo->z == polysec->ceilingheight)
 									{
 										// We're landing on a PO, so check for
@@ -2241,42 +2250,9 @@ static boolean P_SceneryZMovement(mobj_t *mo)
 {
 	// Intercept the stupid 'fall through 3dfloors' bug
 	if (mo->subsector->sector->ffloors)
-	{
-		ffloor_t *rover;
-		fixed_t delta1, delta2;
-		INT32 thingtop = mo->z + mo->height;
-
-		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
-		{
-			if (!(rover->flags & FF_EXISTS))
-				continue;
-
-			if ((!(rover->flags & FF_BLOCKOTHERS || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE)))
-				continue;
-
-			if (rover->flags & FF_QUICKSAND)
-			{
-				if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
-				{
-					mo->floorz = mo->z;
-					continue;
-				}
-			}
-
-			delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2)
-				&& (!(rover->flags & FF_REVERSEPLATFORM)))
-			{
-				mo->floorz = *rover->topheight;
-			}
-			if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
-				&& (/*mo->z + mo->height <= *rover->bottomheight ||*/ !(rover->flags & FF_PLATFORM)))
-			{
-				mo->ceilingz = *rover->bottomheight;
-			}
-		}
-	}
+		P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 2);
+	if (mo->subsector->polyList)
+		P_AdjustMobjFloorZ_PolyObjs(mo, mo->subsector);
 
 	// adjust height
 	if (mo->pmomz && mo->z != mo->floorz)
@@ -3371,11 +3347,7 @@ static void P_Boss2Thinker(mobj_t *mobj)
 	if (!mobj->movecount)
 		mobj->flags2 &= ~MF2_FRET;
 
-	if (!mobj->tracer
-#ifdef CHAOSISNOTDEADYET
-		&& gametype != GT_CHAOS
-#endif
-		)
+	if (!mobj->tracer)
 	{
 		var1 = 0;
 		A_BossJetFume(mobj);
@@ -3398,11 +3370,7 @@ static void P_Boss2Thinker(mobj_t *mobj)
 		return;
 	}
 
-	if (mobj->state == &states[mobj->info->spawnstate] && mobj->health > mobj->info->damage
-#ifdef CHAOSISNOTDEADYET
-	&& gametype != GT_CHAOS
-#endif
-	)
+	if (mobj->state == &states[mobj->info->spawnstate] && mobj->health > mobj->info->damage)
 		A_Boss2Chase(mobj);
 	else if (mobj->health > 0 && mobj->state != &states[mobj->info->painstate] && mobj->state != &states[mobjinfo[mobj->info->missilestate].raisestate])
 	{
@@ -5116,32 +5084,6 @@ void P_SetScale(mobj_t *mobj, fixed_t newscale)
 	}
 }
 
-// Returns true if no boss with health is in the level.
-// Used for Chaos mode
-
-#ifdef CHAOSISNOTDEADYET
-static boolean P_BossDoesntExist(void)
-{
-	thinker_t *th;
-	mobj_t *mo2;
-
-	// scan the thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
-	{
-		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-			continue;
-
-		mo2 = (mobj_t *)th;
-
-		if (mo2->flags & MF_BOSS && mo2->health)
-			return false;
-	}
-
-	// No boss found!
-	return true;
-}
-#endif
-
 void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on your target
 {
 	fixed_t dist, ndist, speedmul;
@@ -6130,14 +6072,6 @@ void P_MobjThinker(mobj_t *mobj)
 					return;
 				}
 
-#ifdef CHAOSISNOTDEADYET
-				if (gametype == GT_CHAOS && mobj->target->health <= 0)
-				{
-					P_RemoveMobj(mobj);
-					return;
-				}
-#endif
-
 				jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale));
 				jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale));
 
@@ -6209,14 +6143,6 @@ void P_MobjThinker(mobj_t *mobj)
 					return;
 				}
 
-#ifdef CHAOSISNOTDEADYET
-				if (gametype == GT_CHAOS && mobj->target->health <= 0)
-				{
-					P_RemoveMobj(mobj);
-					return;
-				}
-#endif
-
 				jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale));
 				jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale));
 
@@ -6239,13 +6165,6 @@ void P_MobjThinker(mobj_t *mobj)
 					return;
 				}
 
-#ifdef CHAOSISNOTDEADYET
-				if (gametype == GT_CHAOS && mobj->target->health <= 0)
-				{
-					P_RemoveMobj(mobj);
-					return;
-				}
-#endif
 				P_UnsetThingPosition(mobj);
 				mobj->x = mobj->target->x;
 				mobj->y = mobj->target->y;
@@ -6677,148 +6596,6 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
 					}
 					P_RemoveMobj(mobj); // make sure they disappear
 					return;
-				case MT_CHAOSSPAWNER: // Chaos Mode spawner thingy
-				{
-					// 8 enemies: Blue Crawla, Red Crawla, Crawla Commander,
-					//            Jett-Synn Bomber, Jett-Synn Gunner, Skim,
-					//            Egg Mobile, Egg Slimer.
-					// Max. 3 chances per enemy.
-
-#ifdef CHAOSISNOTDEADYET
-
-					mobjtype_t spawnchance[8*3], enemy;
-					mobj_t *spawnedmo;
-					INT32 i = 0, numchoices = 0, stop;
-					fixed_t sfloorz, space, airspace, spawnz[8*3];
-
-					sfloorz = mobj->floorz;
-					space = mobj->ceilingz - sfloorz;
-
-					// This makes the assumption there is no gravity-defying water.
-					// A fair assumption to make, if you ask me.
-					airspace = min(space, mobj->ceilingz - mobj->watertop);
-
-					mobj->fuse = cv_chaos_spawnrate.value*TICRATE;
-					prandom = P_Random(); // Gotta love those random numbers!
-
-					if (cv_chaos_bluecrawla.value && space >= mobjinfo[MT_BLUECRAWLA].height)
-					{
-						stop = i + cv_chaos_bluecrawla.value;
-						for (; i < stop; i++)
-						{
-							spawnchance[i] = MT_BLUECRAWLA;
-							spawnz[i] = sfloorz;
-							numchoices++;
-						}
-					}
-					if (cv_chaos_redcrawla.value && space >= mobjinfo[MT_REDCRAWLA].height)
-					{
-						stop = i + cv_chaos_redcrawla.value;
-						for (; i < stop; i++)
-						{
-							spawnchance[i] = MT_REDCRAWLA;
-							spawnz[i] = sfloorz;
-							numchoices++;
-						}
-					}
-					if (cv_chaos_crawlacommander.value
-						&& space >= mobjinfo[MT_CRAWLACOMMANDER].height + 33*FRACUNIT)
-					{
-						stop = i + cv_chaos_crawlacommander.value;
-						for (; i < stop; i++)
-						{
-							spawnchance[i] = MT_CRAWLACOMMANDER;
-							spawnz[i] = sfloorz + 33*FRACUNIT;
-							numchoices++;
-						}
-					}
-					if (cv_chaos_jettysynbomber.value
-						&& airspace >= mobjinfo[MT_JETTBOMBER].height + 33*FRACUNIT)
-					{
-						stop = i + cv_chaos_jettysynbomber.value;
-						for (; i < stop; i++)
-						{
-							spawnchance[i] = MT_JETTBOMBER;
-							spawnz[i] = max(sfloorz, mobj->watertop) + 33*FRACUNIT;
-							numchoices++;
-						}
-					}
-					if (cv_chaos_jettysyngunner.value
-						&& airspace >= mobjinfo[MT_JETTGUNNER].height + 33*FRACUNIT)
-					{
-						stop = i + cv_chaos_jettysyngunner.value;
-						for (; i < stop; i++)
-						{
-							spawnchance[i] = MT_JETTGUNNER;
-							spawnz[i] = max(sfloorz, mobj->watertop) + 33*FRACUNIT;
-							numchoices++;
-						}
-					}
-					if (cv_chaos_skim.value
-						&& mobj->watertop < mobj->ceilingz - mobjinfo[MT_SKIM].height
-						&& mobj->watertop - sfloorz > mobjinfo[MT_SKIM].height/2)
-					{
-						stop = i + cv_chaos_skim.value;
-						for (; i < stop; i++)
-						{
-							spawnchance[i] = MT_SKIM;
-							spawnz[i] = mobj->watertop;
-							numchoices++;
-						}
-					}
-					if (P_BossDoesntExist())
-					{
-						if (cv_chaos_eggmobile1.value
-							&& space >= mobjinfo[MT_EGGMOBILE].height + 33*FRACUNIT)
-						{
-							stop = i + cv_chaos_eggmobile1.value;
-							for (; i < stop; i++)
-							{
-								spawnchance[i] = MT_EGGMOBILE;
-								spawnz[i] = sfloorz + 33*FRACUNIT;
-								numchoices++;
-							}
-						}
-						if (cv_chaos_eggmobile2.value
-							&& space >= mobjinfo[MT_EGGMOBILE2].height + 33*FRACUNIT)
-						{
-							stop = i + cv_chaos_eggmobile2.value;
-							for (; i < stop; i++)
-							{
-								spawnchance[i] = MT_EGGMOBILE2;
-								spawnz[i] = sfloorz + 33*FRACUNIT;
-								numchoices++;
-							}
-						}
-					}
-
-					if (numchoices)
-					{
-						fixed_t fogz;
-
-						i = prandom % numchoices;
-						enemy = spawnchance[i];
-
-						fogz = spawnz[i] - 32*FRACUNIT;
-						if (fogz < sfloorz)
-							fogz = sfloorz;
-
-						spawnedmo = P_SpawnMobj(mobj->x, mobj->y, spawnz[i], enemy);
-						P_SpawnMobj(mobj->x, mobj->y, fogz, MT_TFOG);
-
-						P_SupermanLook4Players(spawnedmo);
-						if (spawnedmo->target && spawnedmo->type != MT_SKIM)
-							P_SetMobjState(spawnedmo, spawnedmo->info->seestate);
-
-						if (spawnedmo->flags & MF_BOSS)
-						{
-							spawnedmo->flags2 |= MF2_CHAOSBOSS;
-							spawnedmo->momx = spawnedmo->momy = 0;
-						}
-					}
-#endif
-					break;
-				}
 				case MT_METALSONIC_BATTLE:
 					break; // don't remove
 				case MT_SPIKE:
@@ -8178,7 +7955,8 @@ void P_SpawnMapThing(mapthing_t *mthing)
 
 	if (i == NUMMOBJTYPES)
 	{
-		if (mthing->type == 3328) // 3D Mode start Thing
+		if (mthing->type == 3328 // 3D Mode start Thing
+		 || mthing->type == 750) // Chaos mode spawn
 			return;
 		CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y);
 		i = MT_UNKNOWN;
@@ -8597,15 +8375,6 @@ ML_NOCLIMB : Direction not controllable
 		if (mthing->angle > 0)
 			mobj->health = mthing->angle;
 		break;
-	case MT_CHAOSSPAWNER:
-#ifndef CHAOSISNOTDEADYET
-		return;
-#else
-		if (gametype != GT_CHAOS)
-			return;
-		mobj->fuse = P_Random()*2;
-		break;
-#endif
 	case MT_TRAPGOYLE:
 	case MT_TRAPGOYLEUP:
 	case MT_TRAPGOYLEDOWN:
diff --git a/src/p_pspr.h b/src/p_pspr.h
index 339dd1f96cbb32f1497fa3c4b62669d087b41af7..e0b57675cd45568e3826c656d8edf17fd032f2ae 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -43,6 +43,16 @@
 #define FF_TRANSMASK 0xf0000
 /// \brief shift for FF_TRANSMASK
 #define FF_TRANSSHIFT 16
+/// \brief preshifted translucency flags
+#define FF_TRANS10 (tr_trans10<<FF_TRANSSHIFT)
+#define FF_TRANS20 (tr_trans20<<FF_TRANSSHIFT)
+#define FF_TRANS30 (tr_trans30<<FF_TRANSSHIFT)
+#define FF_TRANS40 (tr_trans40<<FF_TRANSSHIFT)
+#define FF_TRANS50 (tr_trans50<<FF_TRANSSHIFT)
+#define FF_TRANS60 (tr_trans60<<FF_TRANSSHIFT)
+#define FF_TRANS70 (tr_trans70<<FF_TRANSSHIFT)
+#define FF_TRANS80 (tr_trans80<<FF_TRANSSHIFT)
+#define FF_TRANS90 (tr_trans90<<FF_TRANSSHIFT)
 
 /**	\brief translucency tables
 
diff --git a/src/p_saveg.c b/src/p_saveg.c
index bf64d9a2b2bf11d49df16b7899a18ca70df850a0..851d653fa2c2736d8a59a720f9a493b4f7ee5ffb 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -990,6 +990,241 @@ static inline UINT32 SavePlayer(const player_t *player)
 	return 0xFFFFFFFF;
 }
 
+//
+// SaveMobjThinker
+//
+// Saves a mobj_t thinker
+//
+static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
+{
+	const mobj_t *mobj = (const mobj_t *)th;
+	UINT32 diff;
+	UINT16 diff2;
+
+	// Ignore stationary hoops - these will be respawned from mapthings.
+	if (mobj->type == MT_HOOP)
+		return;
+
+	// These are NEVER saved.
+	if (mobj->type == MT_HOOPCOLLIDE)
+		return;
+
+	// This hoop has already been collected.
+	if (mobj->type == MT_HOOPCENTER && mobj->threshold == 4242)
+		return;
+
+	if (mobj->spawnpoint && mobj->info->doomednum != -1)
+	{
+		// spawnpoint is not modified but we must save it since it is an identifier
+		diff = MD_SPAWNPOINT;
+
+		if ((mobj->x != mobj->spawnpoint->x << FRACBITS) ||
+			(mobj->y != mobj->spawnpoint->y << FRACBITS) ||
+			(mobj->angle != FixedAngle(mobj->spawnpoint->angle*FRACUNIT)))
+			diff |= MD_POS;
+
+		if (mobj->info->doomednum != mobj->spawnpoint->type)
+			diff |= MD_TYPE;
+	}
+	else
+		diff = MD_POS | MD_TYPE; // not a map spawned thing so make it from scratch
+
+	diff2 = 0;
+
+	// not the default but the most probable
+	if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0)
+		diff |= MD_MOM;
+	if (mobj->radius != mobj->info->radius)
+		diff |= MD_RADIUS;
+	if (mobj->height != mobj->info->height)
+		diff |= MD_HEIGHT;
+	if (mobj->flags != mobj->info->flags)
+		diff |= MD_FLAGS;
+	if (mobj->flags2)
+		diff |= MD_FLAGS2;
+	if (mobj->health != mobj->info->spawnhealth)
+		diff |= MD_HEALTH;
+	if (mobj->reactiontime != mobj->info->reactiontime)
+		diff |= MD_RTIME;
+	if ((statenum_t)(mobj->state-states) != mobj->info->spawnstate)
+		diff |= MD_STATE;
+	if (mobj->tics != mobj->state->tics)
+		diff |= MD_TICS;
+	if (mobj->sprite != mobj->state->sprite)
+		diff |= MD_SPRITE;
+	if (mobj->frame != mobj->state->frame)
+		diff |= MD_FRAME;
+	if (mobj->eflags)
+		diff |= MD_EFLAGS;
+	if (mobj->player)
+		diff |= MD_PLAYER;
+
+	if (mobj->movedir)
+		diff |= MD_MOVEDIR;
+	if (mobj->movecount)
+		diff |= MD_MOVECOUNT;
+	if (mobj->threshold)
+		diff |= MD_THRESHOLD;
+	if (mobj->lastlook != -1)
+		diff |= MD_LASTLOOK;
+	if (mobj->target)
+		diff |= MD_TARGET;
+	if (mobj->tracer)
+		diff |= MD_TRACER;
+	if (mobj->friction != ORIG_FRICTION)
+		diff |= MD_FRICTION;
+	if (mobj->movefactor != ORIG_FRICTION_FACTOR)
+		diff |= MD_MOVEFACTOR;
+	if (mobj->fuse)
+		diff |= MD_FUSE;
+	if (mobj->watertop)
+		diff |= MD_WATERTOP;
+	if (mobj->waterbottom)
+		diff |= MD_WATERBOTTOM;
+	if (mobj->scale != FRACUNIT)
+		diff |= MD_SCALE;
+	if (mobj->destscale != mobj->scale)
+		diff |= MD_DSCALE;
+	if (mobj->scalespeed != FRACUNIT/12)
+		diff2 |= MD2_SCALESPEED;
+
+	if (mobj == redflag)
+		diff |= MD_REDFLAG;
+	if (mobj == blueflag)
+		diff |= MD_BLUEFLAG;
+
+	if (mobj->cusval)
+		diff2 |= MD2_CUSVAL;
+	if (mobj->cvmem)
+		diff2 |= MD2_CVMEM;
+	if (mobj->color)
+		diff2 |= MD2_COLOR;
+	if (mobj->skin)
+		diff2 |= MD2_SKIN;
+	if (mobj->extravalue1)
+		diff2 |= MD2_EXTVAL1;
+	if (mobj->extravalue2)
+		diff2 |= MD2_EXTVAL2;
+	if (mobj->hnext)
+		diff2 |= MD2_HNEXT;
+	if (mobj->hprev)
+		diff2 |= MD2_HPREV;
+	if (diff2 != 0)
+		diff |= MD_MORE;
+
+	// Scrap all of that. If we're a hoop center, this is ALL we're saving.
+	if (mobj->type == MT_HOOPCENTER)
+		diff = MD_SPAWNPOINT;
+
+	WRITEUINT8(save_p, type);
+	WRITEUINT32(save_p, diff);
+	if (diff & MD_MORE)
+		WRITEUINT16(save_p, diff2);
+
+	// save pointer, at load time we will search this pointer to reinitilize pointers
+	WRITEUINT32(save_p, (size_t)mobj);
+
+	WRITEFIXED(save_p, mobj->z); // Force this so 3dfloor problems don't arise.
+	WRITEFIXED(save_p, mobj->floorz);
+	WRITEFIXED(save_p, mobj->ceilingz);
+
+	if (diff & MD_SPAWNPOINT)
+	{
+		size_t z;
+
+		for (z = 0; z < nummapthings; z++)
+			if (&mapthings[z] == mobj->spawnpoint)
+				WRITEUINT16(save_p, z);
+		if (mobj->type == MT_HOOPCENTER)
+			return;
+	}
+
+	if (diff & MD_TYPE)
+		WRITEUINT32(save_p, mobj->type);
+	if (diff & MD_POS)
+	{
+		WRITEFIXED(save_p, mobj->x);
+		WRITEFIXED(save_p, mobj->y);
+		WRITEANGLE(save_p, mobj->angle);
+	}
+	if (diff & MD_MOM)
+	{
+		WRITEFIXED(save_p, mobj->momx);
+		WRITEFIXED(save_p, mobj->momy);
+		WRITEFIXED(save_p, mobj->momz);
+	}
+	if (diff & MD_RADIUS)
+		WRITEFIXED(save_p, mobj->radius);
+	if (diff & MD_HEIGHT)
+		WRITEFIXED(save_p, mobj->height);
+	if (diff & MD_FLAGS)
+		WRITEUINT32(save_p, mobj->flags);
+	if (diff & MD_FLAGS2)
+		WRITEUINT32(save_p, mobj->flags2);
+	if (diff & MD_HEALTH)
+		WRITEINT32(save_p, mobj->health);
+	if (diff & MD_RTIME)
+		WRITEINT32(save_p, mobj->reactiontime);
+	if (diff & MD_STATE)
+		WRITEUINT16(save_p, mobj->state-states);
+	if (diff & MD_TICS)
+		WRITEINT32(save_p, mobj->tics);
+	if (diff & MD_SPRITE)
+		WRITEUINT16(save_p, mobj->sprite);
+	if (diff & MD_FRAME)
+		WRITEUINT32(save_p, mobj->frame);
+	if (diff & MD_EFLAGS)
+		WRITEUINT8(save_p, mobj->eflags);
+	if (diff & MD_PLAYER)
+		WRITEUINT8(save_p, mobj->player-players);
+	if (diff & MD_MOVEDIR)
+		WRITEANGLE(save_p, mobj->movedir);
+	if (diff & MD_MOVECOUNT)
+		WRITEINT32(save_p, mobj->movecount);
+	if (diff & MD_THRESHOLD)
+		WRITEINT32(save_p, mobj->threshold);
+	if (diff & MD_LASTLOOK)
+		WRITEINT32(save_p, mobj->lastlook);
+	if (diff & MD_TARGET)
+		WRITEUINT32(save_p, mobj->target->mobjnum);
+	if (diff & MD_TRACER)
+		WRITEUINT32(save_p, mobj->tracer->mobjnum);
+	if (diff & MD_FRICTION)
+		WRITEFIXED(save_p, mobj->friction);
+	if (diff & MD_MOVEFACTOR)
+		WRITEFIXED(save_p, mobj->movefactor);
+	if (diff & MD_FUSE)
+		WRITEINT32(save_p, mobj->fuse);
+	if (diff & MD_WATERTOP)
+		WRITEFIXED(save_p, mobj->watertop);
+	if (diff & MD_WATERBOTTOM)
+		WRITEFIXED(save_p, mobj->waterbottom);
+	if (diff & MD_SCALE)
+		WRITEFIXED(save_p, mobj->scale);
+	if (diff & MD_DSCALE)
+		WRITEFIXED(save_p, mobj->destscale);
+	if (diff2 & MD2_SCALESPEED)
+		WRITEFIXED(save_p, mobj->scalespeed);
+	if (diff2 & MD2_CUSVAL)
+		WRITEINT32(save_p, mobj->cusval);
+	if (diff2 & MD2_CVMEM)
+		WRITEINT32(save_p, mobj->cvmem);
+	if (diff2 & MD2_SKIN)
+		WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins));
+	if (diff2 & MD2_COLOR)
+		WRITEUINT8(save_p, mobj->color);
+	if (diff2 & MD2_EXTVAL1)
+		WRITEINT32(save_p, mobj->extravalue1);
+	if (diff2 & MD2_EXTVAL2)
+		WRITEINT32(save_p, mobj->extravalue2);
+	if (diff2 & MD2_HNEXT)
+		WRITEUINT32(save_p, mobj->hnext->mobjnum);
+	if (diff2 & MD2_HPREV)
+		WRITEUINT32(save_p, mobj->hprev->mobjnum);
+
+	WRITEUINT32(save_p, mobj->mobjnum);
+}
+
 //
 // SaveSpecialLevelThinker
 //
@@ -1395,9 +1630,6 @@ static inline void SaveWhatThinker(const thinker_t *th, const UINT8 type)
 static void P_NetArchiveThinkers(void)
 {
 	const thinker_t *th;
-	const mobj_t *mobj;
-	UINT32 diff;
-	UINT16 diff2;
 
 	WRITEUINT32(save_p, ARCHIVEBLOCK_THINKERS);
 
@@ -1406,230 +1638,8 @@ static void P_NetArchiveThinkers(void)
 	{
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 		{
-			mobj = (const mobj_t *)th;
-
-			// Ignore stationary hoops - these will be respawned from mapthings.
-			if (mobj->type == MT_HOOP)
-				continue;
-
-			// These are NEVER saved.
-			if (mobj->type == MT_HOOPCOLLIDE)
-				continue;
-
-			// This hoop has already been collected.
-			if (mobj->type == MT_HOOPCENTER && mobj->threshold == 4242)
-				continue;
-
-			if (mobj->spawnpoint && mobj->info->doomednum != -1)
-			{
-				// spawnpoint is not modified but we must save it since it is an identifier
-				diff = MD_SPAWNPOINT;
-
-				if ((mobj->x != mobj->spawnpoint->x << FRACBITS) ||
-					(mobj->y != mobj->spawnpoint->y << FRACBITS) ||
-					(mobj->angle != FixedAngle(mobj->spawnpoint->angle*FRACUNIT)))
-					diff |= MD_POS;
-
-				if (mobj->info->doomednum != mobj->spawnpoint->type)
-					diff |= MD_TYPE;
-			}
-			else
-				diff = MD_POS | MD_TYPE; // not a map spawned thing so make it from scratch
-
-			diff2 = 0;
-
-			// not the default but the most probable
-			if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0)
-				diff |= MD_MOM;
-			if (mobj->radius != mobj->info->radius)
-				diff |= MD_RADIUS;
-			if (mobj->height != mobj->info->height)
-				diff |= MD_HEIGHT;
-			if (mobj->flags != mobj->info->flags)
-				diff |= MD_FLAGS;
-			if (mobj->flags2)
-				diff |= MD_FLAGS2;
-			if (mobj->health != mobj->info->spawnhealth)
-				diff |= MD_HEALTH;
-			if (mobj->reactiontime != mobj->info->reactiontime)
-				diff |= MD_RTIME;
-			if ((statenum_t)(mobj->state-states) != mobj->info->spawnstate)
-				diff |= MD_STATE;
-			if (mobj->tics != mobj->state->tics)
-				diff |= MD_TICS;
-			if (mobj->sprite != mobj->state->sprite)
-				diff |= MD_SPRITE;
-			if (mobj->frame != mobj->state->frame)
-				diff |= MD_FRAME;
-			if (mobj->eflags)
-				diff |= MD_EFLAGS;
-			if (mobj->player)
-				diff |= MD_PLAYER;
-
-			if (mobj->movedir)
-				diff |= MD_MOVEDIR;
-			if (mobj->movecount)
-				diff |= MD_MOVECOUNT;
-			if (mobj->threshold)
-				diff |= MD_THRESHOLD;
-			if (mobj->lastlook != -1)
-				diff |= MD_LASTLOOK;
-			if (mobj->target)
-				diff |= MD_TARGET;
-			if (mobj->tracer)
-				diff |= MD_TRACER;
-			if (mobj->friction != ORIG_FRICTION)
-				diff |= MD_FRICTION;
-			if (mobj->movefactor != ORIG_FRICTION_FACTOR)
-				diff |= MD_MOVEFACTOR;
-			if (mobj->fuse)
-				diff |= MD_FUSE;
-			if (mobj->watertop)
-				diff |= MD_WATERTOP;
-			if (mobj->waterbottom)
-				diff |= MD_WATERBOTTOM;
-			if (mobj->scale != FRACUNIT)
-				diff |= MD_SCALE;
-			if (mobj->destscale != mobj->scale)
-				diff |= MD_DSCALE;
-			if (mobj->scalespeed != FRACUNIT/12)
-				diff2 |= MD2_SCALESPEED;
-
-			if (mobj == redflag)
-				diff |= MD_REDFLAG;
-			if (mobj == blueflag)
-				diff |= MD_BLUEFLAG;
-
-			if (mobj->cusval)
-				diff2 |= MD2_CUSVAL;
-			if (mobj->cvmem)
-				diff2 |= MD2_CVMEM;
-			if (mobj->color)
-				diff2 |= MD2_COLOR;
-			if (mobj->skin)
-				diff2 |= MD2_SKIN;
-			if (mobj->extravalue1)
-				diff2 |= MD2_EXTVAL1;
-			if (mobj->extravalue2)
-				diff2 |= MD2_EXTVAL2;
-			if (mobj->hnext)
-				diff2 |= MD2_HNEXT;
-			if (mobj->hprev)
-				diff2 |= MD2_HPREV;
-			if (diff2 != 0)
-				diff |= MD_MORE;
-
-			// Scrap all of that. If we're a hoop center, this is ALL we're saving.
-			if (mobj->type == MT_HOOPCENTER)
-				diff = MD_SPAWNPOINT;
-
-			WRITEUINT8(save_p, tc_mobj);
-			WRITEUINT32(save_p, diff);
-			if (diff & MD_MORE)
-				WRITEUINT16(save_p, diff2);
-
-			// save pointer, at load time we will search this pointer to reinitilize pointers
-			WRITEUINT32(save_p, (size_t)mobj);
-
-			WRITEFIXED(save_p, mobj->z); // Force this so 3dfloor problems don't arise.
-			WRITEFIXED(save_p, mobj->floorz);
-			WRITEFIXED(save_p, mobj->ceilingz);
-
-			if (diff & MD_SPAWNPOINT)
-			{
-				size_t z;
-
-				for (z = 0; z < nummapthings; z++)
-					if (&mapthings[z] == mobj->spawnpoint)
-						WRITEUINT16(save_p, z);
-				if (mobj->type == MT_HOOPCENTER)
-					continue;
-			}
-
-			if (diff & MD_TYPE)
-				WRITEUINT32(save_p, mobj->type);
-			if (diff & MD_POS)
-			{
-				WRITEFIXED(save_p, mobj->x);
-				WRITEFIXED(save_p, mobj->y);
-				WRITEANGLE(save_p, mobj->angle);
-			}
-			if (diff & MD_MOM)
-			{
-				WRITEFIXED(save_p, mobj->momx);
-				WRITEFIXED(save_p, mobj->momy);
-				WRITEFIXED(save_p, mobj->momz);
-			}
-			if (diff & MD_RADIUS)
-				WRITEFIXED(save_p, mobj->radius);
-			if (diff & MD_HEIGHT)
-				WRITEFIXED(save_p, mobj->height);
-			if (diff & MD_FLAGS)
-				WRITEUINT32(save_p, mobj->flags);
-			if (diff & MD_FLAGS2)
-				WRITEUINT32(save_p, mobj->flags2);
-			if (diff & MD_HEALTH)
-				WRITEINT32(save_p, mobj->health);
-			if (diff & MD_RTIME)
-				WRITEINT32(save_p, mobj->reactiontime);
-			if (diff & MD_STATE)
-				WRITEUINT16(save_p, mobj->state-states);
-			if (diff & MD_TICS)
-				WRITEINT32(save_p, mobj->tics);
-			if (diff & MD_SPRITE)
-				WRITEUINT16(save_p, mobj->sprite);
-			if (diff & MD_FRAME)
-				WRITEUINT32(save_p, mobj->frame);
-			if (diff & MD_EFLAGS)
-				WRITEUINT8(save_p, mobj->eflags);
-			if (diff & MD_PLAYER)
-				WRITEUINT8(save_p, mobj->player-players);
-			if (diff & MD_MOVEDIR)
-				WRITEANGLE(save_p, mobj->movedir);
-			if (diff & MD_MOVECOUNT)
-				WRITEINT32(save_p, mobj->movecount);
-			if (diff & MD_THRESHOLD)
-				WRITEINT32(save_p, mobj->threshold);
-			if (diff & MD_LASTLOOK)
-				WRITEINT32(save_p, mobj->lastlook);
-			if (diff & MD_TARGET)
-				WRITEUINT32(save_p, mobj->target->mobjnum);
-			if (diff & MD_TRACER)
-				WRITEUINT32(save_p, mobj->tracer->mobjnum);
-			if (diff & MD_FRICTION)
-				WRITEFIXED(save_p, mobj->friction);
-			if (diff & MD_MOVEFACTOR)
-				WRITEFIXED(save_p, mobj->movefactor);
-			if (diff & MD_FUSE)
-				WRITEINT32(save_p, mobj->fuse);
-			if (diff & MD_WATERTOP)
-				WRITEFIXED(save_p, mobj->watertop);
-			if (diff & MD_WATERBOTTOM)
-				WRITEFIXED(save_p, mobj->waterbottom);
-			if (diff & MD_SCALE)
-				WRITEFIXED(save_p, mobj->scale);
-			if (diff & MD_DSCALE)
-				WRITEFIXED(save_p, mobj->destscale);
-			if (diff2 & MD2_SCALESPEED)
-				WRITEFIXED(save_p, mobj->scalespeed);
-			if (diff2 & MD2_CUSVAL)
-				WRITEINT32(save_p, mobj->cusval);
-			if (diff2 & MD2_CVMEM)
-				WRITEINT32(save_p, mobj->cvmem);
-			if (diff2 & MD2_SKIN)
-				WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins));
-			if (diff2 & MD2_COLOR)
-				WRITEUINT8(save_p, mobj->color);
-			if (diff2 & MD2_EXTVAL1)
-				WRITEINT32(save_p, mobj->extravalue1);
-			if (diff2 & MD2_EXTVAL2)
-				WRITEINT32(save_p, mobj->extravalue2);
-			if (diff2 & MD2_HNEXT)
-				WRITEUINT32(save_p, mobj->hnext->mobjnum);
-			if (diff2 & MD2_HPREV)
-				WRITEUINT32(save_p, mobj->hprev->mobjnum);
-
-			WRITEUINT32(save_p, mobj->mobjnum);
+			SaveMobjThinker(th, tc_mobj);
+			continue;
 		}
 #ifdef PARANOIA
 		else if (th->function.acp1 == (actionf_p1)P_RainThinker
@@ -1862,6 +1872,232 @@ static inline player_t *LoadPlayer(UINT32 player)
 	return &players[player];
 }
 
+//
+// LoadMobjThinker
+//
+// Loads a mobj_t from a save game
+//
+static void LoadMobjThinker(actionf_p1 thinker)
+{
+	thinker_t *next;
+	mobj_t *mobj;
+	UINT32 diff;
+	UINT16 diff2;
+	INT32 i;
+	fixed_t z, floorz, ceilingz;
+
+	diff = READUINT32(save_p);
+	if (diff & MD_MORE)
+		diff2 = READUINT16(save_p);
+	else
+		diff2 = 0;
+
+	next = (void *)(size_t)READUINT32(save_p);
+
+	z = READFIXED(save_p); // Force this so 3dfloor problems don't arise.
+	floorz = READFIXED(save_p);
+	ceilingz = READFIXED(save_p);
+
+	if (diff & MD_SPAWNPOINT)
+	{
+		UINT16 spawnpointnum = READUINT16(save_p);
+
+		if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
+		{
+			P_SpawnHoopsAndRings(&mapthings[spawnpointnum]);
+			return;
+		}
+
+		mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
+
+		mobj->spawnpoint = &mapthings[spawnpointnum];
+		mapthings[spawnpointnum].mobj = mobj;
+	}
+	else
+		mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
+
+	// declare this as a valid mobj as soon as possible.
+	mobj->thinker.function.acp1 = thinker;
+
+	mobj->z = z;
+	mobj->floorz = floorz;
+	mobj->ceilingz = ceilingz;
+
+	if (diff & MD_TYPE)
+		mobj->type = READUINT32(save_p);
+	else
+	{
+		for (i = 0; i < NUMMOBJTYPES; i++)
+			if (mobj->spawnpoint && mobj->spawnpoint->type == mobjinfo[i].doomednum)
+				break;
+		if (i == NUMMOBJTYPES)
+		{
+			if (mobj->spawnpoint)
+				CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type %d\n", mobj->spawnpoint->type);
+			else
+				CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type NULL\n");
+			I_Error("Savegame corrupted");
+		}
+		mobj->type = i;
+	}
+	mobj->info = &mobjinfo[mobj->type];
+	if (diff & MD_POS)
+	{
+		mobj->x = READFIXED(save_p);
+		mobj->y = READFIXED(save_p);
+		mobj->angle = READANGLE(save_p);
+	}
+	else
+	{
+		mobj->x = mobj->spawnpoint->x << FRACBITS;
+		mobj->y = mobj->spawnpoint->y << FRACBITS;
+		mobj->angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT);
+	}
+	if (diff & MD_MOM)
+	{
+		mobj->momx = READFIXED(save_p);
+		mobj->momy = READFIXED(save_p);
+		mobj->momz = READFIXED(save_p);
+	} // otherwise they're zero, and the memset took care of it
+
+	if (diff & MD_RADIUS)
+		mobj->radius = READFIXED(save_p);
+	else
+		mobj->radius = mobj->info->radius;
+	if (diff & MD_HEIGHT)
+		mobj->height = READFIXED(save_p);
+	else
+		mobj->height = mobj->info->height;
+	if (diff & MD_FLAGS)
+		mobj->flags = READUINT32(save_p);
+	else
+		mobj->flags = mobj->info->flags;
+	if (diff & MD_FLAGS2)
+		mobj->flags2 = READUINT32(save_p);
+	if (diff & MD_HEALTH)
+		mobj->health = READINT32(save_p);
+	else
+		mobj->health = mobj->info->spawnhealth;
+	if (diff & MD_RTIME)
+		mobj->reactiontime = READINT32(save_p);
+	else
+		mobj->reactiontime = mobj->info->reactiontime;
+
+	if (diff & MD_STATE)
+		mobj->state = &states[READUINT16(save_p)];
+	else
+		mobj->state = &states[mobj->info->spawnstate];
+	if (diff & MD_TICS)
+		mobj->tics = READINT32(save_p);
+	else
+		mobj->tics = mobj->state->tics;
+	if (diff & MD_SPRITE)
+		mobj->sprite = READUINT16(save_p);
+	else
+		mobj->sprite = mobj->state->sprite;
+	if (diff & MD_FRAME)
+		mobj->frame = READUINT32(save_p);
+	else
+		mobj->frame = mobj->state->frame;
+	if (diff & MD_EFLAGS)
+		mobj->eflags = READUINT8(save_p);
+	if (diff & MD_PLAYER)
+	{
+		i = READUINT8(save_p);
+		mobj->player = &players[i];
+		mobj->player->mo = mobj;
+		// added for angle prediction
+		if (consoleplayer == i)
+			localangle = mobj->angle;
+		if (secondarydisplayplayer == i)
+			localangle2 = mobj->angle;
+	}
+	if (diff & MD_MOVEDIR)
+		mobj->movedir = READANGLE(save_p);
+	if (diff & MD_MOVECOUNT)
+		mobj->movecount = READINT32(save_p);
+	if (diff & MD_THRESHOLD)
+		mobj->threshold = READINT32(save_p);
+	if (diff & MD_LASTLOOK)
+		mobj->lastlook = READINT32(save_p);
+	else
+		mobj->lastlook = -1;
+	if (diff & MD_TARGET)
+		mobj->target = (mobj_t *)(size_t)READUINT32(save_p);
+	if (diff & MD_TRACER)
+		mobj->tracer = (mobj_t *)(size_t)READUINT32(save_p);
+	if (diff & MD_FRICTION)
+		mobj->friction = READFIXED(save_p);
+	else
+		mobj->friction = ORIG_FRICTION;
+	if (diff & MD_MOVEFACTOR)
+		mobj->movefactor = READFIXED(save_p);
+	else
+		mobj->movefactor = ORIG_FRICTION_FACTOR;
+	if (diff & MD_FUSE)
+		mobj->fuse = READINT32(save_p);
+	if (diff & MD_WATERTOP)
+		mobj->watertop = READFIXED(save_p);
+	if (diff & MD_WATERBOTTOM)
+		mobj->waterbottom = READFIXED(save_p);
+	if (diff & MD_SCALE)
+		mobj->scale = READFIXED(save_p);
+	else
+		mobj->scale = FRACUNIT;
+	if (diff & MD_DSCALE)
+		mobj->destscale = READFIXED(save_p);
+	else
+		mobj->destscale = mobj->scale;
+	if (diff2 & MD2_SCALESPEED)
+		mobj->scalespeed = READFIXED(save_p);
+	else
+		mobj->scalespeed = FRACUNIT/12;
+	if (diff2 & MD2_CUSVAL)
+		mobj->cusval = READINT32(save_p);
+	if (diff2 & MD2_CVMEM)
+		mobj->cvmem = READINT32(save_p);
+	if (diff2 & MD2_SKIN)
+		mobj->skin = &skins[READUINT8(save_p)];
+	if (diff2 & MD2_COLOR)
+		mobj->color = READUINT8(save_p);
+	if (diff2 & MD2_EXTVAL1)
+		mobj->extravalue1 = READINT32(save_p);
+	if (diff2 & MD2_EXTVAL2)
+		mobj->extravalue2 = READINT32(save_p);
+	if (diff2 & MD2_HNEXT)
+		mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p);
+	if (diff2 & MD2_HPREV)
+		mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p);
+
+	if (diff & MD_REDFLAG)
+	{
+		redflag = mobj;
+		rflagpoint = mobj->spawnpoint;
+	}
+	if (diff & MD_BLUEFLAG)
+	{
+		blueflag = mobj;
+		bflagpoint = mobj->spawnpoint;
+	}
+
+	// set sprev, snext, bprev, bnext, subsector
+	P_SetThingPosition(mobj);
+
+	mobj->mobjnum = READUINT32(save_p);
+
+	if (mobj->player)
+	{
+		if (mobj->eflags & MFE_VERTICALFLIP)
+			mobj->player->viewz = mobj->z + mobj->height - mobj->player->viewheight;
+		else
+			mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight;
+	}
+
+	P_AddThinker(&mobj->thinker);
+
+	mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
+}
+
 //
 // LoadSpecialLevelThinker
 //
@@ -2131,11 +2367,15 @@ static void LoadPusherThinker(actionf_p1 thinker)
 static inline void LoadLaserThinker(actionf_p1 thinker)
 {
 	laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
+	ffloor_t *rover = NULL;
 	ht->thinker.function.acp1 = thinker;
 	ht->sector = LoadSector(READUINT32(save_p));
-	ht->ffloor = NULL;
 	ht->sec = LoadSector(READUINT32(save_p));
 	ht->sourceline = LoadLine(READUINT32(save_p));
+	for (rover = ht->sector->ffloors; rover; rover = rover->next)
+		if (rover->secnum == (size_t)(ht->sec - sectors)
+		&& rover->master == ht->sourceline)
+			ht->ffloor = rover;
 	P_AddThinker(&ht->thinker);
 }
 
@@ -2333,13 +2573,8 @@ static void P_NetUnArchiveThinkers(void)
 {
 	thinker_t *currentthinker;
 	thinker_t *next;
-	mobj_t *mobj;
-	UINT32 diff;
-	UINT16 diff2;
-	INT32 i;
 	UINT8 tclass;
 	UINT8 restoreNum = false;
-	fixed_t z, floorz, ceilingz;
 
 	if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
 		I_Error("Bad $$$.sav at archive block Thinkers");
@@ -2350,7 +2585,6 @@ static void P_NetUnArchiveThinkers(void)
 	{
 		next = currentthinker->next;
 
-		mobj = (mobj_t *)currentthinker;
 		if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
 			P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it
 		else
@@ -2372,216 +2606,7 @@ static void P_NetUnArchiveThinkers(void)
 		switch (tclass)
 		{
 			case tc_mobj:
-				diff = READUINT32(save_p);
-				if (diff & MD_MORE)
-					diff2 = READUINT16(save_p);
-				else
-					diff2 = 0;
-
-				next = (void *)(size_t)READUINT32(save_p);
-
-				z = READFIXED(save_p); // Force this so 3dfloor problems don't arise.
-				floorz = READFIXED(save_p);
-				ceilingz = READFIXED(save_p);
-
-				if (diff & MD_SPAWNPOINT)
-				{
-					UINT16 spawnpointnum = READUINT16(save_p);
-
-					if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
-					{
-						P_SpawnHoopsAndRings(&mapthings[spawnpointnum]);
-						continue;
-					}
-
-					mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
-
-					mobj->spawnpoint = &mapthings[spawnpointnum];
-					mapthings[spawnpointnum].mobj = mobj;
-				}
-				else
-					mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
-
-				// declare this as a valid mobj as soon as possible.
-				mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
-
-				mobj->z = z;
-				mobj->floorz = floorz;
-				mobj->ceilingz = ceilingz;
-
-				if (diff & MD_TYPE)
-					mobj->type = READUINT32(save_p);
-				else
-				{
-					for (i = 0; i < NUMMOBJTYPES; i++)
-						if (mobj->spawnpoint && mobj->spawnpoint->type == mobjinfo[i].doomednum)
-							break;
-					if (i == NUMMOBJTYPES)
-					{
-						if (mobj->spawnpoint)
-							CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type %d\n", mobj->spawnpoint->type);
-						else
-							CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type NULL\n");
-						I_Error("Savegame corrupted");
-					}
-					mobj->type = i;
-				}
-				mobj->info = &mobjinfo[mobj->type];
-				if (diff & MD_POS)
-				{
-					mobj->x = READFIXED(save_p);
-					mobj->y = READFIXED(save_p);
-					mobj->angle = READANGLE(save_p);
-				}
-				else
-				{
-					mobj->x = mobj->spawnpoint->x << FRACBITS;
-					mobj->y = mobj->spawnpoint->y << FRACBITS;
-					mobj->angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT);
-				}
-				if (diff & MD_MOM)
-				{
-					mobj->momx = READFIXED(save_p);
-					mobj->momy = READFIXED(save_p);
-					mobj->momz = READFIXED(save_p);
-				} // otherwise they're zero, and the memset took care of it
-
-				if (diff & MD_RADIUS)
-					mobj->radius = READFIXED(save_p);
-				else
-					mobj->radius = mobj->info->radius;
-				if (diff & MD_HEIGHT)
-					mobj->height = READFIXED(save_p);
-				else
-					mobj->height = mobj->info->height;
-				if (diff & MD_FLAGS)
-					mobj->flags = READUINT32(save_p);
-				else
-					mobj->flags = mobj->info->flags;
-				if (diff & MD_FLAGS2)
-					mobj->flags2 = READUINT32(save_p);
-				if (diff & MD_HEALTH)
-					mobj->health = READINT32(save_p);
-				else
-					mobj->health = mobj->info->spawnhealth;
-				if (diff & MD_RTIME)
-					mobj->reactiontime = READINT32(save_p);
-				else
-					mobj->reactiontime = mobj->info->reactiontime;
-
-				if (diff & MD_STATE)
-					mobj->state = &states[READUINT16(save_p)];
-				else
-					mobj->state = &states[mobj->info->spawnstate];
-				if (diff & MD_TICS)
-					mobj->tics = READINT32(save_p);
-				else
-					mobj->tics = mobj->state->tics;
-				if (diff & MD_SPRITE)
-					mobj->sprite = READUINT16(save_p);
-				else
-					mobj->sprite = mobj->state->sprite;
-				if (diff & MD_FRAME)
-					mobj->frame = READUINT32(save_p);
-				else
-					mobj->frame = mobj->state->frame;
-				if (diff & MD_EFLAGS)
-					mobj->eflags = READUINT8(save_p);
-				if (diff & MD_PLAYER)
-				{
-					i = READUINT8(save_p);
-					mobj->player = &players[i];
-					mobj->player->mo = mobj;
-					// added for angle prediction
-					if (consoleplayer == i)
-						localangle = mobj->angle;
-					if (secondarydisplayplayer == i)
-						localangle2 = mobj->angle;
-				}
-				if (diff & MD_MOVEDIR)
-					mobj->movedir = READANGLE(save_p);
-				if (diff & MD_MOVECOUNT)
-					mobj->movecount = READINT32(save_p);
-				if (diff & MD_THRESHOLD)
-					mobj->threshold = READINT32(save_p);
-				if (diff & MD_LASTLOOK)
-					mobj->lastlook = READINT32(save_p);
-				else
-					mobj->lastlook = -1;
-				if (diff & MD_TARGET)
-					mobj->target = (mobj_t *)(size_t)READUINT32(save_p);
-				if (diff & MD_TRACER)
-					mobj->tracer = (mobj_t *)(size_t)READUINT32(save_p);
-				if (diff & MD_FRICTION)
-					mobj->friction = READFIXED(save_p);
-				else
-					mobj->friction = ORIG_FRICTION;
-				if (diff & MD_MOVEFACTOR)
-					mobj->movefactor = READFIXED(save_p);
-				else
-					mobj->movefactor = ORIG_FRICTION_FACTOR;
-				if (diff & MD_FUSE)
-					mobj->fuse = READINT32(save_p);
-				if (diff & MD_WATERTOP)
-					mobj->watertop = READFIXED(save_p);
-				if (diff & MD_WATERBOTTOM)
-					mobj->waterbottom = READFIXED(save_p);
-				if (diff & MD_SCALE)
-					mobj->scale = READFIXED(save_p);
-				else
-					mobj->scale = FRACUNIT;
-				if (diff & MD_DSCALE)
-					mobj->destscale = READFIXED(save_p);
-				else
-					mobj->destscale = mobj->scale;
-				if (diff2 & MD2_SCALESPEED)
-					mobj->scalespeed = READFIXED(save_p);
-				else
-					mobj->scalespeed = FRACUNIT/12;
-				if (diff2 & MD2_CUSVAL)
-					mobj->cusval = READINT32(save_p);
-				if (diff2 & MD2_CVMEM)
-					mobj->cvmem = READINT32(save_p);
-				if (diff2 & MD2_SKIN)
-					mobj->skin = &skins[READUINT8(save_p)];
-				if (diff2 & MD2_COLOR)
-					mobj->color = READUINT8(save_p);
-				if (diff2 & MD2_EXTVAL1)
-					mobj->extravalue1 = READINT32(save_p);
-				if (diff2 & MD2_EXTVAL2)
-					mobj->extravalue2 = READINT32(save_p);
-				if (diff2 & MD2_HNEXT)
-					mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p);
-				if (diff2 & MD2_HPREV)
-					mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p);
-
-				if (diff & MD_REDFLAG)
-				{
-					redflag = mobj;
-					rflagpoint = mobj->spawnpoint;
-				}
-				if (diff & MD_BLUEFLAG)
-				{
-					blueflag = mobj;
-					bflagpoint = mobj->spawnpoint;
-				}
-
-				// set sprev, snext, bprev, bnext, subsector
-				P_SetThingPosition(mobj);
-
-				mobj->mobjnum = READUINT32(save_p);
-
-				if (mobj->player)
-				{
-					if (mobj->eflags & MFE_VERTICALFLIP)
-						mobj->player->viewz = mobj->z + mobj->height - mobj->player->viewheight;
-					else
-						mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight;
-				}
-
-				P_AddThinker(&mobj->thinker);
-
-				mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
+				LoadMobjThinker((actionf_p1)P_MobjThinker);
 				break;
 
 			case tc_ceiling:
diff --git a/src/p_setup.c b/src/p_setup.c
index ca78db05a61f003a693ac83a92109991f3c856de..f2b0c49d84c3a1222308e130a539eff55a8cd670 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1502,22 +1502,26 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
 
 static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1)
 {
-	fixed_t bx2 = bx1 + MAPBLOCKUNITS;
-	fixed_t by2 = by1 + MAPBLOCKUNITS;
-	line_t boxline, testline;
-	vertex_t vbox, vtest;
+	fixed_t bbox[4];
+	line_t testline;
+	vertex_t vtest;
+
+	bbox[BOXRIGHT] = bx1 + MAPBLOCKUNITS;
+	bbox[BOXTOP] = by1 + MAPBLOCKUNITS;
+	bbox[BOXLEFT] = bx1;
+	bbox[BOXBOTTOM] = by1;
 
 	// Trivial rejection
-	if (cx1 < bx1 && cx2 < bx1)
+	if (cx1 < bbox[BOXLEFT] && cx2 < bbox[BOXLEFT])
 		return false;
 
-	if (cx1 > bx2 && cx2 > bx2)
+	if (cx1 > bbox[BOXRIGHT] && cx2 > bbox[BOXRIGHT])
 		return false;
 
-	if (cy1 < by1 && cy2 < by1)
+	if (cy1 < bbox[BOXBOTTOM] && cy2 < bbox[BOXBOTTOM])
 		return false;
 
-	if (cy1 > by2 && cy2 > by2)
+	if (cy1 > bbox[BOXTOP] && cy2 > bbox[BOXTOP])
 		return false;
 
 	// Rats, guess we gotta check
@@ -1527,12 +1531,11 @@ static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, f
 	cy1 <<= FRACBITS;
 	cx2 <<= FRACBITS;
 	cy2 <<= FRACBITS;
-	bx1 <<= FRACBITS;
-	by1 <<= FRACBITS;
-	bx2 <<= FRACBITS;
-	by2 <<= FRACBITS;
+	bbox[BOXTOP] <<= FRACBITS;
+	bbox[BOXBOTTOM] <<= FRACBITS;
+	bbox[BOXLEFT] <<= FRACBITS;
+	bbox[BOXRIGHT] <<= FRACBITS;
 
-	boxline.v1 = &vbox;
 	testline.v1 = &vtest;
 
 	testline.v1->x = cx1;
@@ -1540,47 +1543,12 @@ static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, f
 	testline.dx = cx2 - cx1;
 	testline.dy = cy2 - cy1;
 
-	// Test line against bottom edge of box
-	boxline.v1->x = bx1;
-	boxline.v1->y = by1;
-	boxline.dx = bx2 - bx1;
-	boxline.dy = 0;
-
-	if (P_PointOnLineSide(cx1, cy1, &boxline) != P_PointOnLineSide(cx2, cy2, &boxline)
-		&& P_PointOnLineSide(boxline.v1->x, boxline.v1->y, &testline) != P_PointOnLineSide(boxline.v1->x+boxline.dx, boxline.v1->y+boxline.dy, &testline))
-		return true;
-
-	// Right edge of box
-	boxline.v1->x = bx2;
-	boxline.v1->y = by1;
-	boxline.dx = 0;
-	boxline.dy = by2-by1;
-
-	if (P_PointOnLineSide(cx1, cy1, &boxline) != P_PointOnLineSide(cx2, cy2, &boxline)
-		&& P_PointOnLineSide(boxline.v1->x, boxline.v1->y, &testline) != P_PointOnLineSide(boxline.v1->x+boxline.dx, boxline.v1->y+boxline.dy, &testline))
-		return true;
-
-	// Top edge of box
-	boxline.v1->x = bx1;
-	boxline.v1->y = by2;
-	boxline.dx = bx2 - bx1;
-	boxline.dy = 0;
-
-	if (P_PointOnLineSide(cx1, cy1, &boxline) != P_PointOnLineSide(cx2, cy2, &boxline)
-		&& P_PointOnLineSide(boxline.v1->x, boxline.v1->y, &testline) != P_PointOnLineSide(boxline.v1->x+boxline.dx, boxline.v1->y+boxline.dy, &testline))
-		return true;
-
-	// Left edge of box
-	boxline.v1->x = bx1;
-	boxline.v1->y = by1;
-	boxline.dx = 0;
-	boxline.dy = by2-by1;
-
-	if (P_PointOnLineSide(cx1, cy1, &boxline) != P_PointOnLineSide(cx2, cy2, &boxline)
-		&& P_PointOnLineSide(boxline.v1->x, boxline.v1->y, &testline) != P_PointOnLineSide(boxline.v1->x+boxline.dx, boxline.v1->y+boxline.dy, &testline))
-		return true;
+	if ((testline.dx > 0) ^ (testline.dy > 0))
+		testline.slopetype = ST_NEGATIVE;
+	else
+		testline.slopetype = ST_POSITIVE;
 
-	return false;
+	return P_BoxOnLineSide(bbox, &testline) == -1;
 }
 
 //
@@ -2435,11 +2403,8 @@ boolean P_SetupLevel(boolean skipprecip)
 
 	// chasecam on in chaos, race, coop
 	// chasecam off in match, tag, capture the flag
-	chase = (gametype == GT_RACE || gametype == GT_COMPETITION || gametype == GT_COOP
-#ifdef CHAOSISNOTDEADYET
-		|| gametype == GT_CHAOS
-#endif
-		) || (maptol & TOL_2D);
+	chase = (gametype == GT_RACE || gametype == GT_COMPETITION || gametype == GT_COOP)
+		|| (maptol & TOL_2D);
 
 	if (!dedicated)
 	{
diff --git a/src/p_spec.c b/src/p_spec.c
index 323b93c6d8d18e2271c3d3316cc2405bf7c6a987..8228c60b3e5e085276d9a0ca23a420798b5adbcb 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -94,6 +94,7 @@ typedef struct
 	thinker_t **thinkers;
 } thinkerlist_t;
 
+static void P_SearchForDisableLinedefs(void);
 static void P_SpawnScrollers(void);
 static void P_SpawnFriction(void);
 static void P_SpawnPushers(void);
@@ -4776,6 +4777,18 @@ void P_UpdateSpecials(void)
 	}
 }
 
+static inline ffloor_t *P_GetFFloorBySec(sector_t *sec, sector_t *sec2)
+{
+	ffloor_t *rover;
+
+	if (!sec->ffloors)
+		return NULL;
+	for (rover = sec->ffloors; rover; rover = rover->next)
+		if (rover->secnum == (size_t)(sec2 - sectors))
+			return rover;
+	return NULL;
+}
+
 /** Adds a newly formed 3Dfloor structure to a sector's ffloors list.
   *
   * \param sec    Target sector.
@@ -4822,7 +4835,9 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
 	size_t i;
 
 	if (sec == sec2)
-		return false; //Don't need a fake floor on a control sector.
+		return NULL; //Don't need a fake floor on a control sector.
+	if ((ffloor = (P_GetFFloorBySec(sec, sec2))))
+		return ffloor; // If this ffloor already exists, return it
 
 	if (sec2->ceilingheight < sec2->floorheight)
 	{
@@ -5312,9 +5327,6 @@ void T_LaserFlash(laserthink_t *flash)
 	ffloor_t *ffloor = flash->ffloor;
 	sector_t *sector = flash->sector;
 
-	if (!ffloor)
-		flash->ffloor = ffloor = P_AddFakeFloor(sector, flash->sec, flash->sourceline, laserflags, NULL);
-
 	if (!ffloor || !(ffloor->flags & FF_EXISTS))
 		return;
 
@@ -5409,6 +5421,10 @@ void P_SpawnSpecials(INT32 fromnetsave)
 	thinkerlist_t *secthinkers;
 	thinker_t *th;
 
+	// This used to be used, and *should* be used in the future,
+	// but currently isn't.
+	(void)fromnetsave;
+
 	// Set the default gravity. Custom gravity overrides this setting.
 	gravity = FRACUNIT/2;
 
@@ -5480,37 +5496,12 @@ void P_SpawnSpecials(INT32 fromnetsave)
 		curWeather = PRECIP_NONE;
 
 	P_InitTagLists();   // Create xref tables for tags
+	P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line
+
 	P_SpawnScrollers(); // Add generalized scrollers
 	P_SpawnFriction();  // Friction model using linedefs
 	P_SpawnPushers();   // Pusher model using linedefs
 
-	// Look for disable linedefs
-	for (i = 0; i < numlines; i++)
-	{
-		if (lines[i].special == 6)
-		{
-			// Ability flags can disable disable linedefs now, lol
-			if (netgame || multiplayer)
-			{
-				// future: nonet flag?
-			}
-			else if (((lines[i].flags & ML_NETONLY) != ML_NETONLY)
-			&& !(players[consoleplayer].charability == CA_THOK          && (lines[i].flags & ML_NOSONIC))
-			&& !(players[consoleplayer].charability == CA_FLY           && (lines[i].flags & ML_NOTAILS))
-			&& !(players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX )))
-			{
-				for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;)
-				{
-					lines[j].tag = 0;
-					lines[j].special = 0;
-				}
-			}
-			lines[i].special = 0;
-			lines[i].tag = 0;
-		}
-	}
-
-
 	// Look for thinkers that affect FOFs, and sort them by sector
 
 	secthinkers = Z_Calloc(numsectors * sizeof(thinkerlist_t), PU_STATIC, NULL);
@@ -5993,12 +5984,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 160: // Float/bob platform
-				sec = sides[*lines[i].sidenum].sector - sectors;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-				{
-					P_AddFakeFloor(&sectors[s], &sectors[sec], lines + i,
-						FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB, secthinkers);
-				}
+				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB, secthinkers);
 				break;
 
 			case 170: // Crumbling platform
@@ -6043,13 +6029,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 176: // Air bobbing platform that will crumble and bob on the water when it falls and hits
-				sec = sides[*lines[i].sidenum].sector - sectors;
+				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers);
 				lines[i].flags |= ML_BLOCKMONSTERS;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-				{
-					P_AddFakeFloor(&sectors[s], &sectors[sec], lines + i,
-						FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers);
-				}
 				P_AddOldAirbob(lines[i].frontsector, lines + i, true);
 				break;
 
@@ -6061,21 +6042,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 178: // Crumbling platform that will float when it hits water
-				sec = sides[*lines[i].sidenum].sector - sectors;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-				{
-					P_AddFakeFloor(&sectors[s], &sectors[sec], lines + i,
-						FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CRUMBLE|FF_FLOATBOB, secthinkers);
-				}
+				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CRUMBLE|FF_FLOATBOB, secthinkers);
 				break;
 
 			case 179: // Crumbling platform that will float when it hits water, but not return
-				sec = sides[*lines[i].sidenum].sector - sectors;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-				{
-					P_AddFakeFloor(&sectors[s], &sectors[sec], lines + i,
-						FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_FLOATBOB|FF_NORETURN, secthinkers);
-				}
+				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_FLOATBOB|FF_NORETURN, secthinkers);
 				break;
 
 			case 180: // Air bobbing platform that will crumble
@@ -6158,14 +6129,13 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 202: // Fog
+				ffloorflags = FF_EXISTS|FF_RENDERALL|FF_FOG|FF_BOTHPLANES|FF_INVERTPLANES|FF_ALLSIDES|FF_INVERTSIDES|FF_CUTEXTRA|FF_EXTRA|FF_DOUBLESHADOW|FF_CUTSPRITES;
 				sec = sides[*lines[i].sidenum].sector - sectors;
 				// SoM: Because it's fog, check for an extra colormap and set
 				// the fog flag...
 				if (sectors[sec].extra_colormap)
 					sectors[sec].extra_colormap->fog = 1;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-					P_AddFakeFloor(&sectors[s], &sectors[sec], lines + i,
-						FF_EXISTS|FF_RENDERALL|FF_FOG|FF_BOTHPLANES|FF_INVERTPLANES|FF_ALLSIDES|FF_INVERTSIDES|FF_CUTEXTRA|FF_EXTRA|FF_DOUBLESHADOW|FF_CUTSPRITES, secthinkers);
+				P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
 				break;
 
 			case 220: // Like opaque water, but not swimmable. (Good for snow effect on FOFs)
@@ -6195,12 +6165,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 250: // Mario Block
-				sec = sides[*lines[i].sidenum].sector - sectors;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-				{
-					P_AddFakeFloor(&sectors[s], &sectors[sec], lines + i,
-						FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO, secthinkers);
-				}
+				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO, secthinkers);
 				break;
 
 			case 251: // A THWOMP!
@@ -6247,13 +6212,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 258: // Laser block
-				if (!fromnetsave) // This creates a FOF which disrupts net saves
-				{
-					sec = sides[*lines[i].sidenum].sector - sectors;
+				sec = sides[*lines[i].sidenum].sector - sectors;
 
-					for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-						EV_AddLaserThinker(&sectors[s], &sectors[sec], lines + i, secthinkers);
-				}
+				// No longer totally disrupts netgames
+				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
+					EV_AddLaserThinker(&sectors[s], &sectors[sec], lines + i, secthinkers);
 				break;
 
 			case 259: // Make-Your-Own FOF!
@@ -7720,3 +7683,39 @@ static void P_SpawnPushers(void)
 				break;
 		}
 }
+
+static void P_SearchForDisableLinedefs(void)
+{
+	size_t i;
+	INT32 j;
+
+	// Look for disable linedefs
+	for (i = 0; i < numlines; i++)
+	{
+		if (lines[i].special == 6)
+		{
+			// Remove special
+			// Do *not* remove tag. That would mess with the tag lists
+			// that P_InitTagLists literally just created!
+			lines[i].special = 0;
+
+			// Ability flags can disable disable linedefs now, lol
+			if (netgame || multiplayer)
+			{
+				// future: nonet flag?
+			}
+			else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
+				continue; // Net-only never triggers in single player
+			else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
+				continue;
+			else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
+				continue;
+			else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))
+				continue;
+
+			// Disable any linedef specials with our tag.
+			for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;)
+				lines[j].special = 0;
+		}
+	}
+}
diff --git a/src/p_tick.c b/src/p_tick.c
index 3b7d3683bfa70bc81ca7898d418a9416a42e40ad..2973505f3c71fc4b564ceff566a741481b52ba95 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -587,7 +587,7 @@ void P_Ticker(boolean run)
 	}
 
 	// Check for pause or menu up in single player
-	if (paused || P_MenuActivePause())
+	if (paused || P_AutoPause())
 		return;
 
 	postimgtype = postimgtype2 = postimg_none;
diff --git a/src/p_user.c b/src/p_user.c
index 3c2d34a6ecc15e8258caf7a6a28ab762f6a28c1c..6844d2cba37560905f15a2ab13b99ab3df7e0081 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -160,15 +160,17 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move)
 	return FixedMul(move, FINESINE(angle));
 }
 
-boolean P_MenuActivePause(void)
+//
+// P_AutoPause
+// Returns true when gameplay should be halted even if the game isn't necessarily paused.
+//
+boolean P_AutoPause(void)
 {
-	if (netgame || !menuactive)
-		return false;
-
-	if (modeattacking)
+	// Don't pause even on menu-up or focus-lost in netgames or record attack
+	if (netgame || modeattacking)
 		return false;
 
-	return true;
+	return (menuactive || window_notinfocus);
 }
 
 //
@@ -328,14 +330,10 @@ void P_GiveEmerald(boolean spawnObj)
 //
 // P_ResetScore
 //
-// This is called when your chain is reset. If in
-// Chaos mode, it displays what chain you got.
+// This is called when your chain is reset.
 void P_ResetScore(player_t *player)
 {
-#ifdef CHAOSISNOTDEADYET
-	if (gametype == GT_CHAOS && player->scoreadd >= 5)
-		CONS_Printf(M_GetText("%s got a chain of %u!\n"), player_names[player-players], player->scoreadd);
-#endif
+	// Formally a host for Chaos mode behavior
 
 	player->scoreadd = 0;
 }
@@ -974,9 +972,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 	// Transformation animation
 	P_SetPlayerMobjState(player->mo, S_PLAY_SUPERTRANS1);
 
-	player->mo->momx >>= 1;
-	player->mo->momy >>= 1;
-	player->mo->momz >>= 1;
+	player->mo->momx = player->mo->momy = player->mo->momz = 0;
 
 	if (giverings)
 	{
@@ -2542,6 +2538,7 @@ static void P_DoClimbing(player_t *player)
 			thinker_t *think;
 			scroll_t *scroller;
 			angle_t sideangle;
+			fixed_t dx, dy;
 
 			for (think = thinkercap.next; think != &thinkercap; think = think->next)
 			{
@@ -2556,14 +2553,25 @@ static void P_DoClimbing(player_t *player)
 				if (scroller->affectee != player->lastsidehit)
 					continue;
 
+				if (scroller->accel)
+				{
+					dx = scroller->vdx;
+					dy = scroller->vdy;
+				}
+				else
+				{
+					dx = scroller->dx;
+					dy = scroller->dy;
+				}
+
 				if (cmd->forwardmove != 0)
 				{
-					player->mo->momz += scroller->dy;
+					player->mo->momz += dy;
 					climb = true;
 				}
 				else
 				{
-					player->mo->momz = scroller->dy;
+					player->mo->momz = dy;
 					climb = false;
 				}
 
@@ -2571,12 +2579,12 @@ static void P_DoClimbing(player_t *player)
 
 				if (cmd->sidemove != 0)
 				{
-					P_Thrust(player->mo, sideangle, scroller->dx);
+					P_Thrust(player->mo, sideangle, dx);
 					climb = true;
 				}
 				else
 				{
-					P_InstaThrust(player->mo, sideangle, scroller->dx);
+					P_InstaThrust(player->mo, sideangle, dx);
 					climb = false;
 				}
 			}
@@ -2654,6 +2662,125 @@ static void P_DoClimbing(player_t *player)
 	}
 }
 
+//
+// PIT_CheckSolidsTeeter
+// AKA: PIT_HacksToStopPlayersTeeteringOnGargoyles
+//
+
+static mobj_t *teeterer; // the player checking for teetering
+static boolean solidteeter; // saves whether the player can teeter on this or not
+static fixed_t highesttop; // highest floor found so far
+// reserved for standing on multiple objects
+static boolean couldteeter;
+static fixed_t teeterxl, teeterxh;
+static fixed_t teeteryl, teeteryh;
+
+static boolean PIT_CheckSolidsTeeter(mobj_t *thing)
+{
+	fixed_t blockdist;
+	fixed_t tiptop = FixedMul(MAXSTEPMOVE, teeterer->scale);
+	fixed_t thingtop = thing->z + thing->height;
+	fixed_t teeterertop = teeterer->z + teeterer->height;
+
+	if (!teeterer || !thing)
+		return true;
+
+	if (!(thing->flags & MF_SOLID))
+		return true;
+
+	if (thing->flags & MF_NOCLIP)
+		return true;
+
+	if (thing == teeterer)
+		return true;
+
+	if (thing->player && cv_tailspickup.value && gametype != GT_HIDEANDSEEK)
+		return true;
+
+	blockdist = teeterer->radius + thing->radius;
+
+	if (abs(thing->x - teeterer->x) >= blockdist || abs(thing->y - teeterer->y) >= blockdist)
+		return true; // didn't hit it
+
+	if (teeterer->eflags & MFE_VERTICALFLIP)
+	{
+		if (thingtop < teeterer->z)
+			return true;
+		if (thing->z > highesttop)
+			return true;
+		highesttop = thing->z;
+		if (thing->z > teeterertop + tiptop)
+		{
+			solidteeter = true;
+			return true;
+		}
+	}
+	else
+	{
+		if (thing->z > teeterertop)
+			return true;
+		if (thingtop < highesttop)
+			return true;
+		highesttop = thingtop;
+		if (thingtop < teeterer->z - tiptop)
+		{
+			solidteeter = true;
+			return true;
+		}
+	}
+
+	// are you standing on this?
+	if ((teeterer->eflags & MFE_VERTICALFLIP && thing->z - FixedMul(FRACUNIT, teeterer->scale) == teeterertop)
+	|| (!(teeterer->eflags & MFE_VERTICALFLIP) && thingtop + FixedMul(FRACUNIT, teeterer->scale) == teeterer->z))
+	{
+		fixed_t teeterdist = thing->radius - FixedMul(5*FRACUNIT, teeterer->scale);
+		// how far are you from the edge?
+		if (abs(teeterer->x - thing->x) > teeterdist || abs(teeterer->y - thing->y) > teeterdist)
+		{
+			if (couldteeter) // player is standing on another object already, see if we can stand on both and not teeter!
+			{
+				if (thing->x - teeterdist < teeterxl)
+					teeterxl = thing->x - teeterdist;
+				if (thing->x + teeterdist > teeterxh)
+					teeterxh = thing->x + teeterdist;
+				if (thing->y - teeterdist < teeteryl)
+					teeteryl = thing->y - teeterdist;
+				if (thing->y + teeterdist > teeteryh)
+					teeteryh = thing->y + teeterdist;
+
+				if (teeterer->x < teeterxl)
+					return true;
+				if (teeterer->x > teeterxh)
+					return true;
+				if (teeterer->y < teeteryl)
+					return true;
+				if (teeterer->y > teeteryh)
+					return true;
+
+				solidteeter = false; // you can stop teetering now!
+				couldteeter = false; // just in case...
+				return false;
+			}
+			else
+			{
+				// too far! don't change teeter status though
+				// save teeter x/y limits to bring up later
+				teeterxl = thing->x - teeterdist;
+				teeterxh = thing->x + teeterdist;
+				teeteryl = thing->y - teeterdist;
+				teeteryh = thing->y + teeterdist;
+			}
+			couldteeter = true;
+			return true;
+		}
+		solidteeter = false;
+		couldteeter = false;
+		return false; // you're definitely not teetering, that's the end of the matter
+	}
+	solidteeter = false;
+	return true; // you're not teetering but it's not neccessarily over, YET
+}
+
 //
 // P_DoTeeter
 //
@@ -2828,18 +2955,18 @@ static void P_DoTeeter(player_t *player)
 		}
 	}
 
-#ifdef POLYOBJECTS
-	// Polyobjects
 	{
 		INT32 bx, by, xl, xh, yl, yh;
 
-		validcount++;
-
 		yh = (unsigned)(player->mo->y + player->mo->radius - bmaporgy)>>MAPBLOCKSHIFT;
 		yl = (unsigned)(player->mo->y - player->mo->radius - bmaporgy)>>MAPBLOCKSHIFT;
 		xh = (unsigned)(player->mo->x + player->mo->radius - bmaporgx)>>MAPBLOCKSHIFT;
 		xl = (unsigned)(player->mo->x - player->mo->radius - bmaporgx)>>MAPBLOCKSHIFT;
 
+	// Polyobjects
+#ifdef POLYOBJECTS
+		validcount++;
+
 		for (by = yl; by <= yh; by++)
 			for (bx = xl; bx <= xh; bx++)
 			{
@@ -2900,16 +3027,12 @@ static void P_DoTeeter(player_t *player)
 							}
 
 							if (polybottom > player->mo->z + player->mo->height + tiptop
-									|| (polybottom < player->mo->z
-									&& player->mo->z + player->mo->height < player->mo->ceilingz - tiptop))
-							{
+							|| (polybottom < player->mo->z
+							&& player->mo->z + player->mo->height < player->mo->ceilingz - tiptop))
 								teeter = true;
-								roverfloor = true;
-							}
 							else
 							{
 								teeter = false;
-								roverfloor = true;
 								break;
 							}
 						}
@@ -2922,16 +3045,12 @@ static void P_DoTeeter(player_t *player)
 							}
 
 							if (polytop < player->mo->z - tiptop
-									|| (polytop > player->mo->z + player->mo->height
-									&& player->mo->z > player->mo->floorz + tiptop))
-							{
+							|| (polytop > player->mo->z + player->mo->height
+							&& player->mo->z > player->mo->floorz + tiptop))
 								teeter = true;
-								roverfloor = true;
-							}
 							else
 							{
 								teeter = false;
-								roverfloor = true;
 								break;
 							}
 						}
@@ -2939,8 +3058,27 @@ static void P_DoTeeter(player_t *player)
 					plink = (polymaplink_t *)(plink->link.next);
 				}
 			}
-	}
 #endif
+		if (teeter) // only bother with objects as a last resort if you were already teetering
+		{
+			mobj_t *oldtmthing = tmthing;
+			tmthing = teeterer = player->mo;
+			teeterxl = teeterxh = player->mo->x;
+			teeteryl = teeteryh = player->mo->y;
+			couldteeter = false;
+			solidteeter = teeter;
+			for (by = yl; by <= yh; by++)
+				for (bx = xl; bx <= xh; bx++)
+				{
+					highesttop = INT32_MIN;
+					if (!P_BlockThingsIterator(bx, by, PIT_CheckSolidsTeeter))
+						goto teeterdone; // we've found something that stops us teetering at all, how about we stop already
+				}
+teeterdone:
+			teeter = solidteeter;
+			tmthing = oldtmthing; // restore old tmthing, goodness knows what the game does with this before mobj thinkers
+		}
+	}
 	if (teeter)
 	{
 		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]))
diff --git a/src/r_bsp.c b/src/r_bsp.c
index e5e0942e3909f27c1a47b22ab473ecf95e04c149..e967e28cef3e194ebb5e43dcf652f9e2f91061e5 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -572,8 +572,8 @@ static boolean R_CheckBBox(fixed_t *bspcoord)
 	py2 = bspcoord[checkcoord[boxpos][3]];
 
 	// check clip list for an open space
-	angle1 = R_PointToAngle(px1, py1) - viewangle;
-	angle2 = R_PointToAngle(px2, py2) - viewangle;
+	angle1 = R_PointToAngle2(viewx>>1, viewy>>1, px1>>1, py1>>1) - viewangle;
+	angle2 = R_PointToAngle2(viewx>>1, viewy>>1, px2>>1, py2>>1) - viewangle;
 
 	span = angle1 - angle2;
 
@@ -702,21 +702,62 @@ static int R_PolysegCompare(const void *p1, const void *p2)
 {
 	const seg_t *seg1 = *(const seg_t * const *)p1;
 	const seg_t *seg2 = *(const seg_t * const *)p2;
-	fixed_t dist1, dist2;
+	fixed_t dist1v1, dist1v2, dist2v1, dist2v2;
 
 	// TODO might be a better way to get distance?
-#define vxdist(v) FixedMul(R_PointToDist(v->x, v->y), FINECOSINE((R_PointToAngle(v->x, v->y)-viewangle)>>ANGLETOFINESHIFT))+0xFFFFFFF
+#define pdist(x, y) (FixedMul(R_PointToDist(x, y), FINECOSINE((R_PointToAngle(x, y)-viewangle)>>ANGLETOFINESHIFT))+0xFFFFFFF)
+#define vxdist(v) pdist(v->x, v->y)
 
-	dist1 = min(vxdist(seg1->v1), vxdist(seg1->v2));
-	dist2 = min(vxdist(seg2->v1), vxdist(seg2->v2));
+	dist1v1 = vxdist(seg1->v1);
+	dist1v2 = vxdist(seg1->v2);
+	dist2v1 = vxdist(seg2->v1);
+	dist2v2 = vxdist(seg2->v2);
 
-	if (dist1 == dist2) { // Segs connect toward the front, so use the back verts to determine order!
-		dist1 = max(vxdist(seg1->v1), vxdist(seg1->v2));
-		dist2 = max(vxdist(seg2->v1), vxdist(seg2->v2));
+	if (min(dist1v1, dist1v2) != min(dist2v1, dist2v2))
+		return min(dist1v1, dist1v2) - min(dist2v1, dist2v2);
+
+	{ // That didn't work, so now let's try this.......
+		fixed_t delta1, delta2, x1, y1, x2, y2;
+		vertex_t *near1, *near2, *far1, *far2; // wherever you are~
+
+		delta1 = R_PointToDist2(seg1->v1->x, seg1->v1->y, seg1->v2->x, seg1->v2->y);
+		delta2 = R_PointToDist2(seg2->v1->x, seg2->v1->y, seg2->v2->x, seg2->v2->y);
+
+		delta1 = FixedDiv(128<<FRACBITS, delta1);
+		delta2 = FixedDiv(128<<FRACBITS, delta2);
+
+		if (dist1v1 < dist1v2)
+		{
+			near1 = seg1->v1;
+			far1 = seg1->v2;
+		}
+		else
+		{
+			near1 = seg1->v2;
+			far1 = seg1->v1;
+		}
+
+		if (dist2v1 < dist2v2)
+		{
+			near2 = seg2->v1;
+			far2 = seg2->v2;
+		}
+		else
+		{
+			near2 = seg2->v2;
+			far2 = seg2->v1;
+		}
+
+		x1 = near1->x + FixedMul(far1->x-near1->x, delta1);
+		y1 = near1->y + FixedMul(far1->y-near1->y, delta1);
+
+		x2 = near2->x + FixedMul(far2->x-near2->x, delta2);
+		y2 = near2->y + FixedMul(far2->y-near2->y, delta2);
+
+		return pdist(x1, y1)-pdist(x2, y2);
 	}
 #undef vxdist
-
-	return dist1-dist2;
+#undef pdist
 }
 
 //
@@ -835,6 +876,7 @@ static void R_Subsector(size_t num)
 
 	numffloors = 0;
 	ffloor[numffloors].plane = NULL;
+	ffloor[numffloors].polyobj = NULL;
 	if (frontsector->ffloors)
 	{
 		ffloor_t *rover;
@@ -854,6 +896,7 @@ static void R_Subsector(size_t num)
 			}
 
 			ffloor[numffloors].plane = NULL;
+			ffloor[numffloors].polyobj = NULL;
 			if (*rover->bottomheight <= frontsector->ceilingheight
 				&& *rover->bottomheight >= frontsector->floorheight
 				&& ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES))
@@ -872,6 +915,7 @@ static void R_Subsector(size_t num)
 			if (numffloors >= MAXFFLOORS)
 				break;
 			ffloor[numffloors].plane = NULL;
+			ffloor[numffloors].polyobj = NULL;
 			if (*rover->topheight >= frontsector->floorheight
 				&& *rover->topheight <= frontsector->ceilingheight
 				&& ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES))
diff --git a/src/r_data.c b/src/r_data.c
index 930b70bf5d03d563ea6749d68b86e7e754d2dbd1..0aba427505e4ad9083ec991902fb13818a6d118f 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -946,10 +946,12 @@ static void R_InitExtraColormaps(void)
 	CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps));
 }
 
+// 12/14/14 -- only take flats in F_START/F_END
 lumpnum_t R_GetFlatNumForName(const char *name)
 {
-	lumpnum_t lump = W_CheckNumForName(name);
-
+	lumpnum_t lump = W_CheckNumForNameInBlock(name, "F_START", "F_END");
+	if (lump == LUMPERROR)
+		lump = W_CheckNumForNameInBlock(name, "FF_START", "FF_END"); // deutex, some other old things
 	if (lump == LUMPERROR)
 	{
 		if (strcmp(name, SKYFLATNAME))
diff --git a/src/r_main.c b/src/r_main.c
index f2c641f6af914669e9a2d7b60a16760db90649d1..ffd4d5d504c3b6c98e9c02894c41ec1ca0340d7c 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -162,6 +162,7 @@ consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NU
 consvar_t cv_showhud = {"showhud", "Yes", CV_CALL,  CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
+consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@@ -1406,6 +1407,7 @@ void R_RegisterEngineStuff(void)
 		return;
 
 	CV_RegisterVar(&cv_precipdensity);
+	CV_RegisterVar(&cv_translucency);
 	CV_RegisterVar(&cv_drawdist);
 	CV_RegisterVar(&cv_drawdist_nights);
 	CV_RegisterVar(&cv_drawdist_precip);
diff --git a/src/r_main.h b/src/r_main.h
index 0d3f2def5222b8e60340ed6d8ab662ef0d3f2aae..13383451daf6ad3ffc16428d30e38b500575f2ab 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -88,6 +88,7 @@ extern consvar_t cv_homremoval;
 extern consvar_t cv_chasecam, cv_chasecam2;
 extern consvar_t cv_flipcam, cv_flipcam2;
 extern consvar_t cv_shadow, cv_shadowoffs;
+extern consvar_t cv_translucency;
 extern consvar_t cv_precipdensity, cv_drawdist, cv_drawdist_nights, cv_drawdist_precip;
 extern consvar_t cv_skybox;
 extern consvar_t cv_tailspickup;
diff --git a/src/r_segs.c b/src/r_segs.c
index c73cfdf9faeceb9445c22b4538e7798f00000056..7467f532472ae35d9eca14373ee9faf95e2e7b45 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -528,7 +528,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 						else
 							xwalllights = scalelight[rlight->lightnum];
 
-						pindex = spryscale>>LIGHTSCALESHIFT;
+						pindex = FixedMul(spryscale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
 
 						if (pindex >= MAXLIGHTSCALE)
 							pindex = MAXLIGHTSCALE - 1;
@@ -573,7 +573,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 				}
 
 				// calculate lighting
-				pindex = spryscale>>LIGHTSCALESHIFT;
+				pindex = FixedMul(spryscale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
 
 				if (pindex >= MAXLIGHTSCALE)
 					pindex = MAXLIGHTSCALE - 1;
@@ -1130,8 +1130,8 @@ static void R_RenderSegLoop (void)
 			for (i = 0; i < numffloors; i++)
 			{
 #ifdef POLYOBJECTS_PLANES
-				//if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg))
-					//continue; // Causes issues with FOF planes in The Wall -Red
+				if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
+					continue;
 
 				// FIXME hack to fix planes disappearing when a seg goes behind the camera. This NEEDS to be changed to be done properly. -Red
 				if (curline->polyseg) {
@@ -1203,7 +1203,7 @@ static void R_RenderSegLoop (void)
 		if (segtextured)
 		{
 			// calculate lighting
-			pindex = rw_scale>>LIGHTSCALESHIFT;
+			pindex = FixedMul(rw_scale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
 
 			if (pindex >=  MAXLIGHTSCALE)
 				pindex = MAXLIGHTSCALE-1;
@@ -1238,7 +1238,7 @@ static void R_RenderSegLoop (void)
 				else
 					xwalllights = scalelight[lightnum];
 
-				pindex = rw_scale>>LIGHTSCALESHIFT;
+				pindex = FixedMul(rw_scale, FixedDiv(640, vid.width))>>LIGHTSCALESHIFT;
 
 				if (pindex >=  MAXLIGHTSCALE)
 					pindex = MAXLIGHTSCALE-1;
@@ -1359,9 +1359,9 @@ static void R_RenderSegLoop (void)
 
 		for (i = 0; i < numffloors; i++)
 		{
-#if 0 //#ifdef POLYOBJECTS_PLANES
-			if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg))
-				continue; // Causes issues with FOF planes in The Wall -Red
+#ifdef POLYOBJECTS_PLANES
+			if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
+				continue;
 #endif
 
 			ffloor[i].f_frac += ffloor[i].f_step;
@@ -1371,9 +1371,9 @@ static void R_RenderSegLoop (void)
 		{
 			INT32 y_w;
 
-#if 0 //#ifdef POLYOBJECTS_PLANES
-			if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg))
-				continue; // Causes issues with FOF planes in The Wall -Red
+#ifdef POLYOBJECTS_PLANES
+			if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
+				continue;
 #endif
 			y_w = ffloor[i].b_frac >> HEIGHTBITS;
 
@@ -1520,9 +1520,9 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	{
 		for (i = 0; i < numffloors; i++)
 		{
-#if 0 //#ifdef POLYOBJECTS_PLANES
-			if (ds_p->curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != ds_p->curline->polyseg))
-				continue; // Causes issues with FOF planes in The Wall -Red
+#ifdef POLYOBJECTS_PLANES
+			if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg))
+				continue;
 #endif
 			ffloor[i].f_pos = ffloor[i].height - viewz;
 		}
@@ -2021,9 +2021,9 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	{
 		for (i = 0; i < numffloors; i++)
 		{
-#if 0 //#ifdef POLYOBJECTS_PLANES
-			if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg))
-				continue; // Causes issues with FOF planes in The Wall -Red
+#ifdef POLYOBJECTS_PLANES
+			if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg))
+				continue;
 #endif
 
 			ffloor[i].f_pos >>= 4;
@@ -2126,7 +2126,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 #ifdef POLYOBJECTS_PLANES
 			if (curline->polyseg && frontsector && (curline->polyseg->flags & POF_RENDERPLANES))
 			{
-				if (i < MAXFFLOORS && backsector->floorheight <= frontsector->ceilingheight &&
+				while (i < numffloors && ffloor[i].polyobj != curline->polyseg) i++;
+				if (i < numffloors && backsector->floorheight <= frontsector->ceilingheight &&
 					backsector->floorheight >= frontsector->floorheight &&
 					(viewz < backsector->floorheight))
 				{
@@ -2142,7 +2143,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 					ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
 					i++;
 				}
-				if (i < MAXFFLOORS && backsector->ceilingheight >= frontsector->floorheight &&
+				if (i < numffloors && backsector->ceilingheight >= frontsector->floorheight &&
 					backsector->ceilingheight <= frontsector->ceilingheight &&
 					(viewz > backsector->ceilingheight))
 				{
diff --git a/src/r_things.c b/src/r_things.c
index 6372ddb4c06f122b06499864d2ec39528aa98590..9a8b1319bd1ee226c5f238fae706233152d28483 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1293,7 +1293,9 @@ static void R_ProjectSprite(mobj_t *thing)
 	vis->transmap = NULL;
 
 	// specific translucency
-	if (thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
+	if (!cv_translucency.value)
+		; // no translucency
+	else if (thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
 		vis->transmap = ((tr_trans80-1)<<FF_TRANSSHIFT) + transtables; // because now the translucency is set through FF_TRANSMASK
 	else if (thing->frame & FF_TRANSMASK)
 		vis->transmap = (thing->frame & FF_TRANSMASK) - 0x10000 + transtables;
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b4eeeeb5fb1c0e778be6a6a16758e0c116d9ad53
--- /dev/null
+++ b/src/sdl/CMakeLists.txt
@@ -0,0 +1,276 @@
+# Declare SDL2 interface sources
+
+set(SRB2_CONFIG_SDL2_USEMIXER ON CACHE BOOL "Use SDL2_mixer or regular sdl sound")
+
+if(${SRB2_CONFIG_SDL2_USEMIXER})
+	find_package(SDL2_mixer)
+	if(${SDL2_MIXER_FOUND})
+		set(SRB2_HAVE_MIXER ON)
+		set(SRB2_SDL2_SOUNDIMPL mixer_sound.c)
+	else()
+		message(WARNING "You specified that SDL2_mixer is available, but it was not found. Falling back to sdl sound.")
+		set(SRB2_SDL2_SOUNDIMPL sdl_sound.c)
+	endif()
+else()
+	set(SRB2_SDL2_SOUNDIMPL sdl_sound.c)
+endif()
+
+set(SRB2_SDL2_SOURCES
+	dosstr.c
+	endtxt.c
+	hwsym_sdl.c
+	i_cdmus.c
+	i_main.c
+	i_net.c
+	i_system.c
+	i_ttf.c
+	i_video.c
+	#IMG_xpm.c
+	ogl_sdl.c
+
+	${SRB2_SDL2_SOUNDIMPL}
+)
+
+set(SRB2_SDL2_HEADERS
+	endtxt.h
+	hwsym_sdl.h
+	i_ttf.h
+	ogl_sdl.h
+	sdlmain.h
+)
+
+prepend_sources(SRB2_SDL2_SOURCES)
+prepend_sources(SRB2_SDL2_HEADERS)
+
+# Dependency
+find_package(SDL2)
+
+if(${SDL2_FOUND})
+	set(SRB2_SDL2_TOTAL_SOURCES
+		${SRB2_CORE_SOURCES}
+		${SRB2_CORE_HEADERS}
+		${SRB2_SDL2_SOURCES}
+		${SRB2_SDL2_HEADERS}
+	)
+
+	if(${SRB2_CONFIG_HWRENDER})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${SRB2_HWRENDER_SOURCES}
+			${SRB2_HWRENDER_HEADERS}
+			${SRB2_R_OPENGL_SOURCES}
+			${SRB2_R_OPENGL_HEADERS}
+		)
+	endif()
+
+	if(${SRB2_CONFIG_HAVE_BLUA})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${SRB2_LUA_SOURCES}
+			${SRB2_LUA_HEADERS}
+			${SRB2_BLUA_SOURCES}
+			${SRB2_BLUA_HEADERS}
+		)
+	endif()
+
+	if(${SRB2_USEASM})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${SRB2_NASM_SOURCES}
+		)
+		if(MSVC)
+			set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+				${SRB2_NASM_OBJECTS}
+			)
+			set_source_files_properties(${SRB2_NASM_OBJECTS} PROPERTIES GENERATED ON)
+		else()
+			list(APPEND SRB2_SDL2_TOTAL_SOURCES ${SRB2_ASM_SOURCES})
+			set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES LANGUAGE C)
+			set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
+		endif()
+
+	endif()
+
+	if(${CMAKE_SYSTEM} MATCHES Windows)
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${CMAKE_SOURCE_DIR}/src/win32/win_dbg.c
+			${CMAKE_SOURCE_DIR}/src/win32/Srb2win.rc
+		)
+	endif()
+	if(NOT CLANG)
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			${CMAKE_SOURCE_DIR}/src/string.c
+		)
+	endif()
+
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
+		set(MACOSX_BUNDLE_ICON_FILE Srb2mac.icns)
+		set_source_files_properties(macosx/Srb2mac.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+			macosx/mac_alert.c
+			macosx/mac_alert.h
+			macosx/mac_resources.c
+			macosx/mac_resources.h
+			macosx/Srb2mac.icns
+		)
+	endif()
+
+	if(CLANG)
+		add_executable(${SRB2_SDL2_EXE_NAME} MACOSX_BUNDLE ${SRB2_SDL2_TOTAL_SOURCES})
+		add_framework(CoreFoundation ${SRB2_SDL2_EXE_NAME})
+		add_framework(SDL2 ${SRB2_SDL2_EXE_NAME})
+		add_framework(SDL2_mixer ${SRB2_SDL2_EXE_NAME})
+		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			${PNG_LIBRARIES}
+			${ZLIB_LIBRARIES}
+			${OPENGL_LIBRARIES}
+		)
+		set_target_properties(${SRB2_SDL2_EXE_NAME} PROPERTIES OUTPUT_NAME "Sonic Robo Blast 2")
+	else()
+		add_executable(${SRB2_SDL2_EXE_NAME} WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
+
+		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			${SDL2_LIBRARIES}
+			${SDL2_MIXER_LIBRARIES}
+			${PNG_LIBRARIES}
+			${ZLIB_LIBRARIES}
+			${OPENGL_LIBRARIES}
+		)
+
+		if(${CMAKE_SYSTEM} MATCHES Linux)
+			target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+				m
+				rt
+			)
+		endif()
+
+	endif()
+
+	if(${SRB2_USEASM})
+		if(${SRB2_CONFIG_YASM})
+			set(ASM_ASSEMBLER_TEMP ${CMAKE_ASM_YASM_COMPILER})
+			set(ASM_ASSEMBLER_OBJFORMAT ${CMAKE_ASM_YASM_OBJECT_FORMAT})
+			set_source_files_properties(${SRB2_NASM_SOURCES} LANGUAGE ASM_YASM)
+		else()
+			set(ASM_ASSEMBLER_TEMP ${CMAKE_ASM_NASM_COMPILER})
+			set(ASM_ASSEMBLER_OBJFORMAT ${CMAKE_ASM_NASM_OBJECT_FORMAT})
+			set_source_files_properties(${SRB2_NASM_SOURCES} LANGUAGE ASM_NASM)
+		endif()
+
+		if(MSVC)
+			# using assembler with msvc doesn't work, must do it manually
+			foreach(ASMFILE ${SRB2_NASM_SOURCES})
+				get_filename_component(ASMFILE_NAME ${ASMFILE} NAME_WE)
+				set(ASMFILE_NAME ${ASMFILE_NAME}.obj)
+				add_custom_command(TARGET ${SRB2_SDL2_EXE_NAME} PRE_LINK
+					COMMAND ${ASM_ASSEMBLER_TEMP} ARGS -f ${ASM_ASSEMBLER_OBJFORMAT} -o ${CMAKE_CURRENT_BINARY_DIR}/${ASMFILE_NAME} ${ASMFILE}
+					COMMENT "assemble ${ASMFILE_NAME}."
+				)
+			endforeach()
+		endif()
+	endif()
+
+	set_target_properties(${SRB2_SDL2_EXE_NAME} PROPERTIES VERSION ${SRB2_VERSION})
+
+	if(${CMAKE_SYSTEM} MATCHES Windows)
+		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			ws2_32
+		)
+		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+			-U_WINDOWS
+		)
+	endif()
+
+	if(MSVC)
+		find_package(SDL2_MAIN REQUIRED)
+		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			${SDL2_MAIN_LIBRARIES}
+		)
+		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+			/Umain
+			/D_CRT_SECURE_NO_WARNINGS # something about string functions.
+			/D_CRT_NONSTDC_NO_DEPRECATE
+			/DSDLMAIN
+			/D_WINSOCK_DEPRECATED_NO_WARNINGS # Don't care
+		)
+	endif()
+
+	target_include_directories(${SRB2_SDL2_EXE_NAME} PRIVATE
+		${SDL2_INCLUDE_DIRS}
+		${SDL2_MIXER_INCLUDE_DIRS}
+		${PNG_INCLUDE_DIRS}
+		${ZLIB_INCLUDE_DIRS}
+		${OPENGL_INCLUDE_DIRS}
+	)
+
+	if(${SRB2_HAVE_MIXER})
+		target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+	endif()
+
+	target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE
+		-DHAVE_SDL
+	)
+
+	## strip debug symbols into separate file when using gcc
+	if(CMAKE_COMPILER_IS_GNUCC)
+		if(${CMAKE_BUILD_TYPE} MATCHES Debug)
+			message(STATUS "Will make separate debug symbols in *.debug")
+			add_custom_command(TARGET ${SRB2_SDL2_EXE_NAME} POST_BUILD
+				COMMAND ${OBJCOPY} --only-keep-debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}> $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>.debug
+				COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>
+				COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE_NAME:${SRB2_SDL2_EXE_NAME}>.debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>
+			)
+		endif()
+	endif()
+
+	#### Installation ####
+	if (CLANG)
+		install(TARGETS ${SRB2_SDL2_EXE_NAME}
+			BUNDLE DESTINATION .
+		)
+	else()
+		install(TARGETS ${SRB2_SDL2_EXE_NAME} ${SRB2_SDL2_EXE_NAME}
+			RUNTIME DESTINATION .
+		)
+	endif()
+
+	if(${CMAKE_SYSTEM} MATCHES Windows)
+		set(win_extra_dll_list "")
+		macro(getwinlib dllname defaultname)
+			find_library(SRB2_SDL2_DLL_${dllname} "${defaultname}")
+			list(APPEND win_extra_dll_list ${SRB2_SDL2_DLL_${dllname}})
+		endmacro()
+		getwinlib(SDL2 "SDL2.dll")
+		if(${SRB2_CONFIG_SDL2_USEMIXER})
+			getwinlib(SDL2_mixer "SDL2_mixer.dll")
+			getwinlib(libmikmod-2 "libmikmod-2.dll")
+			getwinlib(libogg_0 "libogg-0.dll")
+			getwinlib(libvorbis_0 "libvorbis-0.dll")
+			getwinlib(libvorbisfile_3 "libvorbisfile-3.dll")
+			getwinlib(smpeg2 "smpeg2.dll")
+		endif()
+		if(${SRB2_CONFIG_HAVE_GME})
+			getwinlib(libgme "libgme.dll")
+		endif()
+
+		install(PROGRAMS
+			${win_extra_dll_list}
+			DESTINATION .
+		)
+
+		# We also want to copy those DLLs to build directories on MSVC.
+		# So we'll add a post_build step.
+		copy_files_to_build_dir(${SRB2_SDL2_EXE_NAME} win_extra_dll_list)
+	endif()
+
+	
+	# Mac bundle fixup
+	if(CLANG)
+		install(CODE "
+			include(BundleUtilities)
+			fixup_bundle(\"${CMAKE_INSTALL_PREFIX}/Sonic Robo Blast 2.app\"
+				\"\"
+				/Library/Frameworks
+			)"
+		)
+	endif()
+else()
+	message(WARNING "SDL2 wasn't found, so ${SRB2_SDL2_EXE_NAME} won't be available")
+endif()
diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c
index 1c438e0834f97aed1c15d962c9e982c246892921..976f7eb35760360129128616437c73fd903ea1ef 100644
--- a/src/sdl/i_main.c
+++ b/src/sdl/i_main.c
@@ -195,15 +195,15 @@ int main(int argc, char **argv)
 
 #ifdef LOGMESSAGES
 #if defined(_WIN32_WCE) || defined(GP2X)
-	logstream = fopen(va("%s.log",argv[0]), "a");
+	logstream = fopen(va("%s.log",argv[0]), "wt");
 #elif defined (_WII)
-	logstream = fopen(va("%s/srb2log.txt",logdir), "a");
+	logstream = fopen(va("%s/log.txt",logdir), "wt");
 #elif defined (DEFAULTDIR)
 	if (logdir)
-		logstream = fopen(va("%s/"DEFAULTDIR"/srb2log.txt",logdir), "a");
+		logstream = fopen(va("%s/"DEFAULTDIR"/log.txt",logdir), "wt");
 	else
 #endif
-		logstream = fopen("./srb2log.txt", "a");
+		logstream = fopen("./log.txt", "wt");
 #endif
 
 	//I_OutputMsg("I_StartupSystem() ...\n");
@@ -228,9 +228,9 @@ int main(int argc, char **argv)
 #endif
 #endif
 	// startup SRB2
-	CONS_Printf("%s", M_GetText("Setting up SRB2...\n"));
+	CONS_Printf("Setting up SRB2...\n");
 	D_SRB2Main();
-	CONS_Printf("%s", M_GetText("Entering main game loop...\n"));
+	CONS_Printf("Entering main game loop...\n");
 	// never return
 	D_SRB2Loop();
 
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index a1e91ec754b83815e8cb48cb0b950b5b2065a836..fa09dc343cdea0e5e054a0dc6c6a2b102d58b429 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -20,6 +20,12 @@
 /// \file
 /// \brief SRB2 system stuff for SDL
 
+#ifdef CMAKECONFIG
+#include "config.h"
+#else
+#include "config.h.in"
+#endif
+
 #ifndef _WIN32_WCE
 #include <signal.h>
 #endif
@@ -145,6 +151,10 @@ void __set_fpscr(long); // in libgcc / kernel's startup.s?
 #define O_BINARY 0
 #endif
 
+#ifdef __APPLE__
+#include "macosx/mac_resources.h"
+#endif
+
 // Locations for searching the srb2.srb
 #ifdef _arch_dreamcast
 #define DEFAULTWADLOCATION1 "/cd"
@@ -301,6 +311,7 @@ SDL_bool framebuffer = SDL_FALSE;
 
 UINT8 keyboard_started = false;
 
+#if !defined (DC)
 FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
 {
 	//static char msg[] = "oh no! back to reality!\r\n";
@@ -311,26 +322,24 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
 
 	switch (num)
 	{
-	case SIGINT:
-		sigmsg = "SIGINT - interrupted";
-		break;
+//	case SIGINT:
+//		sigmsg = "SIGINT - interrupted";
+//		break;
 	case SIGILL:
 		sigmsg = "SIGILL - illegal instruction - invalid function image";
 		break;
 	case SIGFPE:
-		sigmsg = "SIGFPE - floating point exception";
+		sigmsg = "SIGFPE - mathematical exception";
 		break;
 	case SIGSEGV:
 		sigmsg = "SIGSEGV - segment violation";
 		break;
-	case SIGTERM:
-		sigmsg = "SIGTERM - Software termination signal from kill";
-		break;
-#if !(defined (__unix_) || defined (UNIXCOMMON))
-	case SIGBREAK:
-		sigmsg = "SIGBREAK - Ctrl-Break sequence";
-		break;
-#endif
+//	case SIGTERM:
+//		sigmsg = "SIGTERM - Software termination signal from kill";
+//		break;
+//	case SIGBREAK:
+//		sigmsg = "SIGBREAK - Ctrl-Break sequence";
+//		break;
 	case SIGABRT:
 		sigmsg = "SIGABRT - abnormal termination triggered by abort call";
 		break;
@@ -339,7 +348,7 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
 		sigmsg = sigdef;
 	}
 
-	I_OutputMsg("signal_handler() error: %s\n", sigmsg);
+	I_OutputMsg("\nsignal_handler() error: %s\n", sigmsg);
 
 	SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
 		"Signal caught",
@@ -350,7 +359,6 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
 	I_Quit();
 }
 
-#if !defined (DC)
 FUNCNORETURN static ATTRNORETURN void quit_handler(int num)
 {
 	signal(num, SIG_DFL); //default signal action
@@ -663,17 +671,9 @@ static void I_StartupConsole(void)
 {
 	HANDLE ci, co;
 	const INT32 ded = M_CheckParm("-dedicated");
-#ifdef SDLMAIN
 	BOOL gotConsole = FALSE;
 	if (M_CheckParm("-console") || ded)
 		gotConsole = AllocConsole();
-#else
-	BOOL gotConsole = TRUE;
-	if (M_CheckParm("-detachconsole"))
-	{
-		FreeConsole();
-		gotConsole = AllocConsole();
-	}
 #ifdef _DEBUG
 	else if (M_CheckParm("-noconsole") && !ded)
 #else
@@ -683,7 +683,6 @@ static void I_StartupConsole(void)
 		FreeConsole();
 		gotConsole = FALSE;
 	}
-#endif
 
 	if (gotConsole)
 	{
@@ -743,24 +742,22 @@ static inline void I_ShutdownConsole(void){}
 void I_StartupKeyboard (void)
 {
 #if !defined (DC)
-#ifdef SIGILL
-	signal(SIGILL , signal_handler);
-#endif
 #ifdef SIGINT
 	signal(SIGINT , quit_handler);
 #endif
-#ifdef SIGSEGV
-	signal(SIGSEGV , signal_handler);
-#endif
 #ifdef SIGBREAK
 	signal(SIGBREAK , quit_handler);
 #endif
-#ifdef SIGABRT
-	signal(SIGABRT , signal_handler);
-#endif
 #ifdef SIGTERM
 	signal(SIGTERM , quit_handler);
 #endif
+
+	// If these defines don't exist,
+	// then compilation would have failed above us...
+	signal(SIGILL , signal_handler);
+	signal(SIGSEGV , signal_handler);
+	signal(SIGABRT , signal_handler);
+	signal(SIGFPE , signal_handler);
 #endif
 }
 
@@ -1665,7 +1662,7 @@ void I_UpdateMumble(const mobj_t *mobj, const listener_t listener)
 		return;
 
 	if(mumble->uiVersion != 2) {
-		wcsncpy(mumble->name, L"SRB2 "VERSIONSTRING, 256);
+		wcsncpy(mumble->name, L"SRB2 "VERSIONSTRINGW, 256);
 		wcsncpy(mumble->description, L"Sonic Robo Blast 2 with integrated Mumble Link support.", 2048);
 		mumble->uiVersion = 2;
 	}
@@ -2341,9 +2338,7 @@ static boolean shutdowning = false;
 void I_Error(const char *error, ...)
 {
 	va_list argptr;
-#if (defined (MAC_ALERT) || defined (_WIN32) || (defined (_WIN32_WCE) && !defined (__GNUC__))) && !defined (_XBOX)
 	char buffer[8192];
-#endif
 
 	// recursive error detecting
 	if (shutdowning)
@@ -2375,62 +2370,38 @@ void I_Error(const char *error, ...)
 		}
 		if (errorcount > 20)
 		{
-#ifdef MAC_ALERT
 			va_start(argptr, error);
 			vsprintf(buffer, error, argptr);
 			va_end(argptr);
-			// 2004-03-03 AJR Since the Mac user is most likely double clicking to run the game, give them a panel.
-			MacShowAlert("Recursive Error", buffer, "Quit", NULL, NULL);
-#elif (defined (_WIN32) || (defined (_WIN32_WCE)) && !defined (__GNUC__)) && !defined (_XBOX)
-			va_start(argptr,error);
-			vsprintf(buffer, error, argptr);
-			va_end(argptr);
-#ifndef _WIN32_WCE
-			{
-				HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
-				DWORD bytesWritten;
-				if (co != INVALID_HANDLE_VALUE)
-				{
-					if (GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &bytesWritten))
-						WriteConsoleA(co, buffer, (DWORD)strlen(buffer), NULL, NULL);
-					else
-						WriteFile(co, buffer, (DWORD)strlen(buffer), &bytesWritten, NULL);
-				}
-			}
-#endif
-			OutputDebugStringA(buffer);
-			MessageBoxA(vid.WndParent, buffer, "SRB2 Recursive Error", MB_OK|MB_ICONERROR);
-#else
-			// Don't print garbage
-			va_start(argptr, error);
-			if (!framebuffer)
-				vfprintf (stderr, error, argptr);
-			va_end(argptr);
-#endif
+			// Implement message box with SDL_ShowSimpleMessageBox,
+			// which should fail gracefully if it can't put a message box up
+			// on the target system
+			SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
+				"SRB2 "VERSIONSTRING" Recursive Error",
+				buffer, NULL);
+
 			W_Shutdown();
+
 #ifdef GP2X
 			chdir("/usr/gp2x");
 			execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL);
 #endif
+
 			exit(-1); // recursive errors detected
 		}
 	}
+
 	shutdowning = true;
-	I_ShutdownConsole();
-#ifndef MAC_ALERT
-	// Message first.
-	va_start(argptr,error);
-	if (!framebuffer)
-	{
-		fprintf(stderr, "Error: ");
-		vfprintf(stderr,error,argptr);
-		fprintf(stderr, "\n");
-	}
+
+	// Display error message in the console before we start shutting it down
+	va_start(argptr, error);
+	vsprintf(buffer, error, argptr);
 	va_end(argptr);
+	I_OutputMsg("\nI_Error(): %s\n", buffer);
+	// ---
+
+	I_ShutdownConsole();
 
-	if (!framebuffer)
-		fflush(stderr);
-#endif
 	M_SaveConfig(NULL); // save game config, cvars..
 #ifndef NONET
 	D_SaveBan(); // save the ban list
@@ -2454,21 +2425,30 @@ void I_Error(const char *error, ...)
 #ifndef _arch_dreamcast
 	SDL_Quit();
 #endif
-#ifdef MAC_ALERT
-	va_start(argptr, error);
-	vsprintf(buffer, error, argptr);
-	va_end(argptr);
-	// 2004-03-03 AJR Since the Mac user is most likely double clicking to run the game, give them a panel.
-	MacShowAlert("Critical Error", buffer, "Quit", NULL, NULL);
-#endif
+
+	// Implement message box with SDL_ShowSimpleMessageBox,
+	// which should fail gracefully if it can't put a message box up
+	// on the target system
+	SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
+		"SRB2 "VERSIONSTRING" Error",
+		buffer, NULL);
+	// Note that SDL_ShowSimpleMessageBox does *not* require SDL to be
+	// initialized at the time, so calling it after SDL_Quit() is
+	// perfectly okay! In addition, we do this on purpose so the
+	// fullscreen window is closed before displaying the error message
+	// in case the fullscreen window blocks it for some absurd reason.
+
 	W_Shutdown();
+
 #if defined (PARANOIA) && defined (__CYGWIN__)
-		*(INT32 *)2 = 4; //Alam: Debug!
+	*(INT32 *)2 = 4; //Alam: Debug!
 #endif
+
 #ifdef GP2X
 	chdir("/usr/gp2x");
 	execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL);
 #endif
+
 	exit(-1);
 }
 
@@ -2534,6 +2514,7 @@ void I_ShutdownSystem(void)
 #ifdef  LOGMESSAGES
 	if (logstream)
 	{
+		I_OutputMsg("I_ShutdownSystem(): end of logstream.\n");
 		fclose(logstream);
 		logstream = NULL;
 	}
@@ -2778,6 +2759,28 @@ static const char *locateWad(void)
 	if (isWadPathOk(returnWadPath))
 		return NULL;
 #endif
+    
+    
+#ifdef CMAKECONFIG
+#ifndef NDEBUG
+    I_OutputMsg(","CMAKE_ASSETS_DIR);
+    strcpy(returnWadPath, CMAKE_ASSETS_DIR);
+    if (isWadPathOk(returnWadPath))
+    {
+        return returnWadPath;
+    }
+#endif
+#endif
+    
+#ifdef __APPLE__
+    OSX_GetResourcesPath(returnWadPath);
+    I_OutputMsg(",%s", returnWadPath);
+    if (isWadPathOk(returnWadPath))
+    {
+        return returnWadPath;
+    }
+    
+#endif
 
 	// examine default dirs
 #ifdef DEFAULTWADLOCATION1
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 660263b3fb3424b72a41ba24fa080cda2d08589a..faee1bc695fc14939468d75c54f1289d815e4de0 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -271,12 +271,17 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
 	{
 		return '0';
 	}
-	if (code >= SDL_SCANCODE_F1 && code <= SDL_SCANCODE_F12)
+	if (code >= SDL_SCANCODE_F1 && code <= SDL_SCANCODE_F10)
 	{
 		return KEY_F1 + (code - SDL_SCANCODE_F1);
 	}
 	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:
@@ -667,31 +672,28 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
 
 	if (mousefocus && kbfocus)
 	{
+		// Tell game we got focus back, resume music if necessary
+		window_notinfocus = false;
+		if (!paused)
+			I_ResumeSong(0); //resume it
+
 		if (!firsttimeonmouse)
 		{
 			if (cv_usemouse.value) I_StartupMouse();
 		}
 		//else firsttimeonmouse = SDL_FALSE;
-		if (gamestate == GS_LEVEL)
-		{
-			if (!paused) I_ResumeSong(0); //resume it
-		}
 	}
 	else if (!mousefocus && !kbfocus)
 	{
+		// Tell game we lost focus, pause music
+		window_notinfocus = true;
+		I_PauseSong(0);
+
 		if (!disable_mouse)
 		{
 			SDLforceUngrabMouse();
 		}
-		if (!netgame && gamestate == GS_LEVEL && !demoplayback && !demorecording && !modeattacking)
-		{
-			paused = true;
-		}
 		memset(gamekeydown, 0, NUMKEYS); // TODO this is a scary memset
-		if (gamestate == GS_LEVEL)
-		{
-			I_PauseSong(0);
-		}
 
 		if (MOUSE_MENU)
 		{
@@ -1570,7 +1572,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 #ifdef HWRENDER
 	if (rendermode == render_opengl)
 	{
-		window = SDL_CreateWindow("SRB2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+		window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 				realwidth, realheight, flags | SDL_WINDOW_OPENGL);
 		if (window != NULL)
 		{
@@ -1590,7 +1592,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 #endif
 	if (rendermode == render_soft)
 	{
-		window = SDL_CreateWindow("SRB2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+		window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 				realwidth, realheight, flags);
 		if (window != NULL)
 		{
@@ -1775,7 +1777,7 @@ void I_StartupGraphics(void)
 
 	// Create window
 	//Impl_CreateWindow(USE_FULLSCREEN);
-	//Impl_SetWindowName("SRB2");
+	//Impl_SetWindowName("SRB2 "VERSIONSTRING);
 	VID_SetMode(VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT));
 
 	vid.buffer = NULL;  // For software mode
@@ -1835,12 +1837,17 @@ void I_ShutdownGraphics(void)
 		bufSurface = NULL;
 	}
 
+	I_OutputMsg("I_ShutdownGraphics(): ");
+
 	// was graphics initialized anyway?
 	if (!graphics_started)
+	{
+		I_OutputMsg("graphics never started\n");
 		return;
-	CONS_Printf("I_ShutdownGraphics: ");
+	}
 	graphics_started = false;
-	CONS_Printf("%s", M_GetText("shut down\n"));
+	I_OutputMsg("shut down\n");
+
 #ifdef HWRENDER
 	if (GLUhandle)
 		hwClose(GLUhandle);
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index a205d30cea0940f91ac87bf8d268f7bd835cdc62..98599fb60b7ad0a89046d317f63292bc461dbae3 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.12;
+				CURRENT_PROJECT_VERSION = 2.1.14;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					NORMALSRB2,
@@ -1226,7 +1226,7 @@
 		C01FCF4C08A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.12;
+				CURRENT_PROJECT_VERSION = 2.1.14;
 				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
 				GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/sdl/macosx/mac_resources.c b/src/sdl/macosx/mac_resources.c
new file mode 100644
index 0000000000000000000000000000000000000000..dacc8014ba8da8fcd48ccbfe56a7772c4ec6c0fc
--- /dev/null
+++ b/src/sdl/macosx/mac_resources.c
@@ -0,0 +1,31 @@
+#include "mac_resources.h"
+#include <string.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+void OSX_GetResourcesPath(char * buffer)
+{
+    CFBundleRef mainBundle;
+    mainBundle = CFBundleGetMainBundle();
+    if (mainBundle)
+    {
+        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);
+        CFRelease(macPath);
+        CFRelease(appUrlRef);
+        //CFRelease(mainBundle);
+        CFRelease(separator);
+    }
+
+}
\ No newline at end of file
diff --git a/src/sdl/macosx/mac_resources.h b/src/sdl/macosx/mac_resources.h
new file mode 100644
index 0000000000000000000000000000000000000000..727ac9f6b091cec94d0cc10c23de7ef8580d9c4f
--- /dev/null
+++ b/src/sdl/macosx/mac_resources.h
@@ -0,0 +1,5 @@
+#ifndef __MAC_RESOURCES_H__
+#define __MAC_RESOURCES_H__
+
+void OSX_GetResourcesPath(char * buffer);
+#endif
\ No newline at end of file
diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h
index af4e48f750c0533c8db014720cba663ce68665a3..7ac32f4b3bf0268be5aaada164426a207195d790 100644
--- a/src/sdl/sdlmain.h
+++ b/src/sdl/sdlmain.h
@@ -25,7 +25,11 @@ extern SDL_bool framebuffer;
 #include "../m_fixed.h"
 
 // SDL2 stub macro
-#define SDL2STUB(name) CONS_Printf("SDL2: stubbed: %s:%d\n", __func__, __LINE__)
+#ifdef _MSC_VER
+#define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __FUNCTION__, __LINE__)
+#else
+#define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __func__, __LINE__)
+#endif
 
 /**	\brief	The JoyInfo_s struct
 
diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
index a205d30cea0940f91ac87bf8d268f7bd835cdc62..98599fb60b7ad0a89046d317f63292bc461dbae3 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.12;
+				CURRENT_PROJECT_VERSION = 2.1.14;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					NORMALSRB2,
@@ -1226,7 +1226,7 @@
 		C01FCF4C08A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.12;
+				CURRENT_PROJECT_VERSION = 2.1.14;
 				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 0d0cb1aefd2ca2fa310472c234750031fbd641c4..a9bdacf7152f3a7683345ccd2ece8c0ed1b3e523 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -203,7 +203,7 @@ void ST_doPaletteStuff(void)
 {
 	INT32 palette;
 
-	if (paused || P_MenuActivePause())
+	if (paused || P_AutoPause())
 		palette = 0;
 	else if (stplyr && stplyr->flashcount)
 		palette = stplyr->flashpal;
@@ -1576,15 +1576,6 @@ static inline void ST_drawTeamName(void)
 		V_DrawString(244, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "SPECTATOR");
 }
 
-#ifdef CHAOSISNOTDEADYET
-static inline void ST_drawChaosHUD(void)
-{
-	char chains[33];
-	sprintf(chains, "CHAINS: %u", stplyr->scoreadd);
-	V_DrawString(8, STRINGY(184), V_HUDTRANSHALF, chains);
-}
-#endif
-
 static void ST_drawSpecialStageHUD(void)
 {
 	if (totalrings > 0)
@@ -1667,7 +1658,7 @@ static void ST_doHuntIconsAndSound(void)
 			interval = newinterval;
 	}
 
-	if (!(P_MenuActivePause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
+	if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
 		S_StartSound(NULL, sfx_emfind);
 }
 
@@ -1727,7 +1718,7 @@ static void ST_doItemFinderIconsAndSound(void)
 		}
 	}
 
-	if (!(P_MenuActivePause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
+	if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
 		S_StartSound(NULL, sfx_emfind);
 }
 
@@ -1814,12 +1805,6 @@ static void ST_overlayDrawer(void)
 		if (G_GametypeHasTeams())
 			ST_drawTeamName();
 
-		// Chaos HUD Stuff
-#ifdef CHAOSISNOTDEADYET
-		else if (gametype == GT_CHAOS)
-			ST_drawChaosHUD();
-#endif
-
 		// Special Stage HUD
 		if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer])
 			ST_drawSpecialStageHUD();
diff --git a/src/w_wad.c b/src/w_wad.c
index adcbb4811cca1670cc9f62a23c9f1e624efd7edd..79ed1f478b67741dd625418e10ef1ece6813c556 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -662,6 +662,32 @@ lumpnum_t W_GetNumForName(const char *name)
 	return i;
 }
 
+//
+// W_CheckNumForNameInBlock
+// Checks only in blocks from blockstart lump to blockend lump
+//
+lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend)
+{
+	INT32 i;
+	lumpnum_t bsid, beid;
+	lumpnum_t check = INT16_MAX;
+
+	// scan wad files backwards so patch lump files take precedence
+	for (i = numwadfiles - 1; i >= 0; i--)
+	{
+		bsid = W_CheckNumForNamePwad(blockstart,(UINT16)i,0);
+		if (bsid == INT16_MAX)
+			continue; // block doesn't exist, keep going
+		beid = W_CheckNumForNamePwad(blockend,(UINT16)i,0);
+		// if block end doesn't exist, just search through everything
+
+		check = W_CheckNumForNamePwad(name,(UINT16)i,bsid);
+		if (check < beid)
+			return (i<<16)+check; // found it, in our constraints
+	}
+	return LUMPERROR;
+}
+
 // Used by Lua. Case sensitive lump checking, quickly...
 #include "fastcmp.h"
 UINT8 W_LumpExists(const char *name)
diff --git a/src/w_wad.h b/src/w_wad.h
index 76f52b0043cb9299b07f954d22ef6e29e92d546f..614b7e4aec8c8b9bc4c16c9703c9735ed84006f8 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -102,6 +102,7 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum);
 UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad
 lumpnum_t W_CheckNumForName(const char *name);
 lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR
+lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend);
 UINT8 W_LumpExists(const char *name); // Lua uses this.
 
 size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump);
diff --git a/src/win32/CMakeLists.txt b/src/win32/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..94c198299add6162c63a69324207ba048d73cf01
--- /dev/null
+++ b/src/win32/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_executable(${SRB2_WIN_EXE_NAME} EXCLUDE_FROM_ALL
+	${SRB2_CORE_SOURCES}
+	${SRB2_CORE_HEADERS}
+	${SRB2_LUA_SOURCES}
+	${SRB2_LUA_HEADERS}
+	${SRB2_BLUA_SOURCES}
+	${SRB2_BLUA_HEADERS})
+
+target_compile_definitions(${SRB2_WIN_EXE_NAME} PRIVATE
+	-D_WINDOWS
+)
\ No newline at end of file
diff --git a/src/y_inter.c b/src/y_inter.c
index 498afa7cfeddc5cd9e580c728a69b7dd77acc242..2f2edf7ca71eef368671f501c88db3e745f52959 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -588,7 +588,7 @@ void Y_Ticker(void)
 		return;
 
 	// Check for pause or menu up in single player
-	if (paused || P_MenuActivePause())
+	if (paused || P_AutoPause())
 		return;
 
 	intertic++;
@@ -907,11 +907,7 @@ void Y_StartIntermission(void)
 			intertype = int_teammatch;
 		else if (gametype == GT_MATCH
 		 || gametype == GT_TAG
-		 || gametype == GT_HIDEANDSEEK
-#ifdef CHAOSISNOTDEADYET
-		 || gametype == GT_CHAOS
-#endif
-		)
+		 || gametype == GT_HIDEANDSEEK)
 			intertype = int_match;
 		else if (gametype == GT_RACE)
 			intertype = int_race;
diff --git a/src/y_inter.h b/src/y_inter.h
index 67ab4f4e2029480505b2d5b62ec9cbe1fa5c8f3f..a3620cea74a8a1d1adde6c649abafdc0d4a36c3a 100644
--- a/src/y_inter.h
+++ b/src/y_inter.h
@@ -25,9 +25,6 @@ typedef enum
 	int_teammatch,// Team Match
 //	int_tag,      // Tag
 	int_ctf,      // CTF
-#ifdef CHAOSISNOTDEADYET
-	int_chaos,    // Chaos
-#endif
 	int_spec,     // Special Stage
 	int_nights,   // NiGHTS into Dreams
 	int_nightsspec,// NiGHTS special stage