diff --git a/.gitignore b/.gitignore
index 4ba05f7ca698b968eec6391857fa5ec68e1b422e..a3d823fa2182edef86c35ee2810560e5d8f7408e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,4 @@ Win32_LIB_ASM_Release
 /CMakeUserPresets.json
 /out
 /objs/VC10
+/thirdparty/vcpkg-overlays
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 016ac951b7dad13cc49bb29a188c326528c2576f..29f5ef5fff9f1bc4afb83006c65f54088762e6dc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,766 +1,19 @@
-variables:
-  GIT_STRATEGY: clone
-  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
-
-default:
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:stable
-
-  cache:
-    - key: ccache-$CI_PROJECT_PATH_SLUG-$CI_JOB_NAME_SLUG
-      fallback_keys:
-        - cache-$CI_PROJECT_PATH_SLUG-$CI_DEFAULT_BRANCH
-        - cache-$CI_PROJECT_PATH_SLUG-default
-      paths:
-        - ccache
-        - ccache_statslog
-
-    - key: apt-$CI_JOB_IMAGE
-      paths:
-        - apt-cache
-      unprotect: true
-
-    - key: apk-$CI_JOB_IMAGE
-      paths:
-        - apk-cache
-      unprotect: true
-
-  before_script:
-    - - |
-         # debconf
-         echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
-      - export DEBIAN_FRONTEND="noninteractive"
-      - export DEBIAN_PRIORITY="low"
-      - export DEBCONF_NONINTERACTIVE_SEEN="true"
-      - |
-          # debconf
-          echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
-    - - |
-          # dpkg_aa
-          echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
-      - dpkg --add-architecture i386
-      - dpkg --add-architecture amd64
-      - dpkg --add-architecture arm64
-      - |
-          # dpkg_aa
-          echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
-    - - |
-          # apt_conf
-          echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
-      - export APT_CACHE_DIR=`pwd`/apt-cache
-      - mkdir --parents --verbose $APT_CACHE_DIR/partial/
-      - touch /etc/apt/apt.conf.d/99build
-      - |
-          # apt.conf
-          echo Adding options to apt.conf':'
-      - |
-          # APT::Install-Recommends
-          echo APT::Install-Recommends "false"\;       | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # quit
-          echo quiet "1"\;                             | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # APT::Get::Assume-Yes
-          echo APT::Get::Assume-Yes "true"\;           | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # Dir::Cache::Archives
-          echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # apt_conf
-          echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
-    - - |
-          # apt_update
-          echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
-      - apt-get update
-      - |
-          # apt_update
-          echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
-
-    - - |
-          # apt_pre
-          echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
-      - apt-get install apt-utils
-      - |
-          # apt_pre
-          echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
+include:
+  - '.gitlab/ci/templates/*.yml'
+  - '.gitlab/ci/jobs/*.yml'
 
-    - - |
-          # apt_upgrade
-          echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
-      - apt-get upgrade
-      - |
-          # apt_update
-          echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
+workflow:
+  auto_cancel:
+    on_new_commit: interruptible
 
-    - - |
-          # apt_common
-          echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apt-get install make git ccache nasm cmake ca-certificates
-      - |
-          # apt_common
-          echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
-
-    - - |
-          # ccache_config
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
-      - mkdir --parents --verbose ~/.ccache/
-      - touch ~/.ccache/ccache.conf
-      - |
-          # cache.conf
-          echo Adding ccache configution option
-      - |
-          # base_dir
-          echo base_dir = $PWD                  | tee --append ~/.ccache/ccache.conf
-      - |
-          # cache_dir
-          echo cache_dir = $PWD/ccache          | tee --append ~/.ccache/ccache.conf
-      - |
-          # compiler_check
-          echo compiler_check = content         | tee --append ~/.ccache/ccache.conf
-      - |
-          # stats_log
-          echo stats_log = $PWD/ccache_statslog | tee --append ~/.ccache/ccache.conf
-      - |
-          # max_size
-          echo max_size = 50M                   | tee --append ~/.ccache/ccache.conf
-      - |
-          # ccache_config
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
-
-    - - |
-          # cache_reset
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
-      - ccache --zero-stats
-      - ccache --show-stats
-      - |
-          # ccache_reset
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME_SLUG"
-
-  after_script:
-    - - |
-           # apt_clean
-           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
-      - apt-get autoclean
-      - |
-          # apt_clean
-          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
-
-    - - |
-          # ccache_stats
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
-      - ccache --show-stats
-      - ccache --show-log-stats || true
-      - |
-          # ccahe_stats
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
+variables:
+  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
+  GIT_DEPTH: 20
 
 stages:
   - build
 
-Debian testing GCC:
-  stage: build
-
-  when: manual
-
-  image: debian:testing-slim
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "testing-gcc"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
-
-  variables:
-    CC: gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Windows x86:
-  stage: build
-
-  when: on_success
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Win32"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
-
-  variables:
-    PREFIX: i686-w64-mingw32
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-mingw-w64-i686-win32
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:amd64:
-  stage: build
-
-  when: on_success
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian amd64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
-
-  variables:
-    CC: x86_64-linux-gnu-gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-    OBJCOPY: x86_64-linux-gnu-objcopy
-    OBJDUMP: x86_64-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian oldstable:amd64:
-  extends: Debian stable:amd64
-
-  when: manual
-
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old amd64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:i386:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian i386"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
-
-  variables:
-    CC: i686-linux-gnu-gcc
-    OBJCOPY: i686-linux-gnu-objcopy
-    OBJDUMP: i686-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:arm64:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
-
-  variables:
-    CC: aarch64-linux-gnu-gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-    OBJCOPY: aarch64-linux-gnu-objcopy
-    OBJDUMP: aarch64-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian oldstable:arm64:
-  extends: Debian stable:arm64
-
-  when: manual
-
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-batocera:arm64:
-  extends: Debian stable:arm64
-
-  when: manual
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Windows x64:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Win64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
-
-  variables:
-    PREFIX: x86_64-w64-mingw32
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-mingw-w64-x86-64-win32
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable Clang:
-  stage: build
-
-  when: on_success
-
-  allow_failure: false
-
-  artifacts:
-    paths:
-      - "build.clang/bin/"
-      - "build.clang/src/comptime.h"
-    expose_as: "clang"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    CC: clang
-    CXX: clang
-    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
-    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install clang
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # cmake
-          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.clang -D CPM_USE_LOCAL_PACKAGES:BOOL=ON -D SRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -D SRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -G "Unix Makefiles"
-      - |
-          # cmake
-          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.clang --keep-going || make --directory=src --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian testing Clang:
-  extends: Debian stable Clang
-
-  when: manual
-
-  allow_failure: true
-
-  image: debian:testing-slim
-
-  artifacts:
-    paths:
-      - "build.clang/bin/"
-      - "build.clang/src/comptime.h"
-    expose_as: "testing-clang"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
-
-  variables:
-    CC: clang
-    CXX: clang
-    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
-    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-Alpine 3 GCC:
-  stage: build
-
-  when: on_success
-
-  image: alpine:3
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Apline-3"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
-
-  before_script:
-    - - |
-          # apk_cache
-          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
-      - export APK_CACHE_DIR=`pwd`/apk-cache
-      - mkdir --parents --verbose $APK_CACHE_DIR/
-      - ln -sf /etc/apk/cache $APK_CACHE_DIR
-      - |
-          # apk_cache
-          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
-
-    - - |
-          # apk_update
-          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
-      - apk update
-      - |
-          # apk_update
-          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
-
-    - - |
-          # apk_upgrade
-          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
-      - apk upgrade
-      - |
-          # apk_update
-          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
-
-    - - |
-          # apk_common
-          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apk add make git ccache nasm
-      - |
-          # apk_common
-          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
-
-    - - |
-          # ccache_config
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
-      - mkdir --parents --verbose ~/.ccache/
-      - touch ~/.ccache/ccache.conf
-      - |
-          # cache.conf
-          echo Adding ccache configution option
-      - |
-          # base_dir
-          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
-      - |
-          # cache_dir
-          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
-      - |
-          # compiler_check
-          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
-      - |
-          # stats_log
-          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
-      - |
-          # max_size
-          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
-      - |
-          # ccache_config
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
-
-    - - |
-          # cache_reset
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
-      - ccache --zero-stats
-      - ccache --show-stats
-      - |
-          # ccache_reset
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
-
-  script:
-    - - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
-      - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
-
-    - - |
-          # apk_development
-          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
-      - |
-          # apk_development
-          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-  after_script:
-    - - |
-           # apk_clean
-           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
-      - apk cache clean
-      - |
-          # apk_clean
-          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
-
-    - - |
-          # ccache_stats
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
-      - ccache --show-stats --verbose
-      - ccache --show-log-stats --verbose
-      - |
-          # ccahe_stats
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
-
-Alpine 3 GCC Dedicated:
-  extends: Alpine 3 GCC
-
+default:
+  interruptible: true
   artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Apline-3-Dedicated"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
-
-  script:
-    - - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
-      - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
-
-    - - |
-          # apk_development
-          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev libpng-dev curl-dev
-      - |
-          # apk_development
-          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+    expire_in: 1 day
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml b/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
new file mode 100644
index 0000000000000000000000000000000000000000..242ddd0eaa3f0e45504fa0fe258e08c63e0845df
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
@@ -0,0 +1,34 @@
+Alpine 3 GCC Dedicated:
+  extends: Alpine 3 GCC
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3-Dedicated"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add musl-dev libpng-dev curl-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/alpine-3-gcc.yml b/.gitlab/ci/jobs/alpine-3-gcc.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3b12e40167a568e3ced2abc7a09ed0045e0cc99
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc.yml
@@ -0,0 +1,135 @@
+Alpine 3 GCC:
+  stage: build
+
+  when: manual
+
+  image: alpine:3
+
+  allow_failure: true
+
+  cache:
+    - key: apk-$CI_JOB_IMAGE
+      paths:
+        - apk-cache
+      unprotect: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
+
+  before_script:
+    - - |
+          # apk_cache
+          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
+      - export APK_CACHE_DIR=`pwd`/apk-cache
+      - mkdir --parents --verbose $APK_CACHE_DIR/
+      - ln -sf /etc/apk/cache $APK_CACHE_DIR
+      - |
+          # apk_cache
+          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
+
+    - - |
+          # apk_update
+          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
+      - apk update
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
+
+    - - |
+          # apk_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apk upgrade
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
+
+    - - |
+          # apk_common
+          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apk add make git ccache nasm
+      - |
+          # apk_common
+          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+  after_script:
+    - - |
+           # apk_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
+      - apk cache clean
+      - |
+          # apk_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats --verbose
+      - ccache --show-log-stats --verbose
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/.gitlab/ci/jobs/batocera-arm64.yml b/.gitlab/ci/jobs/batocera-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3e43aa8753a0a1500abdc52e9f594863bd4b3691
--- /dev/null
+++ b/.gitlab/ci/jobs/batocera-arm64.yml
@@ -0,0 +1,38 @@
+batocera:arm64:
+  extends: Debian stable:arm64
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-amd64.yml b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3929ecdcd10f8f448072d2c859de6a7dd31d94c7
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
@@ -0,0 +1,40 @@
+Debian oldstable:amd64:
+  extends: Debian stable:amd64
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old amd64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-arm64.yml b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b18d538cd0824041650f3f8a5361b7b07c85f206
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
@@ -0,0 +1,40 @@
+Debian oldstable:arm64:
+  extends: Debian stable:arm64
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-amd64.yml b/.gitlab/ci/jobs/debian-stable-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4a757afe0d519f268bb4541cda49ba03a3181600
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-amd64.yml
@@ -0,0 +1,45 @@
+Debian stable:amd64:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian amd64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
+
+  variables:
+    CC: x86_64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: x86_64-linux-gnu-objcopy
+    OBJDUMP: x86_64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
+
+  when: on_success
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-arm64.yml b/.gitlab/ci/jobs/debian-stable-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..879391affebe7586e019e7bb7f8d77a0599983e2
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-arm64.yml
@@ -0,0 +1,45 @@
+Debian stable:arm64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
+
+  variables:
+    CC: aarch64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: aarch64-linux-gnu-objcopy
+    OBJDUMP: aarch64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-clang-amd64.yml b/.gitlab/ci/jobs/debian-stable-clang-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4686c1849196d3be6cbee936c1ad910c0f93627c
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-clang-amd64.yml
@@ -0,0 +1,55 @@
+Debian stable Clang:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  allow_failure: false
+
+  artifacts:
+    paths:
+      - "build.clang/bin/"
+      - "build.clang/src/config.h"
+    expose_as: "clang"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    CC: clang
+    CXX: clang
+    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
+    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install clang
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.clang -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_USE_LIBGME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.clang --keep-going || make --directory=build.clang --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-i386.yml b/.gitlab/ci/jobs/debian-stable-i386.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cd6206e55e9a497d7065d3ea652c1ed3c6bd8d23
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-i386.yml
@@ -0,0 +1,44 @@
+Debian stable:i386:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian i386"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
+
+  variables:
+    CC: i686-linux-gnu-gcc
+    OBJCOPY: i686-linux-gnu-objcopy
+    OBJDUMP: i686-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-testing-clang-amd64.yml b/.gitlab/ci/jobs/debian-testing-clang-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dc790b397f2187b47a75c05bcf3e5973d5a175e1
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-clang-amd64.yml
@@ -0,0 +1,22 @@
+Debian testing Clang:
+  extends: Debian stable Clang
+
+  when: manual
+
+  allow_failure: true
+
+  image: debian:testing-slim
+
+  artifacts:
+    paths:
+      - "build.clang/bin/"
+      - "build.clang/src/config.h"
+    expose_as: "testing-clang"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
+
+  variables:
+    CC: clang
+    CXX: clang
+    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
+    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
+    LDFLAGS: -Wl,-fuse-ld=gold
diff --git a/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..10799b3053e45a3d98fcfa1f63281e36ebadae9d
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
@@ -0,0 +1,46 @@
+Debian testing GCC:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  image: debian:testing-slim
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "testing-gcc"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
+
+  variables:
+    CC: gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-arm64.yml b/.gitlab/ci/jobs/macos-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3928413610a048460dfe05d0dfc8f92e9da76848
--- /dev/null
+++ b/.gitlab/ci/jobs/macos-arm64.yml
@@ -0,0 +1,44 @@
+osxcross arm64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "build.osxcross/bin/"
+      - "build.osxcross/src/config.h"
+    expose_as: "Mac arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    OSXCROSS_HOST: arm64-apple-darwin21.4
+    LD: arm64-apple-darwin21.4-ld
+
+  script:
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
+      - osxcross-macports install --arm64 curl libopenmpt libsdl2_mixer
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-x86_64.yml b/.gitlab/ci/jobs/macos-x86_64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..818028e49a43624f3e29a357d7d7614ef4dd5118
--- /dev/null
+++ b/.gitlab/ci/jobs/macos-x86_64.yml
@@ -0,0 +1,40 @@
+osxcross x86_64:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "build.osxcross/bin/"
+      - "build.osxcross/src/config.h"
+    expose_as: "Mac x86_64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    OSXCROSS_HOST: x86_64-apple-darwin21.4
+    LD: x86_64-apple-darwin21.4-ld
+
+  script:
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
+      - osxcross-macports install curl libopenmpt libsdl2_mixer
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x64.yml b/.gitlab/ci/jobs/windows-x64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..da8d960bd1330229a2265ed9b015a487f1040e75
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x64.yml
@@ -0,0 +1,35 @@
+Windows x64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
+
+  variables:
+    PREFIX: x86_64-w64-mingw32
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-x86-64-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x86.yml b/.gitlab/ci/jobs/windows-x86.yml
new file mode 100644
index 0000000000000000000000000000000000000000..311c767bbd9cd31d1063a248f68c0a6793dd47d5
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x86.yml
@@ -0,0 +1,35 @@
+Windows x86:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win32"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
+
+  variables:
+    PREFIX: i686-w64-mingw32
+    CC: /usr/bin/i686-w64-mingw32-gcc-posix
+    CXX: /usr/bin/i686-w64-mingw32-g++-posix
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-i686-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/templates/srb2ci.yml b/.gitlab/ci/templates/srb2ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3716d9df921407cb29081af301a5b6a3d92db459
--- /dev/null
+++ b/.gitlab/ci/templates/srb2ci.yml
@@ -0,0 +1,145 @@
+.srb2ci:
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:stable
+
+  cache:
+    - key: ccache-$CI_JOB_NAME_SLUG-$CI_COMMIT_REF_SLUG
+      fallback_keys:
+        - ccache-$CI_JOB_NAME_SLUG-$CI_DEFAULT_BRANCH
+        - ccache-$CI_JOB_NAME_SLUG-master
+      paths:
+        - build/ccache
+        - build/ccache_statslog
+
+    - key: apt-$CI_JOB_IMAGE
+      paths:
+        - build/apt-cache
+      unprotect: true
+
+  before_script:
+    - - |
+         # debconf
+         echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
+      - export DEBIAN_FRONTEND="noninteractive"
+      - export DEBIAN_PRIORITY="low"
+      - export DEBCONF_NONINTERACTIVE_SEEN="true"
+      - |
+          # debconf
+          echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
+    - - |
+          # dpkg_aa
+          echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
+      - dpkg --add-architecture i386
+      - dpkg --add-architecture amd64
+      - dpkg --add-architecture arm64
+      - |
+          # dpkg_aa
+          echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
+    - - |
+          # apt_conf
+          echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
+      - export APT_CACHE_DIR=$CI_PROJECT_DIR/build/apt-cache
+      - mkdir --parents --verbose $APT_CACHE_DIR/partial/
+      - touch /etc/apt/apt.conf.d/99build
+      - |
+          # apt.conf
+          echo Adding options to apt.conf':'
+      - |
+          # APT::Install-Recommends
+          echo APT::Install-Recommends "false"\;       | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # quit
+          echo quiet "1"\;                             | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # APT::Get::Assume-Yes
+          echo APT::Get::Assume-Yes "true"\;           | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # Dir::Cache::Archives
+          echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # apt_conf
+          echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
+    - - |
+          # apt_update
+          echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
+      - apt-get update
+      - |
+          # apt_update
+          echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
+
+    - - |
+          # apt_pre
+          echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
+      - apt-get install apt-utils
+      - |
+          # apt_pre
+          echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
+
+    - - |
+          # apt_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apt-get upgrade
+      - |
+          # apt_update
+          echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
+
+    - - |
+          # apt_common
+          echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apt-get install make git ccache nasm cmake ca-certificates
+      - |
+          # apt_common
+          echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $CI_PROJECT_DIR                        | tee --append ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $CI_PROJECT_DIR/build/ccache          | tee --append ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content                          | tee --append ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $CI_PROJECT_DIR/build/ccache_statslog | tee --append ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 300M                                   | tee --append ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  after_script:
+    - - |
+           # apt_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
+      - apt-get autoclean
+      - |
+          # apt_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats
+      - ccache --show-log-stats || true
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8803620e7a9305cb28359aa31c973223d4df247f..3b08a9facc348aad76f77b55a5700b8929859333 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,6 @@ endif()
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
 include(CMakeDependentOption)
-include(cmake/CPM.cmake)
 
 file(STRINGS src/version.h SRB2_VERSION)
 string(REGEX MATCH "[0-9]+\\.[0-9.]+" SRB2_VERSION ${SRB2_VERSION})
@@ -46,30 +45,26 @@ SET(CPACK_OUTPUT_FILE_PREFIX package)
 include(CPack)
 
 # Options
-
-if("${CMAKE_SYSTEM_NAME}" MATCHES Linux)
-	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
+if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
+	if(DEFINED VCPKG_TARGET_TRIPLET)
+		set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
+	else()
+		set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF)
+	endif()
 else()
-	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF)
+	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
 endif()
 
 # Clang tidy options will be ignored if CMAKE_<LANG>_CLANG_TIDY are set.
 option(SRB2_CONFIG_ENABLE_CLANG_TIDY_C "Enable default clang-tidy check configuration for C" OFF)
 option(SRB2_CONFIG_ENABLE_CLANG_TIDY_CXX "Enable default clang-tidy check configuration for C++" OFF)
 option(
-	SRB2_CONFIG_SYSTEM_LIBRARIES
-	"Link dependencies using CMake's find_package and do not use internal builds"
-	${SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT}
-)
-option(SRB2_CONFIG_ENABLE_TESTS "Build the test suite" ON)
-# This option isn't recommended for distribution builds and probably won't work (yet).
-cmake_dependent_option(
-	SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES
-	"Use dynamic libraries when compiling internal dependencies"
-	OFF "NOT SRB2_CONFIG_SYSTEM_LIBRARIES"
-	OFF
+	SRB2_CONFIG_STATIC_STDLIB
+	"Link static version of standard library. All dependencies must also be static"
+	ON
 )
 option(SRB2_CONFIG_HWRENDER "Enable hardware render (OpenGL) support" ON)
+option(SRB2_CONFIG_USE_GME "Enable GME playback support" OFF)
 option(SRB2_CONFIG_STATIC_OPENGL "Enable static linking GL (do not do this)" OFF)
 option(SRB2_CONFIG_ERRORMODE "Compile C code with warnings treated as errors." OFF)
 option(SRB2_CONFIG_DEBUGMODE "Compile with PARANOIA, ZDEBUG, RANGECHECK and PACKETDROP defined." OFF)
@@ -81,63 +76,27 @@ option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF)
 option(SRB2_CONFIG_PROFILEMODE "Compile for profiling (GCC only)." OFF)
 set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.")
 
-if(SRB2_CONFIG_ENABLE_TESTS)
-	# https://github.com/catchorg/Catch2
-	CPMAddPackage(
-		NAME Catch2
-		VERSION 3.4.0
-		GITHUB_REPOSITORY catchorg/Catch2
-		OPTIONS
-			"CATCH_INSTALL_DOCS OFF"
-	)
-	list(APPEND CMAKE_MODULE_PATH "${Catch2_SOURCE_DIR}/extras")
-	include(CTest)
-	include(Catch)
-	add_executable(srb2tests)
-	# To add tests, use target_sources to add individual test files to the target in subdirs.
-	target_link_libraries(srb2tests PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
-	target_compile_features(srb2tests PRIVATE c_std_11 cxx_std_17)
-	catch_discover_tests(srb2tests)
-endif()
+# Dependencies
+add_subdirectory(thirdparty)
 
-# Enable CCache
-# (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options)
-if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows)
-	option(USE_CCACHE "Enable ccache support" OFF)
-
-	if(USE_CCACHE)
-		find_program(CCACHE_TOOL_PATH ccache)
-		if(CCACHE_TOOL_PATH)
-			set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
-			set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
-		else()
-			message(WARNING "USE_CCACHE was set but ccache is not found (set CCACHE_TOOL_PATH)")
-		endif()
-	endif()
+if(SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
+	set(SRB2_INTERNAL_LIBRARY_TYPE SHARED)
+	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES OFF)
 else()
-	CPMAddPackage(
-		NAME Ccache.cmake
-		GITHUB_REPOSITORY TheLartians/Ccache.cmake
-		VERSION 1.2
-	)
+	set(SRB2_INTERNAL_LIBRARY_TYPE STATIC)
+	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES ON)
 endif()
 
-# Dependencies
-add_subdirectory(thirdparty)
 
-if("${SRB2_CONFIG_SYSTEM_LIBRARIES}")
-	find_package(ZLIB REQUIRED)
-	find_package(PNG REQUIRED)
-	find_package(SDL2 REQUIRED)
-	find_package(SDL2_mixer REQUIRED)
-	find_package(CURL REQUIRED)
-	find_package(OPENMPT REQUIRED)
-
-	# libgme defaults to "Nuked" YM2612 emulator, which is
-	# very SLOW. The system library probably uses the
-	# default so just always build it.
-	#find_package(GME REQUIRED)
+find_package(ZLIB REQUIRED)
+find_package(PNG REQUIRED)
+find_package(CURL REQUIRED)
+find_package(libopenmpt QUIET)
+if("${SRB2_CONFIG_USE_GME}")
+	find_package(libgme QUIET)
 endif()
+find_package(miniupnpc QUIET)
+
 
 if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
 	message(FATAL_ERROR "In-source builds will bring you a world of pain. Please make a separate directory to invoke CMake from.")
diff --git a/CMakePresets.json b/CMakePresets.json
index effea7260656c6235c75b07669edea01eeb682b7..8cb95d797f7f4c3ae708effa15e0d38112175937 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -2,26 +2,263 @@
 	"version": 3,
 	"configurePresets": [
 		{
-			"name": "default",
-			"description": "Build using default generator",
-			"binaryDir": "build",
+			"name": "__debug",
+			"hidden": true,
 			"cacheVariables": {
+				"SRB2_CONFIG_DEV_BUILD": "ON",
+				"CMAKE_BUILD_TYPE": "Debug"
+			}
+		},
+		{
+			"name": "__develop",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_C_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"SRB2_CONFIG_DEV_BUILD": "ON",
 				"CMAKE_BUILD_TYPE": "RelWithDebInfo"
 			}
 		},
 		{
-			"name": "debug",
-			"description": "Build for development (no optimizations)",
-			"inherits": "default",
+			"name": "__release",
+			"hidden": true,
 			"cacheVariables": {
-				"CMAKE_BUILD_TYPE": "Debug"
+				"CMAKE_C_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"SRB2_CONFIG_DEV_BUILD": "OFF",
+				"CMAKE_BUILD_TYPE": "RelWithDebInfo"
+			}
+		},
+		{
+			"name": "__testers",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_C_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"SRB2_CONFIG_DEV_BUILD": "ON",
+				"CMAKE_BUILD_TYPE": "RelWithDebInfo",
+				"SRB2_CONFIG_TESTERS": "ON"
+			}
+		},
+		{
+			"name": "__ninja",
+			"hidden": true,
+			"generator": "Ninja",
+			"cacheVariables": {
+				"CMAKE_COLOR_DIAGNOSTICS": "ON"
+			}
+		},
+		{
+			"name": "__vcpkg-toolchain",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
+			}
+		},
+		{
+			"name": "__compiler-mingw-w64-i686",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_C_COMPILER": "i686-w64-mingw32-gcc",
+				"CMAKE_CXX_COMPILER": "i686-w64-mingw32-g++"
+			}
+		},
+		{
+			"name": "__mingw-dynamic",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_TARGET_TRIPLET": "x86-mingw-dynamic"
 			}
+		},
+		{
+			"name": "__mingw-static",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_HOST_TRIPLET": "x86-mingw-static",
+				"VCPKG_TARGET_TRIPLET": "x86-mingw-static"
+			}
+		},
+		{
+			"name": "__osx_x64",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_TARGET_TRIPLET": "x64-osx"
+			}
+		},
+		{
+			"name": "__osx_arm64",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_TARGET_TRIPLET": "arm64-osx"
+			}
+		},
+
+		{
+			"name": "ninja-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja"]
+		},
+		{
+			"name": "ninja-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja"]
+		},
+		{
+			"name": "ninja-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja"]
+		},
+		{
+			"name": "ninja-testers",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__testers", "__ninja"]
+		},
+
+		{
+			"name": "ninja-vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja", "__vcpkg-toolchain"]
+		},
+		{
+			"name": "ninja-vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja", "__vcpkg-toolchain"]
+		},
+		{
+			"name": "ninja-vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja", "__vcpkg-toolchain"]
+		},
+		{
+			"name": "ninja-vcpkg-testers",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__testers", "__ninja", "__vcpkg-toolchain"]
+		},
+
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-testers",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__testers", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+
+		{
+			"name": "ninja-x64_osx_vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja", "__vcpkg-toolchain", "__osx_x64"]
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja", "__vcpkg-toolchain", "__osx_x64"]
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja", "__vcpkg-toolchain", "__osx_x64"]
+		},
+
+		{
+			"name": "ninja-arm64_osx_vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja", "__vcpkg-toolchain", "__osx_arm64"]
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja", "__vcpkg-toolchain", "__osx_arm64"]
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja", "__vcpkg-toolchain", "__osx_arm64"]
 		}
 	],
+
 	"buildPresets": [
 		{
-			"name": "default",
-			"configurePreset": "default"
+			"name": "ninja-debug",
+			"configurePreset": "ninja-debug"
+		},
+		{
+			"name": "ninja-develop",
+			"configurePreset": "ninja-develop"
+		},
+		{
+			"name": "ninja-release",
+			"configurePreset": "ninja-release"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-debug",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-debug"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-develop",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-develop"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-release",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-release"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-testers",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-testers"
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-debug",
+			"configurePreset": "ninja-x64_osx_vcpkg-debug"
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-develop",
+			"configurePreset": "ninja-x64_osx_vcpkg-develop"
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-release",
+			"configurePreset": "ninja-x64_osx_vcpkg-release"
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-debug",
+			"configurePreset": "ninja-arm64_osx_vcpkg-debug"
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-develop",
+			"configurePreset": "ninja-arm64_osx_vcpkg-develop"
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-release",
+			"configurePreset": "ninja-arm64_osx_vcpkg-release"
 		}
 	]
-}
+}
\ No newline at end of file
diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake
deleted file mode 100644
index fba27d2fef3d2bf2edb50ea41687157dc0730c20..0000000000000000000000000000000000000000
--- a/cmake/CPM.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-set(CPM_DOWNLOAD_VERSION 0.38.7)
-
-if(CPM_SOURCE_CACHE)
-  set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
-elseif(DEFINED ENV{CPM_SOURCE_CACHE})
-  set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
-else()
-  set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
-endif()
-
-# Expand relative path. This is important if the provided path contains a tilde (~)
-get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
-if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
-  message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
-  file(DOWNLOAD
-       https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
-       ${CPM_DOWNLOAD_LOCATION}
-  )
-endif()
-
-include(${CPM_DOWNLOAD_LOCATION})
diff --git a/cmake/Modules/FindGME.cmake b/cmake/Modules/FindGME.cmake
deleted file mode 100644
index 3af0a94be604f44cf0eda200f3d90a129ea77809..0000000000000000000000000000000000000000
--- a/cmake/Modules/FindGME.cmake
+++ /dev/null
@@ -1,33 +0,0 @@
-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)
-
-if(GME_FOUND AND NOT TARGET gme)
-	add_library(gme UNKNOWN IMPORTED)
-	set_target_properties(
-		gme
-		PROPERTIES
-		IMPORTED_LOCATION "${GME_LIBRARY}"
-		INTERFACE_INCLUDE_DIRECTORIES "${GME_INCLUDE_DIR}"
-	)
-endif()
diff --git a/cmake/Modules/FindOPENMPT.cmake b/cmake/Modules/FindOPENMPT.cmake
deleted file mode 100644
index 7e5b2d5a3966be22d22afdb815934cf20fe0e4d7..0000000000000000000000000000000000000000
--- a/cmake/Modules/FindOPENMPT.cmake
+++ /dev/null
@@ -1,33 +0,0 @@
-include(LibFindMacros)
-
-libfind_pkg_check_modules(OPENMPT_PKGCONF OPENMPT)
-
-find_path(OPENMPT_INCLUDE_DIR
-	NAMES libopenmpt.h
-	PATHS
-		${OPENMPT_PKGCONF_INCLUDE_DIRS}
-		"/usr/include/libopenmpt"
-		"/usr/local/include/libopenmpt"
-)
-
-find_library(OPENMPT_LIBRARY
-	NAMES openmpt
-	PATHS
-		${OPENMPT_PKGCONF_LIBRARY_DIRS}
-		"/usr/lib"
-		"/usr/local/lib"
-)
-
-set(OPENMPT_PROCESS_INCLUDES OPENMPT_INCLUDE_DIR)
-set(OPENMPT_PROCESS_LIBS OPENMPT_LIBRARY)
-libfind_process(OPENMPT)
-
-if(OPENMPT_FOUND AND NOT TARGET openmpt)
-	add_library(openmpt UNKNOWN IMPORTED)
-	set_target_properties(
-		openmpt
-		PROPERTIES
-		IMPORTED_LOCATION "${OPENMPT_LIBRARY}"
-		INTERFACE_INCLUDE_DIRECTORIES "${OPENMPT_INCLUDE_DIR}"
-	)
-endif()
diff --git a/cmake/Modules/Findlibgme.cmake b/cmake/Modules/Findlibgme.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6b693a7fd14234eb89c24798ea340b6a39030d33
--- /dev/null
+++ b/cmake/Modules/Findlibgme.cmake
@@ -0,0 +1,38 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(libgme_PKGCONF gme libgme)
+
+find_path(libgme_INCLUDE_DIR
+	NAMES gme.h
+	PATHS
+		${libgme_PKGCONF_INCLUDE_DIRS}
+		"/usr/include"
+		"/usr/local/include"
+	PATH_SUFFIXES
+		gme
+)
+
+find_library(libgme_LIBRARY
+	NAMES gme
+	PATHS
+		${libgme_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(libgme
+    REQUIRED_VARS libgme_LIBRARY libgme_INCLUDE_DIR)
+
+if(libgme_FOUND AND NOT TARGET gme)
+	add_library(gme UNKNOWN IMPORTED)
+	set_target_properties(
+		gme
+		PROPERTIES
+		IMPORTED_LOCATION "${libgme_LIBRARY}"
+		INTERFACE_INCLUDE_DIRECTORIES "${libgme_INCLUDE_DIR}"
+	)
+	add_library(gme::gme ALIAS gme)
+endif()
+
+mark_as_advanced(libgme_LIBRARY libgme_INCLUDE_DIR)
diff --git a/cmake/Modules/Findlibopenmpt.cmake b/cmake/Modules/Findlibopenmpt.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..d7de22134831c1e0edc8b3b6e62ed42abd69287f
--- /dev/null
+++ b/cmake/Modules/Findlibopenmpt.cmake
@@ -0,0 +1,37 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(libopenmpt_PKGCONF openmpt)
+
+find_path(libopenmpt_INCLUDE_DIR
+	NAMES libopenmpt.h
+	PATHS
+		${libopenmpt_PKGCONF_INCLUDE_DIRS}
+		"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/libopenmpt"
+		"/usr/include/libopenmpt"
+		"/usr/local/include/libopenmpt"
+)
+
+find_library(libopenmpt_LIBRARY
+	NAMES openmpt
+	PATHS
+		${libopenmpt_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(libopenmpt
+    REQUIRED_VARS libopenmpt_LIBRARY libopenmpt_INCLUDE_DIR)
+
+if(libopenmpt_FOUND AND NOT TARGET openmpt)
+	add_library(openmpt UNKNOWN IMPORTED)
+	set_target_properties(
+		openmpt
+		PROPERTIES
+		IMPORTED_LOCATION "${libopenmpt_LIBRARY}"
+		INTERFACE_INCLUDE_DIRECTORIES "${libopenmpt_INCLUDE_DIR}"
+	)
+	add_library(libopenmpt::libopenmpt ALIAS openmpt)
+endif()
+
+mark_as_advanced(libopenmpt_LIBRARY libopenmpt_INCLUDE_DIR)
diff --git a/cmake/Modules/Findminiupnpc.cmake b/cmake/Modules/Findminiupnpc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f4931ad832eb856583be1c12daaf4d9883847ed3
--- /dev/null
+++ b/cmake/Modules/Findminiupnpc.cmake
@@ -0,0 +1,39 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(libminiupnpc_PKGCONF miniupnpc libminiupnpc)
+
+find_path(libminiupnpc_INCLUDE_DIR
+	NAMES miniupnpc.h
+	PATHS
+		${libminiupnpc_PKGCONF_INCLUDE_DIRS}
+		"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include"
+		"/usr/include"
+		"/usr/local/include"
+	PATH_SUFFIXES
+		miniupnpc
+)
+
+find_library(libminiupnpc_LIBRARY
+	NAMES miniupnpc
+	PATHS
+		${libminiupnpc_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(miniupnpc
+    REQUIRED_VARS libminiupnpc_LIBRARY libminiupnpc_INCLUDE_DIR)
+
+if(miniupnpc_FOUND AND NOT TARGET miniupnpc)
+	add_library(miniupnpc UNKNOWN IMPORTED)
+	set_target_properties(
+		miniupnpc
+		PROPERTIES
+		IMPORTED_LOCATION "${libminiupnpc_LIBRARY}"
+		INTERFACE_INCLUDE_DIRECTORIES "${libminiupnpc_INCLUDE_DIR}"
+	)
+	add_library(miniupnpc::miniupnpc ALIAS miniupnpc)
+endif()
+
+mark_as_advanced(libminiupnpc_LIBRARY libminiupnpc_INCLUDE_DIR)
diff --git a/cmake/PatchFile.cmake b/cmake/PatchFile.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f80da3434d764fdbc1eb1f0219c38204517ee19a
--- /dev/null
+++ b/cmake/PatchFile.cmake
@@ -0,0 +1,30 @@
+# use GNU Patch from any platform
+
+if(WIN32)
+  # prioritize Git Patch on Windows as other Patches may be very old and incompatible.
+  find_package(Git)
+  if(Git_FOUND)
+    get_filename_component(GIT_DIR ${GIT_EXECUTABLE} DIRECTORY)
+    get_filename_component(GIT_DIR ${GIT_DIR} DIRECTORY)
+  endif()
+endif()
+
+find_program(PATCH
+NAMES patch
+HINTS ${GIT_DIR}
+PATH_SUFFIXES usr/bin
+)
+
+if(NOT PATCH)
+  message(FATAL_ERROR "Did not find GNU Patch")
+endif()
+
+execute_process(COMMAND ${PATCH} ${in_file} --input=${patch_file} --output=${out_file} --ignore-whitespace
+TIMEOUT 15
+COMMAND_ECHO STDOUT
+RESULT_VARIABLE ret
+)
+
+if(NOT ret EQUAL 0)
+  message(FATAL_ERROR "Failed to apply patch ${patch_file} to ${in_file} with ${PATCH}")
+endif()
\ No newline at end of file
diff --git a/cmake/Toolchains/mingw-w64-i686.cmake b/cmake/Toolchains/mingw-w64-i686.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6b327291d79d905e7fd97e99196e8b0809fa8d06
--- /dev/null
+++ b/cmake/Toolchains/mingw-w64-i686.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(TOOLCHAIN_PREFIX i686-w64-mingw32)
+
+# cross compilers to use for C, C++ and Fortran
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
+set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
+set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
+
+# target environment on the build host system
+set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
+
+# modify default behavior of FIND_XXX() commands
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/cmake/Toolchains/mingw-w64-x86_64.cmake b/cmake/Toolchains/mingw-w64-x86_64.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..2f22e13d8a5dc80e869c5ca2f0089e5d9917ff7d
--- /dev/null
+++ b/cmake/Toolchains/mingw-w64-x86_64.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
+
+# cross compilers to use for C, C++ and Fortran
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
+set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
+set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
+
+# target environment on the build host system
+set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
+
+# modify default behavior of FIND_XXX() commands
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/doc/specs/udmf_srb2.txt b/doc/specs/udmf_srb2.txt
index c758d7e40f13d466afcfc689c679845fec71b906..b25ed1af38ee55b6c2ecf568c824520d800c58e7 100644
--- a/doc/specs/udmf_srb2.txt
+++ b/doc/specs/udmf_srb2.txt
@@ -228,6 +228,8 @@ Sonic Robo Blast 2 defines the following standardized fields:
       ropehang           = <bool>;     // Sector is a rope hang. Must be applied to a 3D floor.
       jumpflip           = <bool>;     // Sector flips the gravity of players who jump from it.
       gravityoverride    = <bool>;     // Reverse gravity effect is only applied when an object is in the sector.
+      nophysics_floor    = <bool>;     // Disables floor slope physics if created through a plane equation.
+      nophysics_ceiling  = <bool>;     // Disables ceiling slope physics if created through a plane equation.
 
       friction            = <float>;   // Sector's friction factor.
       gravity             = <float>;   // Sector's gravity. Default is 1.0.
diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg
index aee7a70e4e0a4b806d8c0a055d77f06fce476ea6..90c85cdea40827970a7b44222e9a2f6a5e2668f6 100644
--- a/extras/conf/udb/Includes/SRB222_common.cfg
+++ b/extras/conf/udb/Includes/SRB222_common.cfg
@@ -39,6 +39,7 @@ common
 	defaulttexturescale = 1.0f;
 	defaultflatscale = 1.0f;
 	scaledtextureoffsets = true;
+	scaledflatoffsets = true;
 
 	// Colormap/fade related options
 	maxcolormapalpha = 25;
diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index e297f473fd46d2848f3835765988bb913147e84f..fc505fb6025b02782d1a309b247f569a63dd96fd 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -7,13 +7,11 @@ udmf
 		0
 		{
 			title = "None";
-			prefix = "(0)";
 		}
 		
 		6
 		{
 			title = "Sector Set Portal";
-			prefix = "(6)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -52,7 +50,6 @@ udmf
 		7
 		{
 			title = "Sector Flat Alignment";
-			prefix = "(7)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -70,7 +67,6 @@ udmf
 		10
 		{
 			title = "Culling Plane";
-			prefix = "(10)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -91,20 +87,17 @@ udmf
 		40
 		{
 			title = "Visual Portal Between Tagged Linedefs";
-			prefix = "(40)";
 		}
 
 		41
 		{
 			title = "Horizon Effect";
 			id = "srb2_horizonline";
-			prefix = "(41)";
 		}
 
 		63
 		{
 			title = "Fake Floor/Ceiling Planes";
-			prefix = "(63)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -120,7 +113,6 @@ udmf
 		2
 		{
 			title = "Custom Exit";
-			prefix = "(2)";
 			arg0
 			{
 				title = "Next map";
@@ -144,7 +136,6 @@ udmf
 		3
 		{
 			title = "Zoom Tube Parameters";
-			prefix = "(3)";
 			arg0
 			{
 				title = "Speed";
@@ -166,7 +157,6 @@ udmf
 		4
 		{
 			title = "Speed Pad Parameters";
-			prefix = "(4)";
 			arg0
 			{
 				title = "Speed";
@@ -193,7 +183,6 @@ udmf
 		8
 		{
 			title = "Set Camera Collision Planes";
-			prefix = "(8)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -204,7 +193,6 @@ udmf
 		11
 		{
 			title = "Rope Hang Parameters";
-			prefix = "(11)";
 			arg0
 			{
 				title = "Speed";
@@ -226,7 +214,6 @@ udmf
 		14
 		{
 			title = "Bustable Block Parameters";
-			prefix = "(14)";
 			arg0
 			{
 				title = "Debris spacing";
@@ -252,13 +239,11 @@ udmf
 		15
 		{
 			title = "Fan Particle Generator Heights";
-			prefix = "(15)";
 		}
 
 		16
 		{
 			title = "Minecart Parameters";
-			prefix = "(16)";
 			arg0
 			{
 				title = "Order";
@@ -268,7 +253,6 @@ udmf
 		64
 		{
 			title = "Continuously Appearing/Disappearing FOF";
-			prefix = "(64)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -307,7 +291,6 @@ udmf
 		20
 		{
 			title = "PolyObject First Line";
-			prefix = "(20)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -348,7 +331,6 @@ udmf
 		30
 		{
 			title = "Waving PolyObject Flag";
-			prefix = "(30)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -369,7 +351,6 @@ udmf
 		31
 		{
 			title = "Move PolyObject by Front Sector Displacement";
-			prefix = "(31)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -385,7 +366,6 @@ udmf
 		32
 		{
 			title = "Rotate PolyObject by Front Sector Displacement";
-			prefix = "(32)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -421,7 +401,6 @@ udmf
 		52
 		{
 			title = "Continuously Falling Sector";
-			prefix = "(52)";
 			arg0
 			{
 				title = "Speed";
@@ -442,7 +421,6 @@ udmf
 		53
 		{
 			title = "Continuous Plane Mover (Slowdown)";
-			prefix = "(53)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -477,7 +455,6 @@ udmf
 		56
 		{
 			title = "Continuous Plane Mover (Constant)";
-			prefix = "(56)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -512,7 +489,6 @@ udmf
 		60
 		{
 			title = "Activate Moving Platform";
-			prefix = "(60)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -542,7 +518,6 @@ udmf
 		61
 		{
 			title = "Ceiling Crusher";
-			prefix = "(61)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -573,7 +548,6 @@ udmf
 		66
 		{
 			title = "Move Planes by Front Sector Displacement";
-			prefix = "(66)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -600,7 +574,6 @@ udmf
 		70
 		{
 			title = "Add Raise Thinker";
-			prefix = "(70)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -626,7 +599,6 @@ udmf
 		71
 		{
 			title = "Add Air Bobbing Thinker";
-			prefix = "(71)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -652,7 +624,6 @@ udmf
 		72
 		{
 			title = "Add Thwomp Thinker";
-			prefix = "(72)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -679,7 +650,6 @@ udmf
 		73
 		{
 			title = "Add Laser Thinker";
-			prefix = "(73)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -696,7 +666,6 @@ udmf
 		74
 		{
 			title = "Make FOF Bustable";
-			prefix = "(74)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -735,7 +704,6 @@ udmf
 		75
 		{
 			title = "Make FOF Quicksand";
-			prefix = "(75)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -755,7 +723,6 @@ udmf
 		76
 		{
 			title = "Make FOF Bouncy";
-			prefix = "(76)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -775,7 +742,6 @@ udmf
 		100
 		{
 			title = "Solid";
-			prefix = "(100)";
 			id = "srb2_fofsolid";
 			arg0
 			{
@@ -819,7 +785,6 @@ udmf
 		120
 		{
 			title = "Water";
-			prefix = "(120)";
 			id = "srb2_fofwater";
 			arg0
 			{
@@ -857,7 +822,6 @@ udmf
 		150
 		{
 			title = "Air Bobbing";
-			prefix = "(150)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -884,7 +848,6 @@ udmf
 		160
 		{
 			title = "Water Bobbing";
-			prefix = "(160)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -896,7 +859,6 @@ udmf
 		170
 		{
 			title = "Crumbling";
-			prefix = "(170)";
 			id = "srb2_fofcrumbling";
 			arg0
 			{
@@ -939,7 +901,6 @@ udmf
 		190
 		{
 			title = "Rising";
-			prefix = "(190)";
 			id = "srb2_fofsolid";
 			arg0
 			{
@@ -998,7 +959,6 @@ udmf
 		200
 		{
 			title = "Light Block";
-			prefix = "(200)";
 			id = "srb2_foflight";
 			arg0
 			{
@@ -1016,7 +976,6 @@ udmf
 		202
 		{
 			title = "Fog Block";
-			prefix = "(202)";
 			id = "srb2_foffog";
 			arg0
 			{
@@ -1028,7 +987,6 @@ udmf
 		220
 		{
 			title = "Intangible";
-			prefix = "(220)";
 			id = "srb2_fofintangible";
 			arg0
 			{
@@ -1066,7 +1024,6 @@ udmf
 		223
 		{
 			title = "Intangible, Invisible";
-			prefix = "(223)";
 			id = "srb2_fofintangibleinvisible";
 			arg0
 			{
@@ -1078,7 +1035,6 @@ udmf
 		250
 		{
 			title = "Mario Block";
-			prefix = "(250)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1100,7 +1056,6 @@ udmf
 		251
 		{
 			title = "Thwomp Block";
-			prefix = "(251)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1128,7 +1083,6 @@ udmf
 		254
 		{
 			title = "Bustable Block";
-			prefix = "(254)";
 			id = "srb2_fofbustable";
 			arg0
 			{
@@ -1181,7 +1135,6 @@ udmf
 		257
 		{
 			title = "Quicksand";
-			prefix = "(257)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1208,7 +1161,6 @@ udmf
 		258
 		{
 			title = "Laser";
-			prefix = "(258)";
 			id = "srb2_foflaser";
 			arg0
 			{
@@ -1242,7 +1194,6 @@ udmf
 		259
 		{
 			title = "Custom";
-			prefix = "(259)";
 			id = "srb2_fofcustom";
 			arg0
 			{
@@ -1307,7 +1258,6 @@ udmf
 		300
 		{
 			title = "Basic";
-			prefix = "(300)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1319,7 +1269,6 @@ udmf
 		303
 		{
 			title = "Ring Count";
-			prefix = "(303)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1347,7 +1296,6 @@ udmf
 		305
 		{
 			title = "Character Ability";
-			prefix = "(305)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1383,7 +1331,6 @@ udmf
 		308
 		{
 			title = "Gametype";
-			prefix = "(308)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1441,7 +1388,6 @@ udmf
 		309
 		{
 			title = "CTF Team";
-			prefix = "(309)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1459,7 +1405,6 @@ udmf
 		313
 		{
 			title = "No More Enemies";
-			prefix = "(313)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1470,7 +1415,6 @@ udmf
 		314
 		{
 			title = "Number of Pushables";
-			prefix = "(314)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1492,7 +1436,6 @@ udmf
 		317
 		{
 			title = "Condition Set Trigger";
-			prefix = "(317)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1508,7 +1451,6 @@ udmf
 		319
 		{
 			title = "Unlockable";
-			prefix = "(319)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1524,7 +1466,6 @@ udmf
 		321
 		{
 			title = "Trigger After X Calls";
-			prefix = "(321)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1550,7 +1491,6 @@ udmf
 		323
 		{
 			title = "NiGHTSerize";
-			prefix = "(323)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1617,7 +1557,6 @@ udmf
 		325
 		{
 			title = "De-NiGHTSerize";
-			prefix = "(325)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1680,7 +1619,6 @@ udmf
 		327
 		{
 			title = "NiGHTS Lap";
-			prefix = "(327)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1732,7 +1670,6 @@ udmf
 		329
 		{
 			title = "Ideya Capture Touch";
-			prefix = "(329)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1800,7 +1737,6 @@ udmf
 		331
 		{
 			title = "Player Skin";
-			prefix = "(331)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1823,7 +1759,6 @@ udmf
 		334
 		{
 			title = "Object Dye";
-			prefix = "(334)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1846,7 +1781,6 @@ udmf
 		337
 		{
 			title = "Emerald Check";
-			prefix = "(337)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1879,7 +1813,6 @@ udmf
 		340
 		{
 			title = "NiGHTS Mare";
-			prefix = "(340)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1901,7 +1834,6 @@ udmf
 		343
 		{
 			title = "Gravity Check";
-			prefix = "(343)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1924,7 +1856,6 @@ udmf
 		399
 		{
 			title = "Level Load";
-			prefix = "(399)";
 		}
 	}
 
@@ -1935,7 +1866,6 @@ udmf
 		400
 		{
 			title = "Set Tagged Sector's Heights/Textures";
-			prefix = "(400)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1958,7 +1888,6 @@ udmf
 		402
 		{
 			title = "Copy Light Level to Tagged Sectors";
-			prefix = "(402)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1980,7 +1909,6 @@ udmf
 		408
 		{
 			title = "Set Tagged Sector's Flats";
-			prefix = "(408)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1997,7 +1925,6 @@ udmf
 		409
 		{
 			title = "Change Tagged Sector's Tag";
-			prefix = "(409)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2025,7 +1952,6 @@ udmf
 		410
 		{
 			title = "Change Front Sector's Tag";
-			prefix = "(410)";
 			arg0
 			{
 				title = "Tag";
@@ -2048,7 +1974,6 @@ udmf
 		416
 		{
 			title = "Start Adjustable Flickering Light";
-			prefix = "(416)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2077,7 +2002,6 @@ udmf
 		417
 		{
 			title = "Start Adjustable Pulsating Light";
-			prefix = "(417)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2106,7 +2030,6 @@ udmf
 		418
 		{
 			title = "Start Adjustable Blinking Light";
-			prefix = "(418)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2143,7 +2066,6 @@ udmf
 		420
 		{
 			title = "Fade Light Level";
-			prefix = "(420)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2173,7 +2095,6 @@ udmf
 		421
 		{
 			title = "Stop Lighting Effect";
-			prefix = "(421)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2184,7 +2105,6 @@ udmf
 		435
 		{
 			title = "Change Plane Scroller Direction";
-			prefix = "(435)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2200,7 +2120,6 @@ udmf
 		467
 		{
 			title = "Set Tagged Sector's Light Level";
-			prefix = "(467)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2232,7 +2151,6 @@ udmf
 		469
 		{
 			title = "Change Tagged Sector's Gravity";
-			prefix = "(469)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2284,7 +2202,6 @@ udmf
 		403
 		{
 			title = "Move Tagged Sector's Planes";
-			prefix = "(403)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2317,7 +2234,6 @@ udmf
 		405
 		{
 			title = "Move Planes by Set Distance";
-			prefix = "(405)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2349,7 +2265,6 @@ udmf
 		411
 		{
 			title = "Stop Plane Movement";
-			prefix = "(411)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2360,7 +2275,6 @@ udmf
 		428
 		{
 			title = "Start Platform Movement";
-			prefix = "(428)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2394,7 +2308,6 @@ udmf
 		429
 		{
 			title = "Crush Planes Once";
-			prefix = "(429)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2426,7 +2339,6 @@ udmf
 		412
 		{
 			title = "Teleporter";
-			prefix = "(412)";
 			arg0
 			{
 				title = "Destination thing tag";
@@ -2461,7 +2373,6 @@ udmf
 		425
 		{
 			title = "Change Object State";
-			prefix = "(425)";
 			stringarg0
 			{
 				title = "State";
@@ -2472,7 +2383,6 @@ udmf
 		426
 		{
 			title = "Stop Object";
-			prefix = "(426)";
 			arg0
 			{
 				title = "Move to center?";
@@ -2484,7 +2394,6 @@ udmf
 		427
 		{
 			title = "Award Score";
-			prefix = "(427)";
 			arg0
 			{
 				title = "Score";
@@ -2494,7 +2403,6 @@ udmf
 		432
 		{
 			title = "Enable/Disable 2D Mode";
-			prefix = "(432)";
 			arg0
 			{
 				title = "Mode";
@@ -2510,7 +2418,6 @@ udmf
 		433
 		{
 			title = "Enable/Disable Gravity Flip";
-			prefix = "(433)";
 			arg0
 			{
 				title = "Set gravity";
@@ -2546,7 +2453,6 @@ udmf
 		434
 		{
 			title = "Award Power-Up";
-			prefix = "(434)";
 			stringarg0
 			{
 				title = "Power";
@@ -2562,7 +2468,6 @@ udmf
 		437
 		{
 			title = "Disable Player Control";
-			prefix = "(437)";
 			arg0
 			{
 				title = "Time";
@@ -2578,7 +2483,6 @@ udmf
 		438
 		{
 			title = "Change Object Size";
-			prefix = "(438)";
 			arg0
 			{
 				title = "Size (%)";
@@ -2589,7 +2493,6 @@ udmf
 		442
 		{
 			title = "Change Object Type State";
-			prefix = "(442)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2620,7 +2523,6 @@ udmf
 		457
 		{
 			title = "Track Object's Angle";
-			prefix = "(457)";
 			arg0
 			{
 				title = "Anchor tag";
@@ -2651,13 +2553,11 @@ udmf
 		458
 		{
 			title = "Stop Tracking Object's Angle";
-			prefix = "(458)";
 		}
 
 		460
 		{
 			title = "Award Rings";
-			prefix = "(460)";
 			arg0
 			{
 				title = "Rings";
@@ -2671,7 +2571,6 @@ udmf
 		461
 		{
 			title = "Spawn Object";
-			prefix = "(461)";
 			arg0
 			{
 				title = "X position";
@@ -2717,13 +2616,11 @@ udmf
 		462
 		{
 			title = "Stop Timer/Exit Stage in Record Attack";
-			prefix = "(462)";
 		}
 
 		463
 		{
 			title = "Dye Object";
-			prefix = "(463)";
 			stringarg0
 			{
 				title = "Skin color";
@@ -2734,7 +2631,6 @@ udmf
 		464
 		{
 			title = "Trigger Egg Capsule";
-			prefix = "(464)";
 			arg0
 			{
 				title = "Egg Capsule tag";
@@ -2751,7 +2647,6 @@ udmf
 		466
 		{
 			title = "Set Level Failure State";
-			prefix = "(466)";
 			arg0
 			{
 				title = "State";
@@ -2772,7 +2667,6 @@ udmf
 		413
 		{
 			title = "Change Music";
-			prefix = "(413)";
 			arg0
 			{
 				title = "Flags";
@@ -2823,7 +2717,6 @@ udmf
 		414
 		{
 			title = "Play Sound Effect";
-			prefix = "(414)";
 			arg0
 			{
 				title = "Source";
@@ -2863,7 +2756,6 @@ udmf
 		415
 		{
 			title = "Run Script";
-			prefix = "(415)";
 			stringarg0
 			{
 				title = "Lump name";
@@ -2874,7 +2766,6 @@ udmf
 		422
 		{
 			title = "Switch to Cut-Away View";
-			prefix = "(422)";
 			arg0
 			{
 				title = "Viewpoint tag";
@@ -2889,7 +2780,6 @@ udmf
 		423
 		{
 			title = "Change Sky";
-			prefix = "(423)";
 			arg0
 			{
 				title = "Sky number";
@@ -2905,7 +2795,6 @@ udmf
 		424
 		{
 			title = "Change Weather";
-			prefix = "(424)";
 			arg0
 			{
 				title = "Weather";
@@ -2932,7 +2821,6 @@ udmf
 		436
 		{
 			title = "Shatter FOF";
-			prefix = "(436)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2948,7 +2836,6 @@ udmf
 		439
 		{
 			title = "Change Tagged Linedef's Textures";
-			prefix = "(439)";
 			arg0
 			{
 				title = "Target linedef tag";
@@ -2977,13 +2864,11 @@ udmf
 		440
 		{
 			title = "Start Metal Sonic Race";
-			prefix = "(440)";
 		}
 
 		441
 		{
 			title = "Condition Set Trigger";
-			prefix = "(441)";
 			arg0
 			{
 				title = "Trigger number";
@@ -2993,7 +2878,6 @@ udmf
 		443
 		{
 			title = "Call Lua Function";
-			prefix = "(443)";
 			stringarg0
 			{
 				title = "Function name";
@@ -3004,7 +2888,6 @@ udmf
 		444
 		{
 			title = "Earthquake";
-			prefix = "(444)";
 			arg0
 			{
 				title = "Duration";
@@ -3018,7 +2901,6 @@ udmf
 		445
 		{
 			title = "Make FOF Disappear/Reappear";
-			prefix = "(445)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3044,7 +2926,6 @@ udmf
 		446
 		{
 			title = "Make FOF Crumble";
-			prefix = "(446)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3072,7 +2953,6 @@ udmf
 		447
 		{
 			title = "Change Tagged Sector's Colormap";
-			prefix = "(447)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3108,7 +2988,6 @@ udmf
 		448
 		{
 			title = "Change Skybox";
-			prefix = "(448)";
 			arg0
 			{
 				title = "Viewpoint thing tag";
@@ -3139,7 +3018,6 @@ udmf
 		449
 		{
 			title = "Enable Bosses with Parameter";
-			prefix = "(449)";
 			arg0
 			{
 				title = "Boss ID";
@@ -3159,7 +3037,6 @@ udmf
 		450
 		{
 			title = "Execute Linedef Executor (specific tag)";
-			prefix = "(450)";
 			arg0
 			{
 				title = "Trigger linedef tag";
@@ -3170,7 +3047,6 @@ udmf
 		451
 		{
 			title = "Execute Linedef Executor (random tag in range)";
-			prefix = "(451)";
 			arg0
 			{
 				title = "Start of tag range";
@@ -3186,7 +3062,6 @@ udmf
 		452
 		{
 			title = "Set FOF Translucency";
-			prefix = "(452)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3217,7 +3092,6 @@ udmf
 		453
 		{
 			title = "Fade FOF";
-			prefix = "(453)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3260,7 +3134,6 @@ udmf
 		454
 		{
 			title = "Stop Fading FOF";
-			prefix = "(454)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3282,7 +3155,6 @@ udmf
 		455
 		{
 			title = "Fade Tagged Sector's Colormap";
-			prefix = "(455)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3324,7 +3196,6 @@ udmf
 		456
 		{
 			title = "Stop Fading Tagged Sector's Colormap";
-			prefix = "(456)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3335,7 +3206,6 @@ udmf
 		459
 		{
 			title = "Control Text Prompt";
-			prefix = "(459)";
 			arg0
 			{
 				title = "Prompt number";
@@ -3371,7 +3241,6 @@ udmf
 		465
 		{
 			title = "Set Linedef Executor Delay";
-			prefix = "(465)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3392,7 +3261,6 @@ udmf
 		468
 		{
 			title = "Change Linedef Argument";
-			prefix = "(468)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3422,7 +3290,6 @@ udmf
 		480
 		{
 			title = "PolyObject Door Slide";
-			prefix = "(480)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3446,7 +3313,6 @@ udmf
 		481
 		{
 			title = "PolyObject Door Swing";
-			prefix = "(481)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3471,7 +3337,6 @@ udmf
 		482
 		{
 			title = "Move PolyObject";
-			prefix = "(482)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3497,7 +3362,6 @@ udmf
 		484
 		{
 			title = "Rotate PolyObject";
-			prefix = "(484)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3531,7 +3395,6 @@ udmf
 		488
 		{
 			title = "Move PolyObject by Waypoints";
-			prefix = "(488)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3573,7 +3436,6 @@ udmf
 		489
 		{
 			title = "Set PolyObject Visibility/Tangibility";
-			prefix = "(489)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3606,7 +3468,6 @@ udmf
 		491
 		{
 			title = "Set PolyObject Translucency";
-			prefix = "(491)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3628,7 +3489,6 @@ udmf
 		492
 		{
 			title = "Fade PolyObject Translucency";
-			prefix = "(492)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3666,7 +3526,6 @@ udmf
 		500
 		{
 			title = "Scroll Wall";
-			prefix = "(500)";
 			arg0
 			{
 				title = "Side";
@@ -3686,7 +3545,6 @@ udmf
 		502
 		{
 			title = "Scroll Tagged Walls";
-			prefix = "(502)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3717,7 +3575,6 @@ udmf
 		510
 		{
 			title = "Scroll Planes";
-			prefix = "(510)";
 			arg0
 			{
 				title = "Sector tag";
@@ -3755,7 +3612,6 @@ udmf
 		541
 		{
 			title = "Wind/Current";
-			prefix = "(541)";
 			arg0
 			{
 				title = "Sector tag";
@@ -3800,7 +3656,6 @@ udmf
 		600
 		{
 			title = "Copy Light Level to Tagged Sector's Planes";
-			prefix = "(600)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3817,7 +3672,6 @@ udmf
 		602
 		{
 			title = "Adjustable Pulsating Light";
-			prefix = "(602)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3846,7 +3700,6 @@ udmf
 		603
 		{
 			title = "Adjustable Flickering Light";
-			prefix = "(603)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3875,7 +3728,6 @@ udmf
 		604
 		{
 			title = "Adjustable Blinking Light";
-			prefix = "(604)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3912,7 +3764,6 @@ udmf
 		606
 		{
 			title = "Copy Colormap";
-			prefix = "(606)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3933,7 +3784,6 @@ udmf
 		700
 		{
 			title = "Create Sector-Based Slope";
-			prefix = "(700)";
 			id = "plane_align";
 			arg0
 			{
@@ -3963,7 +3813,6 @@ udmf
 		704
 		{
 			title = "Create Vertex-Based Slope";
-			prefix = "(704)";
 			id = "srb2_vertexslope";
 			arg0
 			{
@@ -4007,7 +3856,6 @@ udmf
 		720
 		{
 			title = "Copy Slope";
-			prefix = "(720)";
 			id = "plane_copy";
 			arg0
 			{
@@ -4046,7 +3894,6 @@ udmf
 		799
 		{
 			title = "Set Tagged Dynamic Slope Vertex to Front Sector Height";
-			prefix = "(799)";
 			arg0
 			{
 				title = "Apply height";
diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index 405d043c140995b4ed840528878cc6eda7c53346..37b01d7dd56eadaeb1eb3ae4759fb74efc79e61f 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -78,6 +78,8 @@ sectorflags
 	ropehang = "Rope Hang";
 	jumpflip = "Flip Gravity on Jump";
 	gravityoverride = "Make Reverse Gravity Temporary";
+	nophysics_floor = "Disable Floor Slope Physics";
+	nophysics_ceiling = "Disable Ceiling Slope Physics";
 	flipspecial_nofloor = "No Trigger on Floor Touch";
 	flipspecial_ceiling = "Trigger on Ceiling Touch";
 	triggerspecial_touch = "Trigger on Edge Touch";
@@ -114,6 +116,8 @@ sectorflagscategories
 	ropehang = "special";
 	jumpflip = "special";
 	gravityoverride = "special";
+	nophysics_floor = "special";
+	nophysics_ceiling = "special";
 	flipspecial_nofloor = "trigger";
 	flipspecial_ceiling = "trigger";
 	triggerspecial_touch = "trigger";
@@ -586,6 +590,12 @@ universalfields
 			type = 3;
 			default = false;
 		}
+
+		triggertag
+		{
+			type = 0;
+			default = 0;
+		}
 	}
 }
 
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index 990f8dca9f505b57f1797c49ed0d8ae003d18d5d..c028f9439c493d156e1ded87f7a116cc4b14d9d7 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -3938,6 +3938,7 @@ udmf
 			width = 30;
 			height = 32;
 			color = 17;
+			hangs = 1;
 			arg0
 			{
 				title = "Initial delay";
diff --git a/libs/SDL2/WhatsNew.txt b/libs/SDL2/WhatsNew.txt
index 4e17d25aaab278221b4c0d038f4c6bb11cf40b96..28f60c98ad8f279f8fd62bdd56e99e13798a0452 100644
--- a/libs/SDL2/WhatsNew.txt
+++ b/libs/SDL2/WhatsNew.txt
@@ -1,28 +1,9 @@
 
 This is a list of major changes in SDL's version history.
 
----------------------------------------------------------------------------
-2.30.0:
----------------------------------------------------------------------------
-
-General:
-* Added support for 2 bits-per-pixel indexed surface formats
-* Added the function SDL_GameControllerGetSteamHandle() to get the Steam API handle for a controller, if available
-* Added the event SDL_CONTROLLERSTEAMHANDLEUPDATED which is sent when the Steam API handle for a controller changes. This could also change the name, VID, and PID of the controller.
-* Added the environment variable SDL_LOGGING to control default log output
-
-macOS:
-* Added the hint SDL_HINT_JOYSTICK_IOKIT to control whether the IOKit controller driver should be used
-* Added the hint SDL_HINT_JOYSTICK_MFI to control whether the GCController controller driver should be used
-* Added the hint SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE to choose whether high or low power GPU should be used for rendering, in the case where there are multiple GPUs available
-
-Xbox:
-* Added the function SDL_GDKGetDefaultUser()
-
 ---------------------------------------------------------------------------
 2.28.2:
 ---------------------------------------------------------------------------
-
 General:
 * Added the hint SDL_HINT_JOYSTICK_WGI to control whether to use Windows.Gaming.Input for controllers
 
diff --git a/libs/SDL2/docs/README-android.md b/libs/SDL2/docs/README-android.md
index 6b4307839102ab6b47bdabaaf7bafdd8a9123845..f08493529c577e38b8906dcc019b8e4da3a8571c 100644
--- a/libs/SDL2/docs/README-android.md
+++ b/libs/SDL2/docs/README-android.md
@@ -72,7 +72,7 @@ done in the build directory for the app!
 For more complex projects, follow these instructions:
 
 1. Get the source code for SDL and copy the 'android-project' directory located at SDL/android-project to a suitable location. Also make sure to rename it to your project name (In these examples: YOURPROJECT).
-
+   
    (The 'android-project' directory can basically be seen as a sort of starting point for the android-port of your project. It contains the glue code between the Android Java 'frontend' and the SDL code 'backend'. It also contains some standard behaviour, like how events should be handled, which you will be able to change.)
 
 2. Move or [symlink](https://en.wikipedia.org/wiki/Symbolic_link) the SDL directory into the "YOURPROJECT/app/jni" directory
diff --git a/libs/SDL2/docs/README-dynapi.md b/libs/SDL2/docs/README-dynapi.md
index 6d447eab6906c5dc61842dee8331e0a6959b46d8..8eb6fb21e54d4b7ab829f28901f4c7e138c6c963 100644
--- a/libs/SDL2/docs/README-dynapi.md
+++ b/libs/SDL2/docs/README-dynapi.md
@@ -35,7 +35,7 @@ SDL now has, internally, a table of function pointers. So, this is what SDL_Init
 now looks like:
 
 ```c
-Uint32 SDL_Init(Uint32 flags)
+UInt32 SDL_Init(Uint32 flags)
 {
     return jump_table.SDL_Init(flags);
 }
@@ -100,7 +100,7 @@ a shared library of its own). If so, it loads that library and looks for and
 calls a single function:
 
 ```c
-Sint32 SDL_DYNAPI_entry(Uint32 version, void *table, Uint32 tablesize);
+SInt32 SDL_DYNAPI_entry(Uint32 version, void *table, Uint32 tablesize);
 ```
 
 That function takes a version number (more on that in a moment), the address of
diff --git a/libs/SDL2/docs/README-emscripten.md b/libs/SDL2/docs/README-emscripten.md
index cefad99c4ee80e78a7ff3230f89e7749b3f644d5..f952b08e43c3d0cc0173578daef6eef84856b1b0 100644
--- a/libs/SDL2/docs/README-emscripten.md
+++ b/libs/SDL2/docs/README-emscripten.md
@@ -1,187 +1,27 @@
 # Emscripten
 
-## The state of things
+(This documentation is not very robust; we will update and expand this later.)
 
-(As of September 2023, but things move quickly and we don't update this
-document often.)
-
-In modern times, all the browsers you probably care about (Chrome, Firefox,
-Edge, and Safari, on Windows, macOS, Linux, iOS and Android), support some
-reasonable base configurations:
-
-- WebAssembly (don't bother with asm.js any more)
-- WebGL (which will look like OpenGL ES 2 or 3 to your app).
-- Threads (see caveats, though!)
-- Game controllers
-- Autoupdating (so you can assume they have a recent version of the browser)
-
-All this to say we're at the point where you don't have to make a lot of
-concessions to get even a fairly complex SDL-based game up and running.
-
-
-## RTFM
-
-This document is a quick rundown of some high-level details. The
-documentation at [emscripten.org](https://emscripten.org/) is vast
-and extremely detailed for a wide variety of topics, and you should at
-least skim through it at some point.
-
-
-## Porting your app to Emscripten
-
-Many many things just need some simple adjustments and they'll compile
-like any other C/C++ code, as long as SDL was handling the platform-specific
-work for your program.
-
-First, you probably need this in at least one of your source files:
-
-```c
-#ifdef __EMSCRIPTEN__
-#include <emscripten.h>
-#endif
-```
-
-Second: assembly language code has to go. Replace it with C. You can even use
-[x86 SIMD intrinsic functions in Emscripten](https://emscripten.org/docs/porting/simd.html)!
-
-Third: Middleware has to go. If you have a third-party library you link
-against, you either need an Emscripten port of it, or the source code to it
-to compile yourself, or you need to remove it.
-
-Fourth: You still start in a function called main(), but you need to get out of
-it and into a function that gets called repeatedly, and returns quickly,
-called a mainloop.
-
-Somewhere in your program, you probably have something that looks like a more
-complicated version of this:
-
-```c
-void main(void)
-{
-    initialize_the_game();
-    while (game_is_still_running) {
-        check_for_new_input();
-        think_about_stuff();
-        draw_the_next_frame();
-    }
-    deinitialize_the_game();
-}
-```
-
-This will not work on Emscripten, because the main thread needs to be free
-to do stuff and can't sit in this loop forever. So Emscripten lets you set up
-a [mainloop](https://emscripten.org/docs/porting/emscripten-runtime-environment.html#browser-main-loop).
-
-```c
-static void mainloop(void)   /* this will run often, possibly at the monitor's refresh rate */
-{
-    if (!game_is_still_running) {
-        deinitialize_the_game();
-        #ifdef __EMSCRIPTEN__
-        emscripten_cancel_main_loop();  /* this should "kill" the app. */
-        #else
-        exit(0);
-        #endif
-    }
-
-    check_for_new_input();
-    think_about_stuff();
-    draw_the_next_frame();
-}
-
-void main(void)
-{
-    initialize_the_game();
-    #ifdef __EMSCRIPTEN__
-    emscripten_set_main_loop(mainloop, 0, 1);
-    #else
-    while (1) { mainloop(); }
-    #endif
-}
-```
-
-Basically, `emscripten_set_main_loop(mainloop, 0, 1);` says "run
-`mainloop` over and over until I end the program." The function will
-run, and return, freeing the main thread for other tasks, and then
-run again when it's time. The `1` parameter does some magic to make
-your main() function end immediately; this is useful because you
-don't want any shutdown code that might be sitting below this code
-to actually run if main() were to continue on, since we're just
-getting started.
-
-There's a lot of little details that are beyond the scope of this
-document, but that's the biggest intial set of hurdles to porting
-your app to the web.
-
-
-## Do you need threads?
-
-If you plan to use threads, they work on all major browsers now. HOWEVER,
-they bring with them a lot of careful considerations. Rendering _must_
-be done on the main thread. This is a general guideline for many
-platforms, but a hard requirement on the web.
-
-Many other things also must happen on the main thread; often times SDL
-and Emscripten make efforts to "proxy" work to the main thread that
-must be there, but you have to be careful (and read more detailed
-documentation than this for the finer points).
-
-Even when using threads, your main thread needs to set an Emscripten
-mainloop that runs quickly and returns, or things will fail to work
-correctly.
-
-You should definitely read [Emscripten's pthreads docs](https://emscripten.org/docs/porting/pthreads.html)
-for all the finer points. Mostly SDL's thread API will work as expected,
-but is built on pthreads, so it shares the same little incompatibilities
-that are documented there, such as where you can use a mutex, and when
-a thread will start running, etc.
-
-
-IMPORTANT: You have to decide to either build something that uses
-threads or something that doesn't; you can't have one build
-that works everywhere. This is an Emscripten (or maybe WebAssembly?
-Or just web browsers in general?) limitation. If you aren't using
-threads, it's easier to not enable them at all, at build time.
-
-If you use threads, you _have to_ run from a web server that has
-[COOP/COEP headers set correctly](https://web.dev/why-coop-coep/)
-or your program will fail to start at all.
-
-If building with threads, `__EMSCRIPTEN_PTHREADS__` will be defined
-for checking with the C preprocessor, so you can build something
-different depending on what sort of build you're compiling.
-
-
-## Audio
-
-Audio works as expected at the API level, but not exactly like other
-platforms.
-
-You'll only see a single default audio device. Audio capture also works;
-if the browser pops up a prompt to ask for permission to access the
-microphone, the SDL_OpenAudioDevice call will succeed and start producing
-silence at a regular interval. Once the user approves the request, real
-audio data will flow. If the user denies it, the app is not informed and
-will just continue to receive silence.
+## A quick note about audio
 
 Modern web browsers will not permit web pages to produce sound before the
-user has interacted with them (clicked or tapped on them, usually); this is
-for several reasons, not the least of which being that no one likes when a
-random browser tab suddenly starts making noise and the user has to scramble
-to figure out which and silence it.
-
-SDL will allow you to open the audio device for playback in this
-circumstance, and your audio callback will fire, but SDL will throw the audio
-data away until the user interacts with the page. This helps apps that depend
-on the audio callback to make progress, and also keeps audio playback in sync
-once the app is finally allowed to make noise.
-
-There are two reasonable ways to deal with the silence at the app level:
-if you are writing some sort of media player thing, where the user expects
-there to be a volume control when you mouseover the canvas, just default
-that control to a muted state; if the user clicks on the control to unmute
-it, on this first click, open the audio device. This allows the media to
-play at start, and the user can reasonably opt-in to listening.
+user has interacted with them; this is for several reasons, not the least
+of which being that no one likes when a random browser tab suddenly starts
+making noise and the user has to scramble to figure out which and silence
+it.
+
+To solve this, most browsers will refuse to let a web app use the audio
+subsystem at all before the user has interacted with (clicked on) the page
+in a meaningful way. SDL-based apps also have to deal with this problem; if
+the user hasn't interacted with the page, SDL_OpenAudioDevice will fail.
+
+There are two reasonable ways to deal with this: if you are writing some
+sort of media player thing, where the user expects there to be a volume
+control when you mouseover the canvas, just default that control to a muted
+state; if the user clicks on the control to unmute it, on this first click,
+open the audio device. This allows the media to play at start, the user can
+reasonably opt-in to listening, and you never get access denied to the audio
+device.
 
 Many games do not have this sort of UI, and are more rigid about starting
 audio along with everything else at the start of the process. For these, your
@@ -196,179 +36,41 @@ Please see the discussion at https://github.com/libsdl-org/SDL/issues/6385
 for some Javascript code to steal for this approach.
 
 
-## Rendering
-
-If you use SDL's 2D render API, it will use GLES2 internally, which
-Emscripten will turn into WebGL calls. You can also use OpenGL ES 2
-directly by creating a GL context and drawing into it.
-
-Calling SDL_RenderPresent (or SDL_GL_SwapWindow) will not actually
-present anything on the screen until your return from your mainloop
-function.
-
-
 ## Building SDL/emscripten
 
-First: do you _really_ need to build SDL from source?
-
-If you aren't developing SDL itself, have a desire to mess with its source
-code, or need something on the bleeding edge, don't build SDL. Just use
-Emscripten's packaged version!
-
-Compile and link your app with `-sUSE_SDL=2` and it'll use a build of
-SDL packaged with Emscripten. This comes from the same source code and
-fixes the Emscripten project makes to SDL are generally merged into SDL's
-revision control, so often this is much easier for app developers.
-
-`-sUSE_SDL=1` will select Emscripten's JavaScript reimplementation of SDL
-1.2 instead; if you need SDL 1.2, this might be fine, but we generally
-recommend you don't use SDL 1.2 in modern times.
-
-
-If you want to build SDL, though...
-
 SDL currently requires at least Emscripten 3.1.35 to build. Newer versions
 are likely to work, as well.
 
 
 Build:
 
-This works on Linux/Unix and macOS. Please send comments about Windows.
-
-Make sure you've [installed emsdk](https://emscripten.org/docs/getting_started/downloads.html)
-first, and run `source emsdk_env.sh` at the command line so it finds the
-tools.
-
-(These configure options might be overkill, but this has worked for me.)
-
-```bash
-cd SDL
-mkdir build
-cd build
-emconfigure ../configure --host=wasm32-unknown-emscripten --disable-pthreads --disable-assembly --disable-cpuinfo CFLAGS="-sUSE_SDL=0 -O3"
-emmake make -j4
-```
-
-If you want to build with thread support, something like this works:
-
-```bash
-emconfigure ../configure --host=wasm32-unknown-emscripten --enable-pthreads --disable-assembly --disable-cpuinfo CFLAGS="-sUSE_SDL=0 -O3 -pthread" LDFLAGS="-pthread"
-```
+    $ mkdir build
+    $ cd build
+    $ emconfigure ../configure --host=asmjs-unknown-emscripten --disable-assembly --disable-threads --disable-cpuinfo CFLAGS="-O2"
+    $ emmake make
 
 Or with cmake:
 
-```bash
-mkdir build
-cd build
-emcmake cmake ..
-emmake make -j4
-```
+    $ mkdir build
+    $ cd build
+    $ emcmake cmake ..
+    $ emmake make
 
 To build one of the tests:
 
-```bash
-cd test/
-emcc -O2 --js-opts 0 -g4 testdraw2.c -I../include ../build/.libs/libSDL2.a ../build/libSDL2_test.a -o a.html
-```
-
-## Building your app
-
-You need to compile with `emcc` instead of `gcc` or `clang` or whatever, but
-mostly it uses the same command line arguments as Clang.
-
-Link against the SDL/build/.libs/libSDL2.a file you generated by building SDL,
-link with `-sUSE_SDL=2` to use Emscripten's prepackaged SDL2 build.
-
-Usually you would produce a binary like this:
-
-```bash
-gcc -o mygame mygame.c  # or whatever
-```
-
-But for Emscripten, you want to output something else:
-
-```bash
-emcc -o index.html mygame.c
-```
-
-This will produce several files...support Javascript and WebAssembly (.wasm)
-files. The `-o index.html` will produce a simple HTML page that loads and
-runs your app. You will (probably) eventually want to replace or customize
-that file and do `-o index.js` instead to just build the code pieces.
-
-If you're working on a program of any serious size, you'll likely need to
-link with `-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1gb` to get access
-to more memory. If using pthreads, you'll need the `-sMAXIMUM_MEMORY=1gb`
-or the app will fail to start on iOS browsers, but this might be a bug that
-goes away in the future.
-
-
-## Data files
-
-Your game probably has data files. Here's how to access them.
-
-Filesystem access works like a Unix filesystem; you have a single directory
-tree, possibly interpolated from several mounted locations, no drive letters,
-'/' for a path separator. You can access them with standard file APIs like
-open() or fopen() or SDL_RWops. You can read or write from the filesystem.
-
-By default, you probably have a "MEMFS" filesystem (all files are stored in
-memory, but access to them is immediate and doesn't need to block). There are
-other options, like "IDBFS" (files are stored in a local database, so they
-don't need to be in RAM all the time and they can persist between runs of the
-program, but access is not synchronous). You can mix and match these file
-systems, mounting a MEMFS filesystem at one place and idbfs elsewhere, etc,
-but that's beyond the scope of this document. Please refer to Emscripten's
-[page on the topic](https://emscripten.org/docs/porting/files/file_systems_overview.html)
-for more info.
-
-The _easiest_ (but not the best) way to get at your data files is to embed
-them in the app itself. Emscripten's linker has support for automating this.
-
-```bash
-emcc -o index.html loopwave.c --embed-file=../test/sample.wav@/sounds/sample.wav
-```
-
-This will pack ../test/sample.wav in your app, and make it available at
-"/sounds/sample.wav" at runtime. Emscripten makes sure this data is available
-before your main() function runs, and since it's in MEMFS, you can just
-read it like you do on other platforms. `--embed-file` can also accept a
-directory to pack an entire tree, and you can specify the argument multiple
-times to pack unrelated things into the final installation.
-
-Note that this is absolutely the best approach if you have a few small
-files to include and shouldn't worry about the issue further. However, if you
-have hundreds of megabytes and/or thousands of files, this is not so great,
-since the user will download it all every time they load your page, and it
-all has to live in memory at runtime.
-
-[Emscripten's documentation on the matter](https://emscripten.org/docs/porting/files/packaging_files.html)
-gives other options and details, and is worth a read.
-
-
-## Debugging
-
-Debugging web apps is a mixed bag. You should compile and link with
-`-gsource-map`, which embeds a ton of source-level debugging information into
-the build, and make sure _the app source code is available on the web server_,
-which is often a scary proposition for various reasons.
-
-When you debug from the browser's tools and hit a breakpoint, you can step
-through the actual C/C++ source code, though, which can be nice.
-
-If you try debugging in Firefox and it doesn't work well for no apparent
-reason, try Chrome, and vice-versa. These tools are still relatively new,
-and improving all the time.
-
-SDL_Log() (or even plain old printf) will write to the Javascript console,
-and honestly I find printf-style debugging to be easier than setting up a build
-for proper debugging, so use whatever tools work best for you.
+    $ cd test/
+    $ emcc -O2 --js-opts 0 -g4 testdraw2.c -I../include ../build/.libs/libSDL2.a ../build/libSDL2_test.a -o a.html
 
+Uses GLES2 renderer or software
 
-## Questions?
+Some other SDL2 libraries can be easily built (assuming SDL2 is installed somewhere):
 
-Please give us feedback on this document at [the SDL bug tracker](https://github.com/libsdl-org/SDL/issues).
-If something is wrong or unclear, we want to know!
+SDL_mixer (http://www.libsdl.org/projects/SDL_mixer/):
 
+    $ EMCONFIGURE_JS=1 emconfigure ../configure
+    build as usual...
 
+SDL_gfx (http://cms.ferzkopp.net/index.php/software/13-sdl-gfx):
 
+    $ EMCONFIGURE_JS=1 emconfigure ../configure --disable-mmx
+    build as usual...
diff --git a/libs/SDL2/docs/README-gdk.md b/libs/SDL2/docs/README-gdk.md
index 7997c065ba4cdfc95d8274a76e8ad9548c2632df..903265f32f720276f19758ae62341dd836ecf01a 100644
--- a/libs/SDL2/docs/README-gdk.md
+++ b/libs/SDL2/docs/README-gdk.md
@@ -3,7 +3,7 @@ GDK
 
 This port allows SDL applications to run via Microsoft's Game Development Kit (GDK).
 
-Windows (GDK) and  Xbox One/Xbox Series (GDKX) are both supported and all the required code is included in this public SDL release. However, only licensed Xbox developers have access to the GDKX libraries which will allow you to build the Xbox targets.
+Windows (GDK) and  Xbox One/Xbox Series (GDKX) are supported. Although most of the Xbox code is included in the public SDL source code, NDA access is required for a small number of source files. If you have access to GDKX, these required Xbox files are posted on the GDK forums [here](https://forums.xboxlive.com/questions/130003/).
 
 
 Requirements
@@ -11,7 +11,6 @@ Requirements
 
 * Microsoft Visual Studio 2022 (in theory, it should also work in 2017 or 2019, but this has not been tested)
 * Microsoft GDK June 2022 or newer (public release [here](https://github.com/microsoft/GDK/releases/tag/June_2022))
-* For Xbox, you will need the corresponding GDKX version (licensed developers only)
 * To publish a package or successfully authenticate a user, you will need to create an app id/configure services in Partner Center. However, for local testing purposes (without authenticating on Xbox Live), the identifiers used by the GDK test programs in the included solution will work.
 
 
@@ -30,12 +29,6 @@ The Windows GDK port supports the full set of Win32 APIs, renderers, controllers
   * Global task queue callbacks are dispatched during `SDL_PumpEvents` (which is also called internally if using `SDL_PollEvent`).
   * You can get the handle of the global task queue through `SDL_GDKGetTaskQueue`, if needed. When done with the queue, be sure to use `XTaskQueueCloseHandle` to decrement the reference count (otherwise it will cause a resource leak).
 
-* Single-player games have some additional features available:
-  * Call `SDL_GDKGetDefaultUser` to get the default XUserHandle pointer.
-  * `SDL_GetPrefPath` still works, but only for single-player titles.
-
-  These functions mostly wrap around async APIs, and thus should be treated as synchronous alternatives. Also note that the single-player functions return on any OS errors, so be sure to validate the return values!
-
 * What doesn't work:
   * Compilation with anything other than through the included Visual C++ solution file
 
@@ -146,20 +139,6 @@ To create the package:
 6. Once the package is installed, you can run it from the start menu.
 7. As with when running from Visual Studio, if you need to test any Xbox Live functionality you must switch to the correct sandbox.
 
-Xbox GDKX Setup
----------------------
-In general, the same process in the Windows GDK instructions work. There are just a few additional notes:
-* For Xbox One consoles, use the Gaming.Xbox.XboxOne.x64 target
-* For Xbox Series consoles, use the Gaming.Xbox.Scarlett.x64 target
-* The Xbox One target sets the `__XBOXONE__` define and the Xbox Series target sets the `__XBOXSERIES__` define
-* You don't need to link against the Xbox.Services Thunks lib nor include that dll in your package (it doesn't exist for Xbox)
-* The shader blobs for Xbox are created in a pre-build step for the Xbox targets, rather than included in the source (due to NDA and version compatability reasons)
-* To create a package, use:
-  `makepkg pack /f PackageLayout.xml /lt /d . /pd Package`
-* To install the package, use:
-  `xbapp install [PACKAGE].xvc`
-* For some reason, if you make changes that require SDL2.dll to build, and you are running through the debugger (instead of a package), you have to rebuild your .exe target for the debugger to recognize the dll has changed and needs to be transferred to the console again
-* While there are successful releases of Xbox titles using this port, it is not as extensively tested as other targets
 
 Troubleshooting
 ---------------
diff --git a/libs/SDL2/docs/README-ios.md b/libs/SDL2/docs/README-ios.md
index 8fb90de46e207dfa8eff542da9d6c0fd79fbdeda..f5a3a83bfc881ff3485a6b0affef7cc74277159c 100644
--- a/libs/SDL2/docs/README-ios.md
+++ b/libs/SDL2/docs/README-ios.md
@@ -273,7 +273,7 @@ e.g.
     {
         ... initialize game ...
 
-    #ifdef __IPHONEOS__
+    #if __IPHONEOS__
         // Initialize the Game Center for scoring and matchmaking
         InitGameCenter();
 
diff --git a/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll b/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll
index 3265fb2f3de9e06460e7c6a73a83236b494b89fd..573225caba5abb279c844c438de4d6de2f6a10f1 100755
Binary files a/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll and b/libs/SDL2/i686-w64-mingw32/bin/SDL2.dll differ
diff --git a/libs/SDL2/i686-w64-mingw32/bin/sdl2-config b/libs/SDL2/i686-w64-mingw32/bin/sdl2-config
index fc399f745b16661bc38552d9e2d9c0d20ffc6cad..aa99b065a5ac2c3562b73473774a39e46236a58b 100755
--- a/libs/SDL2/i686-w64-mingw32/bin/sdl2-config
+++ b/libs/SDL2/i686-w64-mingw32/bin/sdl2-config
@@ -43,7 +43,7 @@ while test $# -gt 0; do
       echo $exec_prefix
       ;;
     --version)
-      echo 2.30.0
+      echo 2.28.5
       ;;
     --cflags)
       echo -I${prefix}/include/SDL2  -Dmain=SDL_main
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h
index 20c903b2fe4f60836b397cb19af7e07ca19f3071..9ba8f68c6e7966906d5832985a0f4ebc400a8878 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h
index a396d4e02ed20041a742e22ffb4efaa68995db03..7ce823ec5433f2d168889d7ac9239cd9f6ac6171 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h
index 1fa18f49fe078348ec235adca77cbb6374a62e25..1dd816a3826e307f8b7cb436ce95edd28cee7a5c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -209,7 +209,7 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
-#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
+#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__)
 #ifdef __thumb__
 /* The mcr instruction isn't available in thumb mode, use real functions */
 #define SDL_MEMORY_BARRIER_USES_FUNCTION
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h
index bd8e7ab6fa6d8336bf78fe732726782105f65dfe..ccd35982df124d75a8007791bce88da405c76a75 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h
index 83e8a78c783c473184dd1674279fbdb4caafab8e..81161ae5f30633f2d708e9b7806ba005bdd9c21a 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h
index 09d01477d8db63ecf6e9de2483472b9d17641567..4ecbe50785e9d37fcd57325a5301df6d25237997 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -65,8 +65,8 @@ typedef enum
 typedef enum
 {
     SDL_BLENDOPERATION_ADD              = 0x1,  /**< dst + src: supported by all renderers */
-    SDL_BLENDOPERATION_SUBTRACT         = 0x2,  /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
-    SDL_BLENDOPERATION_REV_SUBTRACT     = 0x3,  /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
+    SDL_BLENDOPERATION_SUBTRACT         = 0x2,  /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
+    SDL_BLENDOPERATION_REV_SUBTRACT     = 0x3,  /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
     SDL_BLENDOPERATION_MINIMUM          = 0x4,  /**< min(dst, src) : supported by D3D9, D3D11 */
     SDL_BLENDOPERATION_MAXIMUM          = 0x5   /**< max(dst, src) : supported by D3D9, D3D11 */
 } SDL_BlendOperation;
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h
index bd4b044c6dd4ec0f0ed298f4333d3aed79702001..7c351fbb9c98aacbbf9136b3373b04ad321fe456 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h
index dba78086016e4d11489ccdb27cda9972ec0d862d..01322c1829401fecea1b72889dfe4d313c5f0175 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h
index 2a9dd380c2e7b8d4ba5f6e8aec4c13d5becd565d..ed5e97915e314132f76df1747f76a5633dbd2b44 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h
index a4276e6810b2fe059720cb2fe81e234e599e663c..6f51c0831afb94f82f03f92fdec39c622b0b3858 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h
index 591ccac4256adc9f17c7ba0234ff745e1fb71a31..71bc06729b6425ad9a4a96ca12e430409fb50514 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h
index 2df6463ad92f2183c0ac3c936bf1277bdef02e22..31c22616ccb0f276d3cab3caef4a769c5381b0ae 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h
index eccbba2553b4fce528c41741b15d7419597afcf6..9d097031805f33ff18e0a9bf381e22fb0f662dd0 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -131,8 +131,6 @@ typedef enum
     SDL_CONTROLLERTOUCHPADMOTION,      /**< Game controller touchpad finger was moved */
     SDL_CONTROLLERTOUCHPADUP,          /**< Game controller touchpad finger was lifted */
     SDL_CONTROLLERSENSORUPDATE,        /**< Game controller sensor was updated */
-    SDL_CONTROLLERUPDATECOMPLETE_RESERVED_FOR_SDL3,
-    SDL_CONTROLLERSTEAMHANDLEUPDATED,  /**< Game controller Steam handle has changed */
 
     /* Touch events */
     SDL_FINGERDOWN      = 0x700,
@@ -448,7 +446,7 @@ typedef struct SDL_ControllerButtonEvent
  */
 typedef struct SDL_ControllerDeviceEvent
 {
-    Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, ::SDL_CONTROLLERDEVICEREMAPPED, or ::SDL_CONTROLLERSTEAMHANDLEUPDATED */
+    Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, or ::SDL_CONTROLLERDEVICEREMAPPED */
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
     Sint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */
 } SDL_ControllerDeviceEvent;
@@ -582,6 +580,15 @@ typedef struct SDL_QuitEvent
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
 } SDL_QuitEvent;
 
+/**
+ *  \brief OS Specific event
+ */
+typedef struct SDL_OSEvent
+{
+    Uint32 type;        /**< ::SDL_QUIT */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+} SDL_OSEvent;
+
 /**
  *  \brief A user-defined event type (event.user.*)
  */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h
index 07498898d3238d6b7c824761c46421e46991c84d..4cad657ec86e7b245a4a3046effd2ed783085932 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -64,7 +64,7 @@ extern "C" {
  * directory of the application as it is uncommon to store resources outside
  * the executable. As such it is not a writable directory.
  *
- * The returned path is guaranteed to end with a path separator ('\\' on
+ * The returned path is guaranteed to end with a path separator ('\' on
  * Windows, '/' on most other platforms).
  *
  * The pointer returned is owned by the caller. Please call SDL_free() on the
@@ -120,7 +120,7 @@ extern DECLSPEC char *SDLCALL SDL_GetBasePath(void);
  * - ...only use letters, numbers, and spaces. Avoid punctuation like "Game
  *   Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
  *
- * The returned path is guaranteed to end with a path separator ('\\' on
+ * The returned path is guaranteed to end with a path separator ('\' on
  * Windows, '/' on most other platforms).
  *
  * The pointer returned is owned by the caller. Please call SDL_free() on the
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h
index 281fa356c63f58cfa5701ff6ae80f1d83c0f6aa8..140054d36ee625c57be7cc976087691b8746f7f4 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -73,8 +73,7 @@ typedef enum
     SDL_CONTROLLER_TYPE_NVIDIA_SHIELD,
     SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
     SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
-    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR,
-    SDL_CONTROLLER_TYPE_MAX
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
 } SDL_GameControllerType;
 
 typedef enum
@@ -524,20 +523,6 @@ extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetFirmwareVersion(SDL_GameCont
  */
 extern DECLSPEC const char * SDLCALL SDL_GameControllerGetSerial(SDL_GameController *gamecontroller);
 
-/**
- * Get the Steam Input handle of an opened controller, if available.
- *
- * Returns an InputHandle_t for the controller that can be used with Steam Input API:
- * https://partner.steamgames.com/doc/api/ISteamInput
- *
- * \param gamecontroller the game controller object to query.
- * \returns the gamepad handle, or 0 if unavailable.
- *
- * \since This function is available since SDL 2.30.0.
- */
-extern DECLSPEC Uint64 SDLCALL SDL_GameControllerGetSteamHandle(SDL_GameController *gamecontroller);
-
-
 /**
  * Check if a controller has been opened and is currently connected.
  *
@@ -613,9 +598,7 @@ extern DECLSPEC void SDLCALL SDL_GameControllerUpdate(void);
  *  and are centered within ~8000 of zero, though advanced UI will allow users to set
  *  or autodetect the dead zone, which varies between controllers.
  *
- *  Trigger axis values range from 0 (released) to SDL_JOYSTICK_AXIS_MAX
- *  (fully pressed) when reported by SDL_GameControllerGetAxis(). Note that this is not the
- *  same range that will be reported by the lower-level SDL_GetJoystickAxis().
+ *  Trigger axis values range from 0 to SDL_JOYSTICK_AXIS_MAX.
  */
 typedef enum
 {
@@ -704,13 +687,8 @@ SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameController
  *
  * The axis indices start at index 0.
  *
- * For thumbsticks, the state is a value ranging from -32768 (up/left)
- * to 32767 (down/right).
- *
- * Triggers range from 0 when released to 32767 when fully pressed, and
- * never return a negative value. Note that this differs from the value
- * reported by the lower-level SDL_GetJoystickAxis(), which normally uses
- * the full range.
+ * The state is a value ranging from -32768 to 32767. Triggers, however, range
+ * from 0 to 32767 (they never return a negative value).
  *
  * \param gamecontroller a game controller
  * \param axis an axis index (one of the SDL_GameControllerAxis values)
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h
index 4fffa5f3e87df75d287da5c6ed0e795ab49d7768..db70b4dd843d983dea8988a60b12f92a739faa0a 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_guid.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_guid.h
index 7daa5f1f585c3d7482108e915ea0ea8fa263751b..d964223c62ca79b46bdb6aa69ba9ed4e256d1f9b 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_guid.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_guid.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h
index c9ed847df02387a5f4d5f5fd02055695cd46a5e6..2462a1e47b3731a20f68af4a2d0d9cdfa5c76e59 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hidapi.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hidapi.h
index b9d8ffac3881e2a297da348e8afb832b0b4afea9..0575100357798a4b34365b5f37d0ef57d1cf831c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hidapi.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hidapi.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h
index e775a6509bc0e4834be32411ddadd1cfd0f2a99b..00beef51e29ed9e610182c7db3d88da70a98230f 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -631,110 +631,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
 
-/**
- *  A variable containing a list of arcade stick style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES "SDL_JOYSTICK_ARCADESTICK_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not arcade stick style controllers. This will override SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED "SDL_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices that should not be considerd joysticks.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_BLACKLIST_DEVICES "SDL_JOYSTICK_BLACKLIST_DEVICES"
-
-/**
- *  A variable containing a list of devices that should be considered joysticks. This will override SDL_HINT_JOYSTICK_BLACKLIST_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED "SDL_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of flightstick style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES "SDL_JOYSTICK_FLIGHTSTICK_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not flightstick style controllers. This will override SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED "SDL_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices known to have a GameCube form factor.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES "SDL_JOYSTICK_GAMECUBE_DEVICES"
-
-/**
- *  A variable containing a list of devices known not to have a GameCube form factor. This will override SDL_HINT_JOYSTICK_GAMECUBE_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED "SDL_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED"
-
 /**
  *  \brief  A variable controlling whether the HIDAPI joystick drivers should be used.
  *
@@ -943,17 +839,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
 
-/**
- *  \brief  A variable controlling whether the HIDAPI driver for the Steam Deck builtin controller should be used.
- *
- *  This variable can be set to the following values:
- *    "0"       - HIDAPI driver is not used
- *    "1"       - HIDAPI driver is used
- *
- *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
- */
-#define SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK "SDL_JOYSTICK_HIDAPI_STEAMDECK"
-
 /**
  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
  *
@@ -1080,24 +965,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED"
 
-/**
-  *  A variable controlling whether IOKit should be used for controller handling.
-  *
-  *  This variable can be set to the following values:
-  *    "0"       - IOKit is not used
-  *    "1"       - IOKit is used (the default)
-  */
-#define SDL_HINT_JOYSTICK_IOKIT "SDL_JOYSTICK_IOKIT"
-
-/**
-  *  A variable controlling whether GCController should be used for controller handling.
-  *
-  *  This variable can be set to the following values:
-  *    "0"       - GCController is not used
-  *    "1"       - GCController is used (the default)
-  */
-#define SDL_HINT_JOYSTICK_MFI "SDL_JOYSTICK_MFI"
-
 /**
   *  \brief  A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
   *
@@ -1140,32 +1007,6 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_THREAD "SDL_JOYSTICK_THREAD"
 
-/**
- *  A variable containing a list of throttle style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_THROTTLE_DEVICES "SDL_JOYSTICK_THROTTLE_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not throttle style controllers. This will override SDL_HINT_JOYSTICK_THROTTLE_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_THROTTLE_DEVICES_EXCLUDED "SDL_JOYSTICK_THROTTLE_DEVICES_EXCLUDED"
-
 /**
   *  \brief  A variable controlling whether Windows.Gaming.Input should be used for controller handling.
   *
@@ -1175,45 +1016,6 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_WGI "SDL_JOYSTICK_WGI"
 
-/**
- *  A variable containing a list of wheel style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_WHEEL_DEVICES "SDL_JOYSTICK_WHEEL_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not wheel style controllers. This will override SDL_HINT_JOYSTICK_WHEEL_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_WHEEL_DEVICES_EXCLUDED "SDL_JOYSTICK_WHEEL_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices known to have all axes centered at zero.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES"
-
 /**
  * \brief Determines whether SDL enforces that DRM master is required in order
  *        to initialize the KMSDRM video backend.
@@ -1282,22 +1084,6 @@ extern "C" {
   */
 #define SDL_HINT_LINUX_JOYSTICK_DEADZONES "SDL_LINUX_JOYSTICK_DEADZONES"
 
-/**
- *  \brief A variable controlling the default SDL log levels.
- *
- *  This variable is a comma separated set of category=level tokens that define the default logging levels for SDL applications.
- *
- *  The category can be a numeric category, one of "app", "error", "assert", "system", "audio", "video", "render", "input", "test", or `*` for any unspecified category.
- *
- *  The level can be a numeric level, one of "verbose", "debug", "info", "warn", "error", "critical", or "quiet" to disable that category.
- *
- *  You can omit the category if you want to set the logging level for all categories.
- *
- *  If this hint isn't set, the default log levels are equivalent to:
- *  "app=info,assert=warn,test=verbose,*=error"
- */
-#define SDL_HINT_LOGGING   "SDL_LOGGING"
-
 /**
 *  \brief  When set don't force the SDL app to become a foreground process
 *
@@ -1699,32 +1485,6 @@ extern "C" {
  */
 #define SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE "SDL_RENDER_METAL_PREFER_LOW_POWER_DEVICE"
 
-/**
- *  A variable containing a list of ROG gamepad capable mice.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_ROG_GAMEPAD_MICE "SDL_ROG_GAMEPAD_MICE"
-
-/**
- *  A variable containing a list of devices that are not ROG gamepad capable mice. This will override SDL_HINT_ROG_GAMEPAD_MICE and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED "SDL_ROG_GAMEPAD_MICE_EXCLUDED"
-
 /**
  *  \brief  A variable controlling if VSYNC is automatically disable if doesn't reach the enough FPS
  *
@@ -2682,22 +2442,6 @@ extern "C" {
  */
 #define SDL_HINT_TRACKPAD_IS_TOUCH_ONLY "SDL_TRACKPAD_IS_TOUCH_ONLY"
 
-/**
- * Cause SDL to call dbus_shutdown() on quit.
- *
- * This is useful as a debug tool to validate memory leaks, but shouldn't ever
- * be set in production applications, as other libraries used by the application
- * might use dbus under the hood and this cause cause crashes if they continue
- * after SDL_Quit().
- *
- * This variable can be set to the following values:
- *   "0"       - SDL will not call dbus_shutdown() on quit (default)
- *   "1"       - SDL will call dbus_shutdown() on quit
- *
- * This hint is available since SDL 2.30.0.
- */
-#define SDL_HINT_SHUTDOWN_DBUS_ON_QUIT "SDL_SHUTDOWN_DBUS_ON_QUIT"
-
 
 /**
  *  \brief  An enumeration of hint priorities
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h
index 561e01099cede911e349969024f9b84bad658c2d..b9b4f622800d7a59285523c1407578ee130c0e32 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h
index 03c7b5a3705af4eb25d296049af1fe23ffd0b7d3..86a37ad1a241688e3ee3e658a824e5a78cba2918 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -298,10 +298,8 @@ extern DECLSPEC void SDLCALL SDL_ClearComposition(void);
 extern DECLSPEC SDL_bool SDLCALL SDL_IsTextInputShown(void);
 
 /**
- * Set the rectangle used to type Unicode text inputs. Native input methods
- * will place a window with word suggestions near it, without covering the
- * text being inputted.
- * 
+ * Set the rectangle used to type Unicode text inputs.
+ *
  * To start text input in a given location, this function is intended to be
  * called before SDL_StartTextInput, although some platforms support moving
  * the rectangle even while text input (and a composition) is active.
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h
index 57a71bd79694d749d3702af58f3813540fb678d8..7106223027e75886652f3a2efd179d82561e350c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h
index 4edc22e9e756c9f69fde1aced4679b63dc228e37..ca59b681cb45d9684223aaa6ab7287e809ced5f2 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_locale.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_locale.h
index 0b6118f0ef8669930b2ce0aa5d4e9628381ae2df..482dbefe765fce9fe2e4248cc5e57e56e71b39b1 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_locale.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_locale.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h
index bd030c6d2d5f27ece4b3a74bd80d8f9b5708d05b..da733c4023d9c9f8ed62668e22ddb00c9f5c1fd4 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ extern "C" {
  *  By default the application category is enabled at the INFO level,
  *  the assert category is enabled at the WARN level, test is enabled
  *  at the VERBOSE level and all other categories are enabled at the
- *  ERROR level.
+ *  CRITICAL level.
  */
 typedef enum
 {
@@ -352,7 +352,7 @@ extern DECLSPEC void SDLCALL SDL_LogMessage(int category,
  */
 extern DECLSPEC void SDLCALL SDL_LogMessageV(int category,
                                              SDL_LogPriority priority,
-                                             SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(3);
+                                             const char *fmt, va_list ap);
 
 /**
  * The prototype for the log output callback function.
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h
index a66c84b4e5fbc2b45a5deca02e42b08e00ef1c66..5cc8e5913a4e705548739f0718d4878392c8a90e 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h
index 5ace6f2ddee1f8172416650c6fbdcd77e0a11ba9..7896fd1291f9211584447abcb4ab3edf320bc389 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_metal.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_metal.h
index 50f7b2aeb45211ce457bf9c6dc268eb86caa6be6..f36e34878cef20b686f7800fe112a5bd99f6a3b3 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_metal.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_metal.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_misc.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_misc.h
index 113ba7a15693dea7e8fd65d4000fd0fb5ca75c18..13ed9c771835f15abdd16c53b5cf39d999159c65 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_misc.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_misc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h
index 687ff122d2c4fc2ba8616dc9fe30fb9764690100..aa07575738a5640c65e5f5dbc4a55661fe0a093e 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h
index eaa21f293f51721c44eb07d1623fb291f3fb7ada..e679d380890ea02d7a05021152aa183646fa178c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h
index 71e9354550f913f1b76dccb0386a19d51dcd164a..5c3e07ab7d3e4a04fa436767527aa3e570a25d25 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h
index 2bb38c5c0e994443e99ce7b2ac3888d4beed435a..0ba89127ace681fa97744e94bad4728c59be9b53 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h
index 7e9a1ab8d4d037d06954b6ddd0df8684fb1a3db4..f4465eaa9da8ba3009fa4f3ee51eeecd0689283b 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h
index 96971344d1b863777ef6a567d321167ebeff4765..5e3b717def6cafa080adb200245e9528f0bf7cbc 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h
index 44757cdcf4b7fdae9c499d8c773c2c5fe28e60d7..9abd57b42014a89b2761608bea2ae802ef9e8515 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -61,10 +61,7 @@ typedef enum
     SDL_PIXELTYPE_ARRAYU16,
     SDL_PIXELTYPE_ARRAYU32,
     SDL_PIXELTYPE_ARRAYF16,
-    SDL_PIXELTYPE_ARRAYF32,
-
-    /* This must be at the end of the list to avoid breaking the existing ABI */
-    SDL_PIXELTYPE_INDEX2
+    SDL_PIXELTYPE_ARRAYF32
 } SDL_PixelType;
 
 /** Bitmap pixel order, high bit -> low bit. */
@@ -137,7 +134,6 @@ typedef enum
 #define SDL_ISPIXELFORMAT_INDEXED(format)   \
     (!SDL_ISPIXELFORMAT_FOURCC(format) && \
      ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX1) || \
-      (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX2) || \
       (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX4) || \
       (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX8)))
 
@@ -181,12 +177,6 @@ typedef enum
     SDL_PIXELFORMAT_INDEX1MSB =
         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_1234, 0,
                                1, 0),
-    SDL_PIXELFORMAT_INDEX2LSB =
-        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX2, SDL_BITMAPORDER_4321, 0,
-                               2, 0),
-    SDL_PIXELFORMAT_INDEX2MSB =
-        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX2, SDL_BITMAPORDER_1234, 0,
-                               2, 0),
     SDL_PIXELFORMAT_INDEX4LSB =
         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_4321, 0,
                                4, 0),
@@ -286,19 +276,11 @@ typedef enum
     SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_ARGB8888,
     SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_BGRA8888,
     SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_ABGR8888,
-    SDL_PIXELFORMAT_RGBX32 = SDL_PIXELFORMAT_RGBX8888,
-    SDL_PIXELFORMAT_XRGB32 = SDL_PIXELFORMAT_XRGB8888,
-    SDL_PIXELFORMAT_BGRX32 = SDL_PIXELFORMAT_BGRX8888,
-    SDL_PIXELFORMAT_XBGR32 = SDL_PIXELFORMAT_XBGR8888,
 #else
     SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_ABGR8888,
     SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_BGRA8888,
     SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_ARGB8888,
     SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_RGBA8888,
-    SDL_PIXELFORMAT_RGBX32 = SDL_PIXELFORMAT_XBGR8888,
-    SDL_PIXELFORMAT_XRGB32 = SDL_PIXELFORMAT_BGRX8888,
-    SDL_PIXELFORMAT_BGRX32 = SDL_PIXELFORMAT_XRGB8888,
-    SDL_PIXELFORMAT_XBGR32 = SDL_PIXELFORMAT_RGBX8888,
 #endif
 
     SDL_PIXELFORMAT_YV12 =      /**< Planar mode: Y + V + U  (3 planes) */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h
index 6e67b4577a3d040835a83fdc5e6332a33cc0bab5..d2a7e052d7b19051d020bb240856fbe6080e1af8 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -166,12 +166,6 @@
 #define WINAPI_FAMILY_WINRT 0
 #endif /* HAVE_WINAPIFAMILY_H */
 
-#if (HAVE_WINAPIFAMILY_H) && defined(WINAPI_FAMILY_PHONE_APP)
-#define SDL_WINAPI_FAMILY_PHONE (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
-#else
-#define SDL_WINAPI_FAMILY_PHONE 0
-#endif
-
 #if WINAPI_FAMILY_WINRT
 #undef __WINRT__
 #define __WINRT__ 1
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h
index 0520065cebbb135035665cf95402a2b15b381d1a..1d75704c421c42b244f68b93edda5694f73d5c31 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h
index 3f69dc9f26011db121417874daa9ccbb1043f708..d8ceb894369194b5a0da17b8b4117ebf2edf0a88 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h
index 5ce1f0b4517fa856ad7ee07e8c14fdf2f33f7c7a..9611a311ce83bc165a1ea968a51d4f968f9557d3 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h
index b7135bb9dd46e73b4de07762cda78cc6b292bf3e..2d3f07366209ba01531b878102b28599b256725f 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -42,7 +42,7 @@
  *  of the many good 3D engines.
  *
  *  These functions must be called from the main thread.
- *  See this bug for details: https://github.com/libsdl-org/SDL/issues/986
+ *  See this bug for details: http://bugzilla.libsdl.org/show_bug.cgi?id=1995
  */
 
 #ifndef SDL_render_h_
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h
index ee42f8421d75d3d1e8a00051725414503c7ff132..4455a08b6289e407412cfb0c59b8d8022ea49d98 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_revision.h
@@ -1,7 +1,7 @@
 /* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.30.0-0-g859844eae (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40 (" SDL_VENDOR_INFO ")"
 #else
-#define SDL_REVISION "SDL-release-2.30.0-0-g859844eae"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40"
 #endif
 #define SDL_REVISION_NUMBER 0
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h
index 9dd99f92b1541ba73386aeed906b16d4db415d17..8615cb542959def634d4a634cd24f24d3a5104a6 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h
index fe13d5b7aaad9378e49005640b0c7641cf0512dc..a960a7991c61accff7874c9c75d92099b350b858 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h
index 8b89ef6a526d45f11d7b3ac64234519df2164b22..9ecce44b17be8469a1572afe95b2ff8a323045bf 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_sensor.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h
index 4783cf290e95eec1a2e5b3f3a2ee5b7f94dcbf33..f66babc011339d5729fee081235f8f57815275c2 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h
index 0035a357cf8e70d0e201413e726b149db96acfd3..182ed86ee371194ec6f45229626fa395472d0f8d 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -257,7 +257,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIs64 PRIs64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIs64 "I64d"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIs64 "ld"
 #else
 #define SDL_PRIs64 "lld"
@@ -268,7 +268,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIu64 PRIu64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIu64 "I64u"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIu64 "lu"
 #else
 #define SDL_PRIu64 "llu"
@@ -279,7 +279,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIx64 PRIx64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIx64 "I64x"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIx64 "lx"
 #else
 #define SDL_PRIx64 "llx"
@@ -290,7 +290,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIX64 PRIX64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIX64 "I64X"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIX64 "lX"
 #else
 #define SDL_PRIX64 "llX"
@@ -336,9 +336,7 @@ typedef uint64_t Uint64;
 #define SDL_PRINTF_FORMAT_STRING
 #define SDL_SCANF_FORMAT_STRING
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber )
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber )
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber )
 #else
 #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */
 #include <sal.h>
@@ -364,14 +362,10 @@ typedef uint64_t Uint64;
 #endif
 #if defined(__GNUC__)
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __printf__, fmtargnumber, fmtargnumber+1 )))
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber ) __attribute__(( format( __printf__, fmtargnumber, 0 )))
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __scanf__, fmtargnumber, fmtargnumber+1 )))
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber ) __attribute__(( format( __scanf__, fmtargnumber, 0 )))
 #else
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber )
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber )
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber )
 #endif
 #endif /* SDL_DISABLE_ANALYZE_MACROS */
 
@@ -609,11 +603,11 @@ extern DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str2);
 extern DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t len);
 
 extern DECLSPEC int SDLCALL SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...) SDL_SCANF_VARARG_FUNC(2);
-extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, va_list ap) SDL_SCANF_VARARG_FUNCV(2);
+extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, const char *fmt, va_list ap);
 extern DECLSPEC int SDLCALL SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ... ) SDL_PRINTF_VARARG_FUNC(3);
-extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(3);
+extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap);
 extern DECLSPEC int SDLCALL SDL_asprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
-extern DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(2);
+extern DECLSPEC int SDLCALL SDL_vasprintf(char **strp, const char *fmt, va_list ap);
 
 #ifndef HAVE_M_PI
 #ifndef M_PI
@@ -694,8 +688,8 @@ extern DECLSPEC size_t SDLCALL SDL_iconv(SDL_iconv_t cd, const char **inbuf,
                                          size_t * outbytesleft);
 
 /**
- * This function converts a buffer or string between encodings in one pass,
- * returning a string that must be freed with SDL_free() or NULL on error.
+ * This function converts a buffer or string between encodings in one pass, returning a
+ * string that must be freed with SDL_free() or NULL on error.
  *
  * \since This function is available since SDL 2.0.0.
  */
@@ -704,8 +698,8 @@ extern DECLSPEC char *SDLCALL SDL_iconv_string(const char *tocode,
                                                const char *inbuf,
                                                size_t inbytesleft);
 #define SDL_iconv_utf8_locale(S)    SDL_iconv_string("", "UTF-8", S, SDL_strlen(S)+1)
-#define SDL_iconv_utf8_ucs2(S)      (Uint16 *)SDL_iconv_string("UCS-2", "UTF-8", S, SDL_strlen(S)+1)
-#define SDL_iconv_utf8_ucs4(S)      (Uint32 *)SDL_iconv_string("UCS-4", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs2(S)      (Uint16 *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs4(S)      (Uint32 *)SDL_iconv_string("UCS-4-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
 #define SDL_iconv_wchar_utf8(S)     SDL_iconv_string("UTF-8", "WCHAR_T", (char *)S, (SDL_wcslen(S)+1)*sizeof(wchar_t))
 
 /* force builds using Clang's static analysis tools to use literal C runtime
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h
index ceeb86bd867e8a657626b20ed45f89cd5637f798..d6ee615c59f0a48bc284fde0b75b0dbb3ee9bee2 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h
index ddae4f8cc1f9ca980837f403101aca74fd7ddd5d..4b7eaddcc0ed9b2033de7ccf7cc00de8a5f58a9d 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -593,8 +593,7 @@ extern DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void
 
 /* Functions used only by GDK */
 #if defined(__GDK__)
-typedef struct XTaskQueueObject *XTaskQueueHandle;
-typedef struct XUser *XUserHandle;
+typedef struct XTaskQueueObject * XTaskQueueHandle;
 
 /**
  * Gets a reference to the global async task queue handle for GDK,
@@ -611,20 +610,6 @@ typedef struct XUser *XUserHandle;
  */
 extern DECLSPEC int SDLCALL SDL_GDKGetTaskQueue(XTaskQueueHandle * outTaskQueue);
 
-/**
- * Gets a reference to the default user handle for GDK.
- *
- * This is effectively a synchronous version of XUserAddAsync, which always
- * prefers the default user and allows a sign-in UI.
- *
- * \param outUserHandle a pointer to be filled in with the default user
- *                      handle.
- * \returns 0 if success, -1 if any error occurs.
- *
- * \since This function is available since SDL 2.28.0.
- */
-extern DECLSPEC int SDLCALL SDL_GDKGetDefaultUser(XUserHandle * outUserHandle);
-
 #endif
 
 /* Ends C function definitions when using C++ */
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h
index 7b8bd6ef996571bbba2e5f1e139a0c9292c88146..b35734deb334508c6fbfcc0b635417a9d2841052 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h
index e5acbee4e31782003083624c56f9d40eac5743bc..80daaafbd9b5dc1e4dfa8f48f5fa97e19caab062 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h
index 4f983350a3944145e8c42be3453d894bba8a1270..341e490facee39061766d2fa4b85c154870611dd 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h
index d977e463f117149f7d27cf3ec35fe65a735557a2..6de63cad6f8b08a5f4f28b9b2e5de0dc65da6b71 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h
index 61a38d09051145431d107793aadffba516e08d92..5fce25ca1856cef2790a13d1895dbdd95cb8a4ad 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h
index e3478318dc069a6087e6dffd23b424764bf96f04..bf34782103a218ef811e65a356ab6f900201aa54 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h
index 620c82116b3f3418cde5195a27e7e2247f19c88e..18a82ffc80f16a989cf37da79ed06a3e5279ff37 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
index a847ccb01ca25d80ffa7b4e36f9a2a8f12f7fa6f..cfe6a14f2a0288bd57cd00d642b4dd9c609a8c21 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h
index bd9e4f8de070ae4ac730e1414b8f4ca951252008..26231dcd6bce9e72d54ddbef532a278762634948 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h
index b5bcb0a0000c49ff42d35284df2c859c9a577ca9..1211371755fdfd7bed0953fe1322fdcb639637a3 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h
index ea9ae5e1ca1d9b5170d336b5f770f9c530fdb893..a27ffc209a95ca3dd105b08dbe8ca4509245fe4c 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h
index 3764b042569eb63323ef6a589a5f3252147d4476..538c7ae3e09caa78990f738337bfbf2db9a86459 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h
index 9bd143252cefbdff77396b68ea54132b1859f16f..f959177d2336b5cf649d4d12a41cf76bf7a52578 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h
index 344646aa8b24a589b63482528441afbd296f88f8..0035a8030ad2cc4751a87d5aea3c032cd3c4944f 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h
index dc7f5363aadce39089dd1399963e541d416028b8..b829bbad5dc08bc47f02c64efc24ac97556ac603 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h
index 8123e432f1e5065b67bf51277110fbd7caf886fd..98f9ad16c647e8ecca4829b0629ae15e767f895e 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h
index f6a5db413df92d8b253614ef723f546b581354b9..c12d4a1c8174997225ba25fe087bfb794e094f48 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h
index e8d33c651371bd2fd29b155f135461f66f6681bb..b5d7192ff2e95a994229a90e668ab003e16e5cab 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h
index 02143ff7a114e9cbe2a6113aa9d7726e2532808d..7585eece563127330f3e236174f55615d9f03ddf 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -58,8 +58,8 @@ typedef struct SDL_version
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_MAJOR_VERSION   2
-#define SDL_MINOR_VERSION   30
-#define SDL_PATCHLEVEL      0
+#define SDL_MINOR_VERSION   28
+#define SDL_PATCHLEVEL      5
 
 /**
  * Macro to determine SDL version program was compiled against.
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h
index fa47d30991df03867c400da2fe80bb32d93457a8..c8b2d7a0d871e1f84cf4bf52f3583f8f5aaaf727 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -1278,8 +1278,7 @@ extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window * window,
 /**
  * Return whether the window has a surface associated with it.
  *
- * \returns SDL_TRUE if there is a surface associated with the window, or
- *          SDL_FALSE otherwise.
+ * \returns SDL_TRUE if there is a surface associated with the window, or SDL_FALSE otherwise.
  *
  * \since This function is available since SDL 2.28.0.
  *
@@ -1341,11 +1340,6 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurface(SDL_Window * window);
  *
  * This function is equivalent to the SDL 1.2 API SDL_UpdateRects().
  *
- * Note that this function will update _at least_ the rectangles specified,
- * but this is only intended as an optimization; in practice, this might
- * update more of the screen (or all of the screen!), depending on what
- * method SDL uses to send pixels to the system.
- *
  * \param window the window to update
  * \param rects an array of SDL_Rect structures representing areas of the
  *              surface to copy, in pixels
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h
index a47a7d2b6413cbb4f5dcd7534123477697ef71a3..4142ffeba928866354f51bedf3d1b1a9b8a4c3d9 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -36,8 +36,6 @@
 #ifndef SDL_DEPRECATED
 #  if defined(__GNUC__) && (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
 #    define SDL_DEPRECATED __attribute__((deprecated))
-#  elif defined(_MSC_VER)
-#    define SDL_DEPRECATED __declspec(deprecated)
 #  else
 #    define SDL_DEPRECATED
 #  endif
diff --git a/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h b/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h
index 50a0e6f3b4462c5197bd15d7d22e6a8f36204b46..b5ff3e2049b666eeeb923d234b7179722fd8d6c3 100644
--- a/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h
+++ b/libs/SDL2/i686-w64-mingw32/include/SDL2/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake b/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake
index 82dfeab129e3a872175ac18a1cbc351c980616de..0e63829954166a1b637f058307f6202b00ceabfd 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake
+++ b/libs/SDL2/i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake
@@ -1,6 +1,6 @@
 # sdl2 cmake project-config-version input for ./configure scripts
 
-set(PACKAGE_VERSION "2.30.0")
+set(PACKAGE_VERSION "2.28.5")
 
 if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
   set(PACKAGE_VERSION_COMPATIBLE FALSE)
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a
index 927fd51a7831c0199014df3cded1936616f9646f..57a097cbf8cbaadbd9f4efc8dfa0713565d033e6 100644
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a
index 65add3aa8ad6b86458e828f962ca7983646f90f6..64f541cd81bb3f2f6fee7c7586c3b7b3642e4623 100755
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.dll.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la
index 0f885324bd25a2452dc75f22a396e0eec70da66f..9687a5e29ec997fa88c2d51441df70e238d27f34 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la
+++ b/libs/SDL2/i686-w64-mingw32/lib/libSDL2.la
@@ -23,9 +23,9 @@ dependency_libs=' -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -
 weak_library_names=''
 
 # Version information for libSDL2.
-current=3000
-age=3000
-revision=0
+current=2800
+age=2800
+revision=5
 
 # Is this an already installed library?
 installed=yes
@@ -38,4 +38,4 @@ dlopen=''
 dlpreopen=''
 
 # Directory that this library needs to be installed in:
-libdir='/Users/valve/release/SDL2/SDL2-2.30.0/i686-w64-mingw32/lib'
+libdir='/Users/valve/release/SDL2/SDL2-2.28.5/i686-w64-mingw32/lib'
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a
index 4fcf88772ba06e0d0cc02f1e8fd0f905a36f07d5..71c766c1ccf58fd2323ea5a507d1221e8c767a8a 100644
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la
index b048909ca631a480743e77826f6d322c692a7e11..2e2e296e9d3c5b0fc557a76f84293487c4e682d2 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la
+++ b/libs/SDL2/i686-w64-mingw32/lib/libSDL2_test.la
@@ -38,4 +38,4 @@ dlopen=''
 dlpreopen=''
 
 # Directory that this library needs to be installed in:
-libdir='/Users/valve/release/SDL2/SDL2-2.30.0/i686-w64-mingw32/lib'
+libdir='/Users/valve/release/SDL2/SDL2-2.28.5/i686-w64-mingw32/lib'
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a
index 79a835a40b0de416b029df168a79f7acf56bff90..9f64593a652ae9047b6f00e42ddb788e161cd889 100644
Binary files a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a and b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.a differ
diff --git a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la
index 128a7f5b1428e0b7bad4749a25bfc3f740f87aac..6e12ee786d756ee65beadcbeee116d651646c20d 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la
+++ b/libs/SDL2/i686-w64-mingw32/lib/libSDL2main.la
@@ -38,4 +38,4 @@ dlopen=''
 dlpreopen=''
 
 # Directory that this library needs to be installed in:
-libdir='/Users/valve/release/SDL2/SDL2-2.30.0/i686-w64-mingw32/lib'
+libdir='/Users/valve/release/SDL2/SDL2-2.28.5/i686-w64-mingw32/lib'
diff --git a/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc b/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc
index e28b4803f2b37135dc3b092041761e6fc95b43f5..d52c268ea653f08574bd8df4292a8dc3c1e1a3e1 100644
--- a/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc
+++ b/libs/SDL2/i686-w64-mingw32/lib/pkgconfig/sdl2.pc
@@ -1,13 +1,13 @@
 # sdl pkg-config source file
 
-prefix=/usr/local/i686-w64-mingw32
+prefix=/i686-w64-mingw32
 exec_prefix=${prefix}
 libdir=${exec_prefix}/lib
 includedir=${prefix}/include
 
 Name: sdl2
 Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
-Version: 2.30.0
+Version: 2.28.5
 Requires.private: 
 Conflicts:
 Libs: -L${libdir}  -lmingw32 -lSDL2main -lSDL2 -mwindows 
diff --git a/libs/SDL2/i686-w64-mingw32/share/aclocal/sdl2.m4 b/libs/SDL2/i686-w64-mingw32/share/aclocal/sdl2.m4
index 274753b118aaf3184843800cc2297b9de568891b..75b60f6ea9338d050b32fd19b5214ef9c1024afa 100644
--- a/libs/SDL2/i686-w64-mingw32/share/aclocal/sdl2.m4
+++ b/libs/SDL2/i686-w64-mingw32/share/aclocal/sdl2.m4
@@ -9,9 +9,8 @@
 # * also look for SDL2.framework under Mac OS X
 # * removed HP/UX 9 support.
 # * updated for newer autoconf.
-# * (v3) use $PKG_CONFIG for pkg-config cross-compiling support
 
-# serial 3
+# serial 2
 
 dnl AM_PATH_SDL2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
 dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
@@ -55,7 +54,7 @@ AC_ARG_VAR(SDL2_FRAMEWORK, [Path to SDL2.framework])
 
   if test "x$sdl_pc" = xyes ; then
     no_sdl=""
-    SDL2_CONFIG="$PKG_CONFIG sdl2"
+    SDL2_CONFIG="pkg-config sdl2"
   else
     as_save_PATH="$PATH"
     if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then
diff --git a/libs/SDL2/include/SDL.h b/libs/SDL2/include/SDL.h
index 20c903b2fe4f60836b397cb19af7e07ca19f3071..9ba8f68c6e7966906d5832985a0f4ebc400a8878 100644
--- a/libs/SDL2/include/SDL.h
+++ b/libs/SDL2/include/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_assert.h b/libs/SDL2/include/SDL_assert.h
index a396d4e02ed20041a742e22ffb4efaa68995db03..7ce823ec5433f2d168889d7ac9239cd9f6ac6171 100644
--- a/libs/SDL2/include/SDL_assert.h
+++ b/libs/SDL2/include/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_atomic.h b/libs/SDL2/include/SDL_atomic.h
index 1fa18f49fe078348ec235adca77cbb6374a62e25..1dd816a3826e307f8b7cb436ce95edd28cee7a5c 100644
--- a/libs/SDL2/include/SDL_atomic.h
+++ b/libs/SDL2/include/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -209,7 +209,7 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
-#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
+#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__)
 #ifdef __thumb__
 /* The mcr instruction isn't available in thumb mode, use real functions */
 #define SDL_MEMORY_BARRIER_USES_FUNCTION
diff --git a/libs/SDL2/include/SDL_audio.h b/libs/SDL2/include/SDL_audio.h
index bd8e7ab6fa6d8336bf78fe732726782105f65dfe..ccd35982df124d75a8007791bce88da405c76a75 100644
--- a/libs/SDL2/include/SDL_audio.h
+++ b/libs/SDL2/include/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_bits.h b/libs/SDL2/include/SDL_bits.h
index 83e8a78c783c473184dd1674279fbdb4caafab8e..81161ae5f30633f2d708e9b7806ba005bdd9c21a 100644
--- a/libs/SDL2/include/SDL_bits.h
+++ b/libs/SDL2/include/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_blendmode.h b/libs/SDL2/include/SDL_blendmode.h
index 09d01477d8db63ecf6e9de2483472b9d17641567..4ecbe50785e9d37fcd57325a5301df6d25237997 100644
--- a/libs/SDL2/include/SDL_blendmode.h
+++ b/libs/SDL2/include/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -65,8 +65,8 @@ typedef enum
 typedef enum
 {
     SDL_BLENDOPERATION_ADD              = 0x1,  /**< dst + src: supported by all renderers */
-    SDL_BLENDOPERATION_SUBTRACT         = 0x2,  /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
-    SDL_BLENDOPERATION_REV_SUBTRACT     = 0x3,  /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
+    SDL_BLENDOPERATION_SUBTRACT         = 0x2,  /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
+    SDL_BLENDOPERATION_REV_SUBTRACT     = 0x3,  /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
     SDL_BLENDOPERATION_MINIMUM          = 0x4,  /**< min(dst, src) : supported by D3D9, D3D11 */
     SDL_BLENDOPERATION_MAXIMUM          = 0x5   /**< max(dst, src) : supported by D3D9, D3D11 */
 } SDL_BlendOperation;
diff --git a/libs/SDL2/include/SDL_clipboard.h b/libs/SDL2/include/SDL_clipboard.h
index bd4b044c6dd4ec0f0ed298f4333d3aed79702001..7c351fbb9c98aacbbf9136b3373b04ad321fe456 100644
--- a/libs/SDL2/include/SDL_clipboard.h
+++ b/libs/SDL2/include/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_config.h b/libs/SDL2/include/SDL_config.h
index dba78086016e4d11489ccdb27cda9972ec0d862d..01322c1829401fecea1b72889dfe4d313c5f0175 100644
--- a/libs/SDL2/include/SDL_config.h
+++ b/libs/SDL2/include/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_cpuinfo.h b/libs/SDL2/include/SDL_cpuinfo.h
index 2a9dd380c2e7b8d4ba5f6e8aec4c13d5becd565d..ed5e97915e314132f76df1747f76a5633dbd2b44 100644
--- a/libs/SDL2/include/SDL_cpuinfo.h
+++ b/libs/SDL2/include/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_egl.h b/libs/SDL2/include/SDL_egl.h
index a4276e6810b2fe059720cb2fe81e234e599e663c..6f51c0831afb94f82f03f92fdec39c622b0b3858 100644
--- a/libs/SDL2/include/SDL_egl.h
+++ b/libs/SDL2/include/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_endian.h b/libs/SDL2/include/SDL_endian.h
index 591ccac4256adc9f17c7ba0234ff745e1fb71a31..71bc06729b6425ad9a4a96ca12e430409fb50514 100644
--- a/libs/SDL2/include/SDL_endian.h
+++ b/libs/SDL2/include/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_error.h b/libs/SDL2/include/SDL_error.h
index 2df6463ad92f2183c0ac3c936bf1277bdef02e22..31c22616ccb0f276d3cab3caef4a769c5381b0ae 100644
--- a/libs/SDL2/include/SDL_error.h
+++ b/libs/SDL2/include/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_events.h b/libs/SDL2/include/SDL_events.h
index eccbba2553b4fce528c41741b15d7419597afcf6..9d097031805f33ff18e0a9bf381e22fb0f662dd0 100644
--- a/libs/SDL2/include/SDL_events.h
+++ b/libs/SDL2/include/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -131,8 +131,6 @@ typedef enum
     SDL_CONTROLLERTOUCHPADMOTION,      /**< Game controller touchpad finger was moved */
     SDL_CONTROLLERTOUCHPADUP,          /**< Game controller touchpad finger was lifted */
     SDL_CONTROLLERSENSORUPDATE,        /**< Game controller sensor was updated */
-    SDL_CONTROLLERUPDATECOMPLETE_RESERVED_FOR_SDL3,
-    SDL_CONTROLLERSTEAMHANDLEUPDATED,  /**< Game controller Steam handle has changed */
 
     /* Touch events */
     SDL_FINGERDOWN      = 0x700,
@@ -448,7 +446,7 @@ typedef struct SDL_ControllerButtonEvent
  */
 typedef struct SDL_ControllerDeviceEvent
 {
-    Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, ::SDL_CONTROLLERDEVICEREMAPPED, or ::SDL_CONTROLLERSTEAMHANDLEUPDATED */
+    Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, or ::SDL_CONTROLLERDEVICEREMAPPED */
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
     Sint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */
 } SDL_ControllerDeviceEvent;
@@ -582,6 +580,15 @@ typedef struct SDL_QuitEvent
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
 } SDL_QuitEvent;
 
+/**
+ *  \brief OS Specific event
+ */
+typedef struct SDL_OSEvent
+{
+    Uint32 type;        /**< ::SDL_QUIT */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+} SDL_OSEvent;
+
 /**
  *  \brief A user-defined event type (event.user.*)
  */
diff --git a/libs/SDL2/include/SDL_filesystem.h b/libs/SDL2/include/SDL_filesystem.h
index 07498898d3238d6b7c824761c46421e46991c84d..4cad657ec86e7b245a4a3046effd2ed783085932 100644
--- a/libs/SDL2/include/SDL_filesystem.h
+++ b/libs/SDL2/include/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -64,7 +64,7 @@ extern "C" {
  * directory of the application as it is uncommon to store resources outside
  * the executable. As such it is not a writable directory.
  *
- * The returned path is guaranteed to end with a path separator ('\\' on
+ * The returned path is guaranteed to end with a path separator ('\' on
  * Windows, '/' on most other platforms).
  *
  * The pointer returned is owned by the caller. Please call SDL_free() on the
@@ -120,7 +120,7 @@ extern DECLSPEC char *SDLCALL SDL_GetBasePath(void);
  * - ...only use letters, numbers, and spaces. Avoid punctuation like "Game
  *   Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
  *
- * The returned path is guaranteed to end with a path separator ('\\' on
+ * The returned path is guaranteed to end with a path separator ('\' on
  * Windows, '/' on most other platforms).
  *
  * The pointer returned is owned by the caller. Please call SDL_free() on the
diff --git a/libs/SDL2/include/SDL_gamecontroller.h b/libs/SDL2/include/SDL_gamecontroller.h
index 281fa356c63f58cfa5701ff6ae80f1d83c0f6aa8..140054d36ee625c57be7cc976087691b8746f7f4 100644
--- a/libs/SDL2/include/SDL_gamecontroller.h
+++ b/libs/SDL2/include/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -73,8 +73,7 @@ typedef enum
     SDL_CONTROLLER_TYPE_NVIDIA_SHIELD,
     SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
     SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
-    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR,
-    SDL_CONTROLLER_TYPE_MAX
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
 } SDL_GameControllerType;
 
 typedef enum
@@ -524,20 +523,6 @@ extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetFirmwareVersion(SDL_GameCont
  */
 extern DECLSPEC const char * SDLCALL SDL_GameControllerGetSerial(SDL_GameController *gamecontroller);
 
-/**
- * Get the Steam Input handle of an opened controller, if available.
- *
- * Returns an InputHandle_t for the controller that can be used with Steam Input API:
- * https://partner.steamgames.com/doc/api/ISteamInput
- *
- * \param gamecontroller the game controller object to query.
- * \returns the gamepad handle, or 0 if unavailable.
- *
- * \since This function is available since SDL 2.30.0.
- */
-extern DECLSPEC Uint64 SDLCALL SDL_GameControllerGetSteamHandle(SDL_GameController *gamecontroller);
-
-
 /**
  * Check if a controller has been opened and is currently connected.
  *
@@ -613,9 +598,7 @@ extern DECLSPEC void SDLCALL SDL_GameControllerUpdate(void);
  *  and are centered within ~8000 of zero, though advanced UI will allow users to set
  *  or autodetect the dead zone, which varies between controllers.
  *
- *  Trigger axis values range from 0 (released) to SDL_JOYSTICK_AXIS_MAX
- *  (fully pressed) when reported by SDL_GameControllerGetAxis(). Note that this is not the
- *  same range that will be reported by the lower-level SDL_GetJoystickAxis().
+ *  Trigger axis values range from 0 to SDL_JOYSTICK_AXIS_MAX.
  */
 typedef enum
 {
@@ -704,13 +687,8 @@ SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameController
  *
  * The axis indices start at index 0.
  *
- * For thumbsticks, the state is a value ranging from -32768 (up/left)
- * to 32767 (down/right).
- *
- * Triggers range from 0 when released to 32767 when fully pressed, and
- * never return a negative value. Note that this differs from the value
- * reported by the lower-level SDL_GetJoystickAxis(), which normally uses
- * the full range.
+ * The state is a value ranging from -32768 to 32767. Triggers, however, range
+ * from 0 to 32767 (they never return a negative value).
  *
  * \param gamecontroller a game controller
  * \param axis an axis index (one of the SDL_GameControllerAxis values)
diff --git a/libs/SDL2/include/SDL_gesture.h b/libs/SDL2/include/SDL_gesture.h
index 4fffa5f3e87df75d287da5c6ed0e795ab49d7768..db70b4dd843d983dea8988a60b12f92a739faa0a 100644
--- a/libs/SDL2/include/SDL_gesture.h
+++ b/libs/SDL2/include/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_guid.h b/libs/SDL2/include/SDL_guid.h
index 7daa5f1f585c3d7482108e915ea0ea8fa263751b..d964223c62ca79b46bdb6aa69ba9ed4e256d1f9b 100644
--- a/libs/SDL2/include/SDL_guid.h
+++ b/libs/SDL2/include/SDL_guid.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_haptic.h b/libs/SDL2/include/SDL_haptic.h
index c9ed847df02387a5f4d5f5fd02055695cd46a5e6..2462a1e47b3731a20f68af4a2d0d9cdfa5c76e59 100644
--- a/libs/SDL2/include/SDL_haptic.h
+++ b/libs/SDL2/include/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_hidapi.h b/libs/SDL2/include/SDL_hidapi.h
index b9d8ffac3881e2a297da348e8afb832b0b4afea9..0575100357798a4b34365b5f37d0ef57d1cf831c 100644
--- a/libs/SDL2/include/SDL_hidapi.h
+++ b/libs/SDL2/include/SDL_hidapi.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_hints.h b/libs/SDL2/include/SDL_hints.h
index e775a6509bc0e4834be32411ddadd1cfd0f2a99b..00beef51e29ed9e610182c7db3d88da70a98230f 100644
--- a/libs/SDL2/include/SDL_hints.h
+++ b/libs/SDL2/include/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -631,110 +631,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
 
-/**
- *  A variable containing a list of arcade stick style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES "SDL_JOYSTICK_ARCADESTICK_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not arcade stick style controllers. This will override SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED "SDL_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices that should not be considerd joysticks.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_BLACKLIST_DEVICES "SDL_JOYSTICK_BLACKLIST_DEVICES"
-
-/**
- *  A variable containing a list of devices that should be considered joysticks. This will override SDL_HINT_JOYSTICK_BLACKLIST_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED "SDL_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of flightstick style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES "SDL_JOYSTICK_FLIGHTSTICK_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not flightstick style controllers. This will override SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED "SDL_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices known to have a GameCube form factor.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES "SDL_JOYSTICK_GAMECUBE_DEVICES"
-
-/**
- *  A variable containing a list of devices known not to have a GameCube form factor. This will override SDL_HINT_JOYSTICK_GAMECUBE_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED "SDL_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED"
-
 /**
  *  \brief  A variable controlling whether the HIDAPI joystick drivers should be used.
  *
@@ -943,17 +839,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
 
-/**
- *  \brief  A variable controlling whether the HIDAPI driver for the Steam Deck builtin controller should be used.
- *
- *  This variable can be set to the following values:
- *    "0"       - HIDAPI driver is not used
- *    "1"       - HIDAPI driver is used
- *
- *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
- */
-#define SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK "SDL_JOYSTICK_HIDAPI_STEAMDECK"
-
 /**
  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
  *
@@ -1080,24 +965,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED"
 
-/**
-  *  A variable controlling whether IOKit should be used for controller handling.
-  *
-  *  This variable can be set to the following values:
-  *    "0"       - IOKit is not used
-  *    "1"       - IOKit is used (the default)
-  */
-#define SDL_HINT_JOYSTICK_IOKIT "SDL_JOYSTICK_IOKIT"
-
-/**
-  *  A variable controlling whether GCController should be used for controller handling.
-  *
-  *  This variable can be set to the following values:
-  *    "0"       - GCController is not used
-  *    "1"       - GCController is used (the default)
-  */
-#define SDL_HINT_JOYSTICK_MFI "SDL_JOYSTICK_MFI"
-
 /**
   *  \brief  A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
   *
@@ -1140,32 +1007,6 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_THREAD "SDL_JOYSTICK_THREAD"
 
-/**
- *  A variable containing a list of throttle style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_THROTTLE_DEVICES "SDL_JOYSTICK_THROTTLE_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not throttle style controllers. This will override SDL_HINT_JOYSTICK_THROTTLE_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_THROTTLE_DEVICES_EXCLUDED "SDL_JOYSTICK_THROTTLE_DEVICES_EXCLUDED"
-
 /**
   *  \brief  A variable controlling whether Windows.Gaming.Input should be used for controller handling.
   *
@@ -1175,45 +1016,6 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_WGI "SDL_JOYSTICK_WGI"
 
-/**
- *  A variable containing a list of wheel style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_WHEEL_DEVICES "SDL_JOYSTICK_WHEEL_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not wheel style controllers. This will override SDL_HINT_JOYSTICK_WHEEL_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_WHEEL_DEVICES_EXCLUDED "SDL_JOYSTICK_WHEEL_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices known to have all axes centered at zero.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES"
-
 /**
  * \brief Determines whether SDL enforces that DRM master is required in order
  *        to initialize the KMSDRM video backend.
@@ -1282,22 +1084,6 @@ extern "C" {
   */
 #define SDL_HINT_LINUX_JOYSTICK_DEADZONES "SDL_LINUX_JOYSTICK_DEADZONES"
 
-/**
- *  \brief A variable controlling the default SDL log levels.
- *
- *  This variable is a comma separated set of category=level tokens that define the default logging levels for SDL applications.
- *
- *  The category can be a numeric category, one of "app", "error", "assert", "system", "audio", "video", "render", "input", "test", or `*` for any unspecified category.
- *
- *  The level can be a numeric level, one of "verbose", "debug", "info", "warn", "error", "critical", or "quiet" to disable that category.
- *
- *  You can omit the category if you want to set the logging level for all categories.
- *
- *  If this hint isn't set, the default log levels are equivalent to:
- *  "app=info,assert=warn,test=verbose,*=error"
- */
-#define SDL_HINT_LOGGING   "SDL_LOGGING"
-
 /**
 *  \brief  When set don't force the SDL app to become a foreground process
 *
@@ -1699,32 +1485,6 @@ extern "C" {
  */
 #define SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE "SDL_RENDER_METAL_PREFER_LOW_POWER_DEVICE"
 
-/**
- *  A variable containing a list of ROG gamepad capable mice.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_ROG_GAMEPAD_MICE "SDL_ROG_GAMEPAD_MICE"
-
-/**
- *  A variable containing a list of devices that are not ROG gamepad capable mice. This will override SDL_HINT_ROG_GAMEPAD_MICE and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED "SDL_ROG_GAMEPAD_MICE_EXCLUDED"
-
 /**
  *  \brief  A variable controlling if VSYNC is automatically disable if doesn't reach the enough FPS
  *
@@ -2682,22 +2442,6 @@ extern "C" {
  */
 #define SDL_HINT_TRACKPAD_IS_TOUCH_ONLY "SDL_TRACKPAD_IS_TOUCH_ONLY"
 
-/**
- * Cause SDL to call dbus_shutdown() on quit.
- *
- * This is useful as a debug tool to validate memory leaks, but shouldn't ever
- * be set in production applications, as other libraries used by the application
- * might use dbus under the hood and this cause cause crashes if they continue
- * after SDL_Quit().
- *
- * This variable can be set to the following values:
- *   "0"       - SDL will not call dbus_shutdown() on quit (default)
- *   "1"       - SDL will call dbus_shutdown() on quit
- *
- * This hint is available since SDL 2.30.0.
- */
-#define SDL_HINT_SHUTDOWN_DBUS_ON_QUIT "SDL_SHUTDOWN_DBUS_ON_QUIT"
-
 
 /**
  *  \brief  An enumeration of hint priorities
diff --git a/libs/SDL2/include/SDL_joystick.h b/libs/SDL2/include/SDL_joystick.h
index 561e01099cede911e349969024f9b84bad658c2d..b9b4f622800d7a59285523c1407578ee130c0e32 100644
--- a/libs/SDL2/include/SDL_joystick.h
+++ b/libs/SDL2/include/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_keyboard.h b/libs/SDL2/include/SDL_keyboard.h
index 03c7b5a3705af4eb25d296049af1fe23ffd0b7d3..86a37ad1a241688e3ee3e658a824e5a78cba2918 100644
--- a/libs/SDL2/include/SDL_keyboard.h
+++ b/libs/SDL2/include/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -298,10 +298,8 @@ extern DECLSPEC void SDLCALL SDL_ClearComposition(void);
 extern DECLSPEC SDL_bool SDLCALL SDL_IsTextInputShown(void);
 
 /**
- * Set the rectangle used to type Unicode text inputs. Native input methods
- * will place a window with word suggestions near it, without covering the
- * text being inputted.
- * 
+ * Set the rectangle used to type Unicode text inputs.
+ *
  * To start text input in a given location, this function is intended to be
  * called before SDL_StartTextInput, although some platforms support moving
  * the rectangle even while text input (and a composition) is active.
diff --git a/libs/SDL2/include/SDL_keycode.h b/libs/SDL2/include/SDL_keycode.h
index 57a71bd79694d749d3702af58f3813540fb678d8..7106223027e75886652f3a2efd179d82561e350c 100644
--- a/libs/SDL2/include/SDL_keycode.h
+++ b/libs/SDL2/include/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_loadso.h b/libs/SDL2/include/SDL_loadso.h
index 4edc22e9e756c9f69fde1aced4679b63dc228e37..ca59b681cb45d9684223aaa6ab7287e809ced5f2 100644
--- a/libs/SDL2/include/SDL_loadso.h
+++ b/libs/SDL2/include/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_locale.h b/libs/SDL2/include/SDL_locale.h
index 0b6118f0ef8669930b2ce0aa5d4e9628381ae2df..482dbefe765fce9fe2e4248cc5e57e56e71b39b1 100644
--- a/libs/SDL2/include/SDL_locale.h
+++ b/libs/SDL2/include/SDL_locale.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_log.h b/libs/SDL2/include/SDL_log.h
index bd030c6d2d5f27ece4b3a74bd80d8f9b5708d05b..da733c4023d9c9f8ed62668e22ddb00c9f5c1fd4 100644
--- a/libs/SDL2/include/SDL_log.h
+++ b/libs/SDL2/include/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ extern "C" {
  *  By default the application category is enabled at the INFO level,
  *  the assert category is enabled at the WARN level, test is enabled
  *  at the VERBOSE level and all other categories are enabled at the
- *  ERROR level.
+ *  CRITICAL level.
  */
 typedef enum
 {
@@ -352,7 +352,7 @@ extern DECLSPEC void SDLCALL SDL_LogMessage(int category,
  */
 extern DECLSPEC void SDLCALL SDL_LogMessageV(int category,
                                              SDL_LogPriority priority,
-                                             SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(3);
+                                             const char *fmt, va_list ap);
 
 /**
  * The prototype for the log output callback function.
diff --git a/libs/SDL2/include/SDL_main.h b/libs/SDL2/include/SDL_main.h
index a66c84b4e5fbc2b45a5deca02e42b08e00ef1c66..5cc8e5913a4e705548739f0718d4878392c8a90e 100644
--- a/libs/SDL2/include/SDL_main.h
+++ b/libs/SDL2/include/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_messagebox.h b/libs/SDL2/include/SDL_messagebox.h
index 5ace6f2ddee1f8172416650c6fbdcd77e0a11ba9..7896fd1291f9211584447abcb4ab3edf320bc389 100644
--- a/libs/SDL2/include/SDL_messagebox.h
+++ b/libs/SDL2/include/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_metal.h b/libs/SDL2/include/SDL_metal.h
index 50f7b2aeb45211ce457bf9c6dc268eb86caa6be6..f36e34878cef20b686f7800fe112a5bd99f6a3b3 100644
--- a/libs/SDL2/include/SDL_metal.h
+++ b/libs/SDL2/include/SDL_metal.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_misc.h b/libs/SDL2/include/SDL_misc.h
index 113ba7a15693dea7e8fd65d4000fd0fb5ca75c18..13ed9c771835f15abdd16c53b5cf39d999159c65 100644
--- a/libs/SDL2/include/SDL_misc.h
+++ b/libs/SDL2/include/SDL_misc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_mouse.h b/libs/SDL2/include/SDL_mouse.h
index 687ff122d2c4fc2ba8616dc9fe30fb9764690100..aa07575738a5640c65e5f5dbc4a55661fe0a093e 100644
--- a/libs/SDL2/include/SDL_mouse.h
+++ b/libs/SDL2/include/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_mutex.h b/libs/SDL2/include/SDL_mutex.h
index eaa21f293f51721c44eb07d1623fb291f3fb7ada..e679d380890ea02d7a05021152aa183646fa178c 100644
--- a/libs/SDL2/include/SDL_mutex.h
+++ b/libs/SDL2/include/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_name.h b/libs/SDL2/include/SDL_name.h
index 71e9354550f913f1b76dccb0386a19d51dcd164a..5c3e07ab7d3e4a04fa436767527aa3e570a25d25 100644
--- a/libs/SDL2/include/SDL_name.h
+++ b/libs/SDL2/include/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengl.h b/libs/SDL2/include/SDL_opengl.h
index 2bb38c5c0e994443e99ce7b2ac3888d4beed435a..0ba89127ace681fa97744e94bad4728c59be9b53 100644
--- a/libs/SDL2/include/SDL_opengl.h
+++ b/libs/SDL2/include/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengles.h b/libs/SDL2/include/SDL_opengles.h
index 7e9a1ab8d4d037d06954b6ddd0df8684fb1a3db4..f4465eaa9da8ba3009fa4f3ee51eeecd0689283b 100644
--- a/libs/SDL2/include/SDL_opengles.h
+++ b/libs/SDL2/include/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_opengles2.h b/libs/SDL2/include/SDL_opengles2.h
index 96971344d1b863777ef6a567d321167ebeff4765..5e3b717def6cafa080adb200245e9528f0bf7cbc 100644
--- a/libs/SDL2/include/SDL_opengles2.h
+++ b/libs/SDL2/include/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_pixels.h b/libs/SDL2/include/SDL_pixels.h
index 44757cdcf4b7fdae9c499d8c773c2c5fe28e60d7..9abd57b42014a89b2761608bea2ae802ef9e8515 100644
--- a/libs/SDL2/include/SDL_pixels.h
+++ b/libs/SDL2/include/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -61,10 +61,7 @@ typedef enum
     SDL_PIXELTYPE_ARRAYU16,
     SDL_PIXELTYPE_ARRAYU32,
     SDL_PIXELTYPE_ARRAYF16,
-    SDL_PIXELTYPE_ARRAYF32,
-
-    /* This must be at the end of the list to avoid breaking the existing ABI */
-    SDL_PIXELTYPE_INDEX2
+    SDL_PIXELTYPE_ARRAYF32
 } SDL_PixelType;
 
 /** Bitmap pixel order, high bit -> low bit. */
@@ -137,7 +134,6 @@ typedef enum
 #define SDL_ISPIXELFORMAT_INDEXED(format)   \
     (!SDL_ISPIXELFORMAT_FOURCC(format) && \
      ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX1) || \
-      (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX2) || \
       (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX4) || \
       (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX8)))
 
@@ -181,12 +177,6 @@ typedef enum
     SDL_PIXELFORMAT_INDEX1MSB =
         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_1234, 0,
                                1, 0),
-    SDL_PIXELFORMAT_INDEX2LSB =
-        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX2, SDL_BITMAPORDER_4321, 0,
-                               2, 0),
-    SDL_PIXELFORMAT_INDEX2MSB =
-        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX2, SDL_BITMAPORDER_1234, 0,
-                               2, 0),
     SDL_PIXELFORMAT_INDEX4LSB =
         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_4321, 0,
                                4, 0),
@@ -286,19 +276,11 @@ typedef enum
     SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_ARGB8888,
     SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_BGRA8888,
     SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_ABGR8888,
-    SDL_PIXELFORMAT_RGBX32 = SDL_PIXELFORMAT_RGBX8888,
-    SDL_PIXELFORMAT_XRGB32 = SDL_PIXELFORMAT_XRGB8888,
-    SDL_PIXELFORMAT_BGRX32 = SDL_PIXELFORMAT_BGRX8888,
-    SDL_PIXELFORMAT_XBGR32 = SDL_PIXELFORMAT_XBGR8888,
 #else
     SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_ABGR8888,
     SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_BGRA8888,
     SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_ARGB8888,
     SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_RGBA8888,
-    SDL_PIXELFORMAT_RGBX32 = SDL_PIXELFORMAT_XBGR8888,
-    SDL_PIXELFORMAT_XRGB32 = SDL_PIXELFORMAT_BGRX8888,
-    SDL_PIXELFORMAT_BGRX32 = SDL_PIXELFORMAT_XRGB8888,
-    SDL_PIXELFORMAT_XBGR32 = SDL_PIXELFORMAT_RGBX8888,
 #endif
 
     SDL_PIXELFORMAT_YV12 =      /**< Planar mode: Y + V + U  (3 planes) */
diff --git a/libs/SDL2/include/SDL_platform.h b/libs/SDL2/include/SDL_platform.h
index 6e67b4577a3d040835a83fdc5e6332a33cc0bab5..d2a7e052d7b19051d020bb240856fbe6080e1af8 100644
--- a/libs/SDL2/include/SDL_platform.h
+++ b/libs/SDL2/include/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -166,12 +166,6 @@
 #define WINAPI_FAMILY_WINRT 0
 #endif /* HAVE_WINAPIFAMILY_H */
 
-#if (HAVE_WINAPIFAMILY_H) && defined(WINAPI_FAMILY_PHONE_APP)
-#define SDL_WINAPI_FAMILY_PHONE (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
-#else
-#define SDL_WINAPI_FAMILY_PHONE 0
-#endif
-
 #if WINAPI_FAMILY_WINRT
 #undef __WINRT__
 #define __WINRT__ 1
diff --git a/libs/SDL2/include/SDL_power.h b/libs/SDL2/include/SDL_power.h
index 0520065cebbb135035665cf95402a2b15b381d1a..1d75704c421c42b244f68b93edda5694f73d5c31 100644
--- a/libs/SDL2/include/SDL_power.h
+++ b/libs/SDL2/include/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_quit.h b/libs/SDL2/include/SDL_quit.h
index 3f69dc9f26011db121417874daa9ccbb1043f708..d8ceb894369194b5a0da17b8b4117ebf2edf0a88 100644
--- a/libs/SDL2/include/SDL_quit.h
+++ b/libs/SDL2/include/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_rect.h b/libs/SDL2/include/SDL_rect.h
index 5ce1f0b4517fa856ad7ee07e8c14fdf2f33f7c7a..9611a311ce83bc165a1ea968a51d4f968f9557d3 100644
--- a/libs/SDL2/include/SDL_rect.h
+++ b/libs/SDL2/include/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_render.h b/libs/SDL2/include/SDL_render.h
index b7135bb9dd46e73b4de07762cda78cc6b292bf3e..2d3f07366209ba01531b878102b28599b256725f 100644
--- a/libs/SDL2/include/SDL_render.h
+++ b/libs/SDL2/include/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -42,7 +42,7 @@
  *  of the many good 3D engines.
  *
  *  These functions must be called from the main thread.
- *  See this bug for details: https://github.com/libsdl-org/SDL/issues/986
+ *  See this bug for details: http://bugzilla.libsdl.org/show_bug.cgi?id=1995
  */
 
 #ifndef SDL_render_h_
diff --git a/libs/SDL2/include/SDL_revision.h b/libs/SDL2/include/SDL_revision.h
index ee42f8421d75d3d1e8a00051725414503c7ff132..4455a08b6289e407412cfb0c59b8d8022ea49d98 100644
--- a/libs/SDL2/include/SDL_revision.h
+++ b/libs/SDL2/include/SDL_revision.h
@@ -1,7 +1,7 @@
 /* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.30.0-0-g859844eae (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40 (" SDL_VENDOR_INFO ")"
 #else
-#define SDL_REVISION "SDL-release-2.30.0-0-g859844eae"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40"
 #endif
 #define SDL_REVISION_NUMBER 0
diff --git a/libs/SDL2/include/SDL_rwops.h b/libs/SDL2/include/SDL_rwops.h
index 9dd99f92b1541ba73386aeed906b16d4db415d17..8615cb542959def634d4a634cd24f24d3a5104a6 100644
--- a/libs/SDL2/include/SDL_rwops.h
+++ b/libs/SDL2/include/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_scancode.h b/libs/SDL2/include/SDL_scancode.h
index fe13d5b7aaad9378e49005640b0c7641cf0512dc..a960a7991c61accff7874c9c75d92099b350b858 100644
--- a/libs/SDL2/include/SDL_scancode.h
+++ b/libs/SDL2/include/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_sensor.h b/libs/SDL2/include/SDL_sensor.h
index 8b89ef6a526d45f11d7b3ac64234519df2164b22..9ecce44b17be8469a1572afe95b2ff8a323045bf 100644
--- a/libs/SDL2/include/SDL_sensor.h
+++ b/libs/SDL2/include/SDL_sensor.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_shape.h b/libs/SDL2/include/SDL_shape.h
index 4783cf290e95eec1a2e5b3f3a2ee5b7f94dcbf33..f66babc011339d5729fee081235f8f57815275c2 100644
--- a/libs/SDL2/include/SDL_shape.h
+++ b/libs/SDL2/include/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_stdinc.h b/libs/SDL2/include/SDL_stdinc.h
index 0035a357cf8e70d0e201413e726b149db96acfd3..182ed86ee371194ec6f45229626fa395472d0f8d 100644
--- a/libs/SDL2/include/SDL_stdinc.h
+++ b/libs/SDL2/include/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -257,7 +257,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIs64 PRIs64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIs64 "I64d"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIs64 "ld"
 #else
 #define SDL_PRIs64 "lld"
@@ -268,7 +268,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIu64 PRIu64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIu64 "I64u"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIu64 "lu"
 #else
 #define SDL_PRIu64 "llu"
@@ -279,7 +279,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIx64 PRIx64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIx64 "I64x"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIx64 "lx"
 #else
 #define SDL_PRIx64 "llx"
@@ -290,7 +290,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIX64 PRIX64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIX64 "I64X"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIX64 "lX"
 #else
 #define SDL_PRIX64 "llX"
@@ -336,9 +336,7 @@ typedef uint64_t Uint64;
 #define SDL_PRINTF_FORMAT_STRING
 #define SDL_SCANF_FORMAT_STRING
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber )
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber )
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber )
 #else
 #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */
 #include <sal.h>
@@ -364,14 +362,10 @@ typedef uint64_t Uint64;
 #endif
 #if defined(__GNUC__)
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __printf__, fmtargnumber, fmtargnumber+1 )))
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber ) __attribute__(( format( __printf__, fmtargnumber, 0 )))
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __scanf__, fmtargnumber, fmtargnumber+1 )))
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber ) __attribute__(( format( __scanf__, fmtargnumber, 0 )))
 #else
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber )
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber )
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber )
 #endif
 #endif /* SDL_DISABLE_ANALYZE_MACROS */
 
@@ -609,11 +603,11 @@ extern DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str2);
 extern DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t len);
 
 extern DECLSPEC int SDLCALL SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...) SDL_SCANF_VARARG_FUNC(2);
-extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, va_list ap) SDL_SCANF_VARARG_FUNCV(2);
+extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, const char *fmt, va_list ap);
 extern DECLSPEC int SDLCALL SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ... ) SDL_PRINTF_VARARG_FUNC(3);
-extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(3);
+extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap);
 extern DECLSPEC int SDLCALL SDL_asprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
-extern DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(2);
+extern DECLSPEC int SDLCALL SDL_vasprintf(char **strp, const char *fmt, va_list ap);
 
 #ifndef HAVE_M_PI
 #ifndef M_PI
@@ -694,8 +688,8 @@ extern DECLSPEC size_t SDLCALL SDL_iconv(SDL_iconv_t cd, const char **inbuf,
                                          size_t * outbytesleft);
 
 /**
- * This function converts a buffer or string between encodings in one pass,
- * returning a string that must be freed with SDL_free() or NULL on error.
+ * This function converts a buffer or string between encodings in one pass, returning a
+ * string that must be freed with SDL_free() or NULL on error.
  *
  * \since This function is available since SDL 2.0.0.
  */
@@ -704,8 +698,8 @@ extern DECLSPEC char *SDLCALL SDL_iconv_string(const char *tocode,
                                                const char *inbuf,
                                                size_t inbytesleft);
 #define SDL_iconv_utf8_locale(S)    SDL_iconv_string("", "UTF-8", S, SDL_strlen(S)+1)
-#define SDL_iconv_utf8_ucs2(S)      (Uint16 *)SDL_iconv_string("UCS-2", "UTF-8", S, SDL_strlen(S)+1)
-#define SDL_iconv_utf8_ucs4(S)      (Uint32 *)SDL_iconv_string("UCS-4", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs2(S)      (Uint16 *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs4(S)      (Uint32 *)SDL_iconv_string("UCS-4-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
 #define SDL_iconv_wchar_utf8(S)     SDL_iconv_string("UTF-8", "WCHAR_T", (char *)S, (SDL_wcslen(S)+1)*sizeof(wchar_t))
 
 /* force builds using Clang's static analysis tools to use literal C runtime
diff --git a/libs/SDL2/include/SDL_surface.h b/libs/SDL2/include/SDL_surface.h
index ceeb86bd867e8a657626b20ed45f89cd5637f798..d6ee615c59f0a48bc284fde0b75b0dbb3ee9bee2 100644
--- a/libs/SDL2/include/SDL_surface.h
+++ b/libs/SDL2/include/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_system.h b/libs/SDL2/include/SDL_system.h
index ddae4f8cc1f9ca980837f403101aca74fd7ddd5d..4b7eaddcc0ed9b2033de7ccf7cc00de8a5f58a9d 100644
--- a/libs/SDL2/include/SDL_system.h
+++ b/libs/SDL2/include/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -593,8 +593,7 @@ extern DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void
 
 /* Functions used only by GDK */
 #if defined(__GDK__)
-typedef struct XTaskQueueObject *XTaskQueueHandle;
-typedef struct XUser *XUserHandle;
+typedef struct XTaskQueueObject * XTaskQueueHandle;
 
 /**
  * Gets a reference to the global async task queue handle for GDK,
@@ -611,20 +610,6 @@ typedef struct XUser *XUserHandle;
  */
 extern DECLSPEC int SDLCALL SDL_GDKGetTaskQueue(XTaskQueueHandle * outTaskQueue);
 
-/**
- * Gets a reference to the default user handle for GDK.
- *
- * This is effectively a synchronous version of XUserAddAsync, which always
- * prefers the default user and allows a sign-in UI.
- *
- * \param outUserHandle a pointer to be filled in with the default user
- *                      handle.
- * \returns 0 if success, -1 if any error occurs.
- *
- * \since This function is available since SDL 2.28.0.
- */
-extern DECLSPEC int SDLCALL SDL_GDKGetDefaultUser(XUserHandle * outUserHandle);
-
 #endif
 
 /* Ends C function definitions when using C++ */
diff --git a/libs/SDL2/include/SDL_syswm.h b/libs/SDL2/include/SDL_syswm.h
index 7b8bd6ef996571bbba2e5f1e139a0c9292c88146..b35734deb334508c6fbfcc0b635417a9d2841052 100644
--- a/libs/SDL2/include/SDL_syswm.h
+++ b/libs/SDL2/include/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test.h b/libs/SDL2/include/SDL_test.h
index e5acbee4e31782003083624c56f9d40eac5743bc..80daaafbd9b5dc1e4dfa8f48f5fa97e19caab062 100644
--- a/libs/SDL2/include/SDL_test.h
+++ b/libs/SDL2/include/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_assert.h b/libs/SDL2/include/SDL_test_assert.h
index 4f983350a3944145e8c42be3453d894bba8a1270..341e490facee39061766d2fa4b85c154870611dd 100644
--- a/libs/SDL2/include/SDL_test_assert.h
+++ b/libs/SDL2/include/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_common.h b/libs/SDL2/include/SDL_test_common.h
index d977e463f117149f7d27cf3ec35fe65a735557a2..6de63cad6f8b08a5f4f28b9b2e5de0dc65da6b71 100644
--- a/libs/SDL2/include/SDL_test_common.h
+++ b/libs/SDL2/include/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_compare.h b/libs/SDL2/include/SDL_test_compare.h
index 61a38d09051145431d107793aadffba516e08d92..5fce25ca1856cef2790a13d1895dbdd95cb8a4ad 100644
--- a/libs/SDL2/include/SDL_test_compare.h
+++ b/libs/SDL2/include/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_crc32.h b/libs/SDL2/include/SDL_test_crc32.h
index e3478318dc069a6087e6dffd23b424764bf96f04..bf34782103a218ef811e65a356ab6f900201aa54 100644
--- a/libs/SDL2/include/SDL_test_crc32.h
+++ b/libs/SDL2/include/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_font.h b/libs/SDL2/include/SDL_test_font.h
index 620c82116b3f3418cde5195a27e7e2247f19c88e..18a82ffc80f16a989cf37da79ed06a3e5279ff37 100644
--- a/libs/SDL2/include/SDL_test_font.h
+++ b/libs/SDL2/include/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_fuzzer.h b/libs/SDL2/include/SDL_test_fuzzer.h
index a847ccb01ca25d80ffa7b4e36f9a2a8f12f7fa6f..cfe6a14f2a0288bd57cd00d642b4dd9c609a8c21 100644
--- a/libs/SDL2/include/SDL_test_fuzzer.h
+++ b/libs/SDL2/include/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_harness.h b/libs/SDL2/include/SDL_test_harness.h
index bd9e4f8de070ae4ac730e1414b8f4ca951252008..26231dcd6bce9e72d54ddbef532a278762634948 100644
--- a/libs/SDL2/include/SDL_test_harness.h
+++ b/libs/SDL2/include/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_images.h b/libs/SDL2/include/SDL_test_images.h
index b5bcb0a0000c49ff42d35284df2c859c9a577ca9..1211371755fdfd7bed0953fe1322fdcb639637a3 100644
--- a/libs/SDL2/include/SDL_test_images.h
+++ b/libs/SDL2/include/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_log.h b/libs/SDL2/include/SDL_test_log.h
index ea9ae5e1ca1d9b5170d336b5f770f9c530fdb893..a27ffc209a95ca3dd105b08dbe8ca4509245fe4c 100644
--- a/libs/SDL2/include/SDL_test_log.h
+++ b/libs/SDL2/include/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_md5.h b/libs/SDL2/include/SDL_test_md5.h
index 3764b042569eb63323ef6a589a5f3252147d4476..538c7ae3e09caa78990f738337bfbf2db9a86459 100644
--- a/libs/SDL2/include/SDL_test_md5.h
+++ b/libs/SDL2/include/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_memory.h b/libs/SDL2/include/SDL_test_memory.h
index 9bd143252cefbdff77396b68ea54132b1859f16f..f959177d2336b5cf649d4d12a41cf76bf7a52578 100644
--- a/libs/SDL2/include/SDL_test_memory.h
+++ b/libs/SDL2/include/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_test_random.h b/libs/SDL2/include/SDL_test_random.h
index 344646aa8b24a589b63482528441afbd296f88f8..0035a8030ad2cc4751a87d5aea3c032cd3c4944f 100644
--- a/libs/SDL2/include/SDL_test_random.h
+++ b/libs/SDL2/include/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_thread.h b/libs/SDL2/include/SDL_thread.h
index dc7f5363aadce39089dd1399963e541d416028b8..b829bbad5dc08bc47f02c64efc24ac97556ac603 100644
--- a/libs/SDL2/include/SDL_thread.h
+++ b/libs/SDL2/include/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_timer.h b/libs/SDL2/include/SDL_timer.h
index 8123e432f1e5065b67bf51277110fbd7caf886fd..98f9ad16c647e8ecca4829b0629ae15e767f895e 100644
--- a/libs/SDL2/include/SDL_timer.h
+++ b/libs/SDL2/include/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_touch.h b/libs/SDL2/include/SDL_touch.h
index f6a5db413df92d8b253614ef723f546b581354b9..c12d4a1c8174997225ba25fe087bfb794e094f48 100644
--- a/libs/SDL2/include/SDL_touch.h
+++ b/libs/SDL2/include/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_types.h b/libs/SDL2/include/SDL_types.h
index e8d33c651371bd2fd29b155f135461f66f6681bb..b5d7192ff2e95a994229a90e668ab003e16e5cab 100644
--- a/libs/SDL2/include/SDL_types.h
+++ b/libs/SDL2/include/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/include/SDL_version.h b/libs/SDL2/include/SDL_version.h
index 02143ff7a114e9cbe2a6113aa9d7726e2532808d..7585eece563127330f3e236174f55615d9f03ddf 100644
--- a/libs/SDL2/include/SDL_version.h
+++ b/libs/SDL2/include/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -58,8 +58,8 @@ typedef struct SDL_version
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_MAJOR_VERSION   2
-#define SDL_MINOR_VERSION   30
-#define SDL_PATCHLEVEL      0
+#define SDL_MINOR_VERSION   28
+#define SDL_PATCHLEVEL      5
 
 /**
  * Macro to determine SDL version program was compiled against.
diff --git a/libs/SDL2/include/SDL_video.h b/libs/SDL2/include/SDL_video.h
index fa47d30991df03867c400da2fe80bb32d93457a8..c8b2d7a0d871e1f84cf4bf52f3583f8f5aaaf727 100644
--- a/libs/SDL2/include/SDL_video.h
+++ b/libs/SDL2/include/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -1278,8 +1278,7 @@ extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window * window,
 /**
  * Return whether the window has a surface associated with it.
  *
- * \returns SDL_TRUE if there is a surface associated with the window, or
- *          SDL_FALSE otherwise.
+ * \returns SDL_TRUE if there is a surface associated with the window, or SDL_FALSE otherwise.
  *
  * \since This function is available since SDL 2.28.0.
  *
@@ -1341,11 +1340,6 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurface(SDL_Window * window);
  *
  * This function is equivalent to the SDL 1.2 API SDL_UpdateRects().
  *
- * Note that this function will update _at least_ the rectangles specified,
- * but this is only intended as an optimization; in practice, this might
- * update more of the screen (or all of the screen!), depending on what
- * method SDL uses to send pixels to the system.
- *
  * \param window the window to update
  * \param rects an array of SDL_Rect structures representing areas of the
  *              surface to copy, in pixels
diff --git a/libs/SDL2/include/begin_code.h b/libs/SDL2/include/begin_code.h
index a47a7d2b6413cbb4f5dcd7534123477697ef71a3..4142ffeba928866354f51bedf3d1b1a9b8a4c3d9 100644
--- a/libs/SDL2/include/begin_code.h
+++ b/libs/SDL2/include/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -36,8 +36,6 @@
 #ifndef SDL_DEPRECATED
 #  if defined(__GNUC__) && (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
 #    define SDL_DEPRECATED __attribute__((deprecated))
-#  elif defined(_MSC_VER)
-#    define SDL_DEPRECATED __declspec(deprecated)
 #  else
 #    define SDL_DEPRECATED
 #  endif
diff --git a/libs/SDL2/include/close_code.h b/libs/SDL2/include/close_code.h
index 50a0e6f3b4462c5197bd15d7d22e6a8f36204b46..b5ff3e2049b666eeeb923d234b7179722fd8d6c3 100644
--- a/libs/SDL2/include/close_code.h
+++ b/libs/SDL2/include/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/lib/x64/SDL2.dll b/libs/SDL2/lib/x64/SDL2.dll
index 878760628d4855ee65934869a1f47050b6920678..e26bcb1c3be11930053e594bc070df85b68d7b89 100644
Binary files a/libs/SDL2/lib/x64/SDL2.dll and b/libs/SDL2/lib/x64/SDL2.dll differ
diff --git a/libs/SDL2/lib/x64/SDL2.lib b/libs/SDL2/lib/x64/SDL2.lib
index 7257de6383ca5732a50a1df3f41f2447a2625d1c..99c5321cab958bb4c2e43583c7866a69972923f7 100644
Binary files a/libs/SDL2/lib/x64/SDL2.lib and b/libs/SDL2/lib/x64/SDL2.lib differ
diff --git a/libs/SDL2/lib/x64/SDL2main.lib b/libs/SDL2/lib/x64/SDL2main.lib
index 1981305fc5bc2ea865b5f35d02eb0d2e9659e265..241e7c3c8e8e4f6b088e07adfeeb34867b347343 100644
Binary files a/libs/SDL2/lib/x64/SDL2main.lib and b/libs/SDL2/lib/x64/SDL2main.lib differ
diff --git a/libs/SDL2/lib/x64/SDL2test.lib b/libs/SDL2/lib/x64/SDL2test.lib
index 0255ad475e4deec32f313495ba1c4d3db4f51ee1..1fa2ecb04e8eb3287df625803c3d0c426a7a268a 100644
Binary files a/libs/SDL2/lib/x64/SDL2test.lib and b/libs/SDL2/lib/x64/SDL2test.lib differ
diff --git a/libs/SDL2/lib/x86/SDL2.dll b/libs/SDL2/lib/x86/SDL2.dll
index 3265fb2f3de9e06460e7c6a73a83236b494b89fd..573225caba5abb279c844c438de4d6de2f6a10f1 100644
Binary files a/libs/SDL2/lib/x86/SDL2.dll and b/libs/SDL2/lib/x86/SDL2.dll differ
diff --git a/libs/SDL2/lib/x86/SDL2.lib b/libs/SDL2/lib/x86/SDL2.lib
index 0ac84d292be475cdf212bc9f5f34e843b633f48c..b35ba62a2807cb26a2ed8f29224d9744d6031ece 100644
Binary files a/libs/SDL2/lib/x86/SDL2.lib and b/libs/SDL2/lib/x86/SDL2.lib differ
diff --git a/libs/SDL2/lib/x86/SDL2main.lib b/libs/SDL2/lib/x86/SDL2main.lib
index 7cd691b62e67bffb3ae0f5348f14bef1f70782e3..eccce234347008bc5fa8c36005eef964df44447d 100644
Binary files a/libs/SDL2/lib/x86/SDL2main.lib and b/libs/SDL2/lib/x86/SDL2main.lib differ
diff --git a/libs/SDL2/lib/x86/SDL2test.lib b/libs/SDL2/lib/x86/SDL2test.lib
index 36ce4e0a59a7b4af853822ce0ed669959363fd85..21892ca9c737b69ac39e8d8b4a417c9ec1f2d961 100644
Binary files a/libs/SDL2/lib/x86/SDL2test.lib and b/libs/SDL2/lib/x86/SDL2test.lib differ
diff --git a/libs/SDL2/test/CMakeLists.txt b/libs/SDL2/test/CMakeLists.txt
index f048d51f9edcdfe1ed55ee2667606a07c4bc53a5..52a268561cb3ff21c7dc5d1318e808c6e503e702 100644
--- a/libs/SDL2/test/CMakeLists.txt
+++ b/libs/SDL2/test/CMakeLists.txt
@@ -7,55 +7,18 @@ include(CMakePushCheckState)
 
 set(SDL_TEST_EXECUTABLES)
 set(SDL_TESTS_NONINTERACTIVE)
-set(SDL_TESTS_NEEDS_RESOURCES)
+set(SDL_TESTS_NEEDS_ESOURCES)
 
 macro(add_sdl_test_executable TARGET)
     cmake_parse_arguments(AST "NONINTERACTIVE;NEEDS_RESOURCES" "" "" ${ARGN})
-    if(ANDROID)
-        add_library(${TARGET} SHARED ${AST_UNPARSED_ARGUMENTS})
-    else()
-        add_executable(${TARGET} ${AST_UNPARSED_ARGUMENTS})
-    endif()
+    add_executable(${TARGET} ${AST_UNPARSED_ARGUMENTS})
 
     list(APPEND SDL_TEST_EXECUTABLES ${TARGET})
     if(AST_NONINTERACTIVE)
         list(APPEND SDL_TESTS_NONINTERACTIVE ${TARGET})
     endif()
     if(AST_NEEDS_RESOURCES)
-        list(APPEND SDL_TESTS_NEEDS_RESOURCES ${TARGET})
-    endif()
-
-    if(HAVE_GCC_WDOCUMENTATION)
-        target_compile_options(${TARGET} PRIVATE "-Wdocumentation")
-        if(HAVE_GCC_WERROR_DOCUMENTATION)
-            target_compile_options(${TARGET} PRIVATE "-Werror=documentation")
-        endif()
-    endif()
-
-    if(HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND)
-        if(SDL_WERROR)
-            if(HAVE_GCC_WERROR_DOCUMENTATION_UNKNOWN_COMMAND)
-                target_compile_options(${TARGET} PRIVATE "-Werror=documentation-unknown-command")
-            endif()
-        endif()
-        target_compile_options(${TARGET} PRIVATE "-Wdocumentation-unknown-command")
-    endif()
-
-    if(HAVE_GCC_COMMENT_BLOCK_COMMANDS)
-        target_compile_options(${TARGET} PRIVATE "-fcomment-block-commands=threadsafety")
-        target_compile_options(${TARGET} PRIVATE "-fcomment-block-commands=deprecated")
-    else()
-        if(HAVE_CLANG_COMMENT_BLOCK_COMMANDS)
-            target_compile_options(${TARGET} PRIVATE "/clang:-fcomment-block-commands=threadsafety")
-            target_compile_options(${TARGET} PRIVATE "/clang:-fcomment-block-commands=deprecated")
-        endif()
-    endif()
-
-    if(USE_GCC OR USE_CLANG)
-        check_c_compiler_flag(-fno-fast-math HAVE_GCC_FNO_FAST_MATH)
-        if(HAVE_GCC_FNO_FAST_MATH)
-            target_compile_options(${TARGET} PRIVATE -fno-fast-math)
-        endif()
+        list(APPEND SDL_TESTS_NEEDS_ESOURCES ${TARGET})
     endif()
 endmacro()
 
@@ -90,7 +53,7 @@ if(PSP)
         psppower
     )
 elseif(PS2)
-    link_libraries(
+link_libraries(
         SDL2main
         SDL2_test
         SDL2-static
@@ -98,7 +61,7 @@ elseif(PS2)
         gskit
         dmakit
         ps2_drivers
-    )
+)
 else()
     link_libraries(SDL2::SDL2test SDL2::SDL2-static)
 endif()
@@ -128,7 +91,7 @@ if(NOT MSVC OR NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
 endif()
 
 if (OPENGL_FOUND)
-    add_definitions(-DHAVE_OPENGL)
+add_definitions(-DHAVE_OPENGL)
 endif()
 
 add_sdl_test_executable(checkkeys checkkeys.c)
@@ -140,7 +103,7 @@ add_sdl_test_executable(testresample NEEDS_RESOURCES testresample.c)
 add_sdl_test_executable(testaudioinfo testaudioinfo.c)
 
 file(GLOB TESTAUTOMATION_SOURCE_FILES testautomation*.c)
-add_sdl_test_executable(testautomation NONINTERACTIVE NEEDS_RESOURCES ${TESTAUTOMATION_SOURCE_FILES})
+add_sdl_test_executable(testautomation NEEDS_RESOURCES ${TESTAUTOMATION_SOURCE_FILES})
 add_sdl_test_executable(testmultiaudio NEEDS_RESOURCES testmultiaudio.c testutils.c)
 add_sdl_test_executable(testaudiohotplug NEEDS_RESOURCES testaudiohotplug.c testutils.c)
 add_sdl_test_executable(testaudiocapture testaudiocapture.c)
@@ -254,18 +217,18 @@ endif()
 cmake_pop_check_state()
 
 if(SDL_DUMMYAUDIO)
-    list(APPEND SDL_TESTS_NONINTERACTIVE
-        testaudioinfo
-        testsurround
-    )
+  list(APPEND SDL_TESTS_NONINTERACTIVE
+    testaudioinfo
+    testsurround
+  )
 endif()
 
 if(SDL_DUMMYVIDEO)
-    list(APPEND SDL_TESTS_NONINTERACTIVE
-        testkeys
-        testbounds
-        testdisplayinfo
-    )
+  list(APPEND SDL_TESTS_NONINTERACTIVE
+    testkeys
+    testbounds
+    testdisplayinfo
+  )
 endif()
 
 if(OPENGL_FOUND)
@@ -291,7 +254,7 @@ file(COPY ${RESOURCE_FILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
 if(PSP)
     # Build EBOOT files if building for PSP
     set(BUILD_EBOOT
-        ${SDL_TESTS_NEEDS_RESOURCES}
+        ${SDL_TESTS_NEEDS_ESOURCES}
         testatomic
         testaudiocapture
         testaudioinfo
@@ -400,41 +363,14 @@ if(RISCOS)
     endforeach()
 endif()
 
-if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
-    set(test_bin_dir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
-    if(NOT IS_ABSOLUTE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
-        set(test_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
-    endif()
-else()
-    set(test_bin_dir "${CMAKE_CURRENT_BINARY_DIR}")
-endif()
-if(NOT CMAKE_VERSION VERSION_LESS 3.20)
-    get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-    set(test_bin_dir "${test_bin_dir}$<$<BOOL:${is_multi_config}>:/$<CONFIG>>")
-endif()
-
-set(RESOURCE_FILES_BINDIR)
-foreach(resource_file IN LISTS RESOURCE_FILES)
-    get_filename_component(res_file_name ${resource_file} NAME)
-    set(resource_file_bindir "${test_bin_dir}/${res_file_name}")
-    add_custom_command(OUTPUT "${resource_file_bindir}"
-        COMMAND "${CMAKE_COMMAND}" -E copy "${resource_file}" "${resource_file_bindir}"
-        DEPENDS "${resource_file}"
-    )
-    list(APPEND RESOURCE_FILES_BINDIR "${resource_file_bindir}")
-endforeach()
-add_custom_target(copy-sdl-test-resources
-    DEPENDS "${RESOURCE_FILES_BINDIR}"
-)
-
 foreach(APP IN LISTS SDL_TESTS_NEEDS_RESOURCES)
-    if(PSP OR PS2)
-        foreach(RESOURCE_FILE ${RESOURCE_FILES})
+    foreach(RESOURCE_FILE ${RESOURCE_FILES})
+        if(PSP OR PS2)
             add_custom_command(TARGET ${APP} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${RESOURCE_FILE} $<TARGET_FILE_DIR:${APP}>/sdl-${APP})
-        endforeach()
-    else()
-        add_dependencies(${APP} copy-sdl-test-resources)
-    endif()
+        else()
+            add_custom_command(TARGET ${APP} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${RESOURCE_FILE} $<TARGET_FILE_DIR:${APP}>)
+        endif()
+    endforeach(RESOURCE_FILE)
     if(APPLE)
         # Make sure resource files get installed into macOS/iOS .app bundles.
         target_sources(${APP} PRIVATE "${RESOURCE_FILES}")
@@ -491,7 +427,6 @@ foreach(TESTCASE ${SDL_TESTS_NONINTERACTIVE})
     endif()
 endforeach()
 
-set_tests_properties(testautomation PROPERTIES TIMEOUT 120)
 set_tests_properties(testthread PROPERTIES TIMEOUT 40)
 set_tests_properties(testtimer PROPERTIES TIMEOUT 60)
 if(TARGET testfilesystem_pre)
@@ -511,11 +446,6 @@ if(SDL_INSTALL_TESTS)
             DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL2
         )
     endif()
-    if(MSVC)
-        foreach(test ${SDL_TEST_EXECUTABLES})
-            SDL_install_pdb(${test} "${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL2")
-        endforeach()
-    endif()
     install(
         FILES ${RESOURCE_FILES}
         DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL2
diff --git a/libs/SDL2/test/Makefile.in b/libs/SDL2/test/Makefile.in
index 76331d67fdd50191f211345a8a7c6a2df0b93b31..93df6360e847c37a1bde5845d4031bb91289d116 100644
--- a/libs/SDL2/test/Makefile.in
+++ b/libs/SDL2/test/Makefile.in
@@ -95,7 +95,7 @@ installedtestsmetadir = $(datadir)/installed-tests/SDL2
 
 generatetestmeta:
 	rm -f *.test
-	set -e; for exe in $(TESTS); do \
+	set -e; for exe in $(noninteractive) $(needs_audio) $(needs_display); do \
 		sed \
 			-e 's#@installedtestsdir@#$(installedtestsdir)#g' \
 			-e "s#@exe@#$$exe#g" \
@@ -141,7 +141,6 @@ testautomation$(EXE): $(srcdir)/testautomation.c \
 		      $(srcdir)/testautomation_hints.c \
 		      $(srcdir)/testautomation_joystick.c \
 		      $(srcdir)/testautomation_keyboard.c \
-		      $(srcdir)/testautomation_log.c \
 		      $(srcdir)/testautomation_main.c \
 		      $(srcdir)/testautomation_math.c \
 		      $(srcdir)/testautomation_mouse.c \
@@ -152,7 +151,6 @@ testautomation$(EXE): $(srcdir)/testautomation.c \
 		      $(srcdir)/testautomation_rwops.c \
 		      $(srcdir)/testautomation_sdltest.c \
 		      $(srcdir)/testautomation_stdlib.c \
-		      $(srcdir)/testautomation_subsystems.c \
 		      $(srcdir)/testautomation_surface.c \
 		      $(srcdir)/testautomation_syswm.c \
 		      $(srcdir)/testautomation_timer.c \
@@ -387,12 +385,8 @@ distclean: clean
 	rm -f config.status config.cache config.log
 	rm -rf $(srcdir)/autom4te*
 
-TESTS = \
+noninteractive = \
 	testatomic$(EXE) \
-	testaudioinfo$(EXE) \
-	testautomation$(EXE) \
-	testbounds$(EXE) \
-	testdisplayinfo$(EXE) \
 	testerror$(EXE) \
 	testevdev$(EXE) \
 	testfilesystem$(EXE) \
@@ -401,12 +395,23 @@ TESTS = \
 	testplatform$(EXE) \
 	testpower$(EXE) \
 	testqsort$(EXE) \
-	testsurround$(EXE) \
 	testthread$(EXE) \
 	testtimer$(EXE) \
 	testver$(EXE) \
 	$(NULL)
 
+needs_audio = \
+	testaudioinfo$(EXE) \
+	testsurround$(EXE) \
+	$(NULL)
+
+needs_display = \
+	testbounds$(EXE) \
+	testdisplayinfo$(EXE) \
+	$(NULL)
+
+TESTS = $(noninteractive) $(needs_audio) $(needs_display)
+
 check:
 	@set -e; \
 	status=0; \
diff --git a/libs/SDL2/test/acinclude.m4 b/libs/SDL2/test/acinclude.m4
index ebee8238ab63e78847963d6d9e7225510cb3cd7e..0fdf353ea29a56e196bfd3340ebb6a9ab1491259 100644
--- a/libs/SDL2/test/acinclude.m4
+++ b/libs/SDL2/test/acinclude.m4
@@ -5,6 +5,8 @@
 # stolen from Manish Singh
 # Shamelessly stolen from Owen Taylor
 
+# serial 2
+
 dnl AM_PATH_SDL2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
 dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
 dnl
@@ -43,7 +45,7 @@ AC_ARG_ENABLE(sdltest, [  --disable-sdltest       Do not try to compile and run
 
   if test "x$sdl_pc" = xyes ; then
     no_sdl=""
-    SDL2_CONFIG="$PKG_CONFIG sdl2"
+    SDL2_CONFIG="pkg-config sdl2"
   else
     as_save_PATH="$PATH"
     if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then
diff --git a/libs/SDL2/test/checkkeys.c b/libs/SDL2/test/checkkeys.c
index f546900c5079422e7515e4d0a1f8a49986021321..4efdc721e1a0928299bf0d7dfc26f56c8d01cbfb 100644
--- a/libs/SDL2/test/checkkeys.c
+++ b/libs/SDL2/test/checkkeys.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -269,14 +269,14 @@ int main(int argc, char *argv[])
     window = SDL_CreateWindow("CheckKeys Test",
                               SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                               640, 480, 0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create 640x480 window: %s\n",
                      SDL_GetError());
         quit(2);
     }
 
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n",
                      SDL_GetError());
         quit(2);
@@ -284,7 +284,7 @@ int main(int argc, char *argv[])
 
     textwin = SDLTest_TextWindowCreate(0, 0, 640, 480);
 
-#ifdef __IPHONEOS__
+#if __IPHONEOS__
     /* Creating the context creates the view, which we need to show keyboard */
     SDL_GL_CreateContext(window);
 #endif
diff --git a/libs/SDL2/test/checkkeysthreads.c b/libs/SDL2/test/checkkeysthreads.c
index efd654875f935d6e5465444ce4af9b0400d9a6b8..3db5dd2dc7a2b27455faa1e46e30dfd4182c867a 100644
--- a/libs/SDL2/test/checkkeysthreads.c
+++ b/libs/SDL2/test/checkkeysthreads.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -254,7 +254,7 @@ int main(int argc, char *argv[])
     window = SDL_CreateWindow("CheckKeys Test",
                               SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                               640, 480, 0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create 640x480 window: %s\n",
                      SDL_GetError());
         quit(2);
@@ -266,7 +266,7 @@ int main(int argc, char *argv[])
     renderer = SDL_CreateRenderer(window, -1, 0);
     SDL_RenderPresent(renderer);
 
-#ifdef __IPHONEOS__
+#if __IPHONEOS__
     /* Creating the context creates the view, which we need to show keyboard */
     SDL_GL_CreateContext(window);
 #endif
diff --git a/libs/SDL2/test/configure b/libs/SDL2/test/configure
index 8ea80bc27ea2d4150880e42d505f24c77cfa6c0c..c71abe48977ffe5ff68d0b8c6f0cc82fb836aa69 100755
--- a/libs/SDL2/test/configure
+++ b/libs/SDL2/test/configure
@@ -3966,7 +3966,7 @@ fi
 
   if test "x$sdl_pc" = xyes ; then
     no_sdl=""
-    SDL2_CONFIG="$PKG_CONFIG sdl2"
+    SDL2_CONFIG="pkg-config sdl2"
   else
     as_save_PATH="$PATH"
     if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then
diff --git a/libs/SDL2/test/controllermap.c b/libs/SDL2/test/controllermap.c
index 982a9fb6fd9c562f59060f099a03b327fca4161a..cfb0effaced81512761061bbf918bfa57d0d8636 100644
--- a/libs/SDL2/test/controllermap.c
+++ b/libs/SDL2/test/controllermap.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -288,8 +288,7 @@ ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding)
         SDL_Log("Configuring button binding for button %d\n", pBinding->value.button);
         break;
     case SDL_CONTROLLER_BINDTYPE_AXIS:
-        SDL_Log("Configuring axis binding for axis %d %d/%d committed = %s\n", pBinding->value.axis.axis, pBinding->value.axis.axis_min, pBinding->value.axis.axis_max,
-                pBinding->committed ? "true" : "false");
+        SDL_Log("Configuring axis binding for axis %d %d/%d committed = %s\n", pBinding->value.axis.axis, pBinding->value.axis.axis_min, pBinding->value.axis.axis_max, pBinding->committed ? "true" : "false");
         break;
     case SDL_CONTROLLER_BINDTYPE_HAT:
         SDL_Log("Configuring hat binding for hat %d %d\n", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
@@ -730,13 +729,13 @@ int main(int argc, char *argv[])
     window = SDL_CreateWindow("Game Controller Map", SDL_WINDOWPOS_CENTERED,
                               SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
                               SCREEN_HEIGHT, 0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
         return 2;
     }
 
     screen = SDL_CreateRenderer(window, -1, 0);
-    if (!screen) {
+    if (screen == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
         return 2;
     }
@@ -767,7 +766,7 @@ int main(int argc, char *argv[])
         name = SDL_JoystickNameForIndex(i);
         SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
         joystick = SDL_JoystickOpen(i);
-        if (!joystick) {
+        if (joystick == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
                          SDL_GetError());
         } else {
@@ -793,7 +792,7 @@ int main(int argc, char *argv[])
         }
     }
     joystick = SDL_JoystickOpen(joystick_index);
-    if (!joystick) {
+    if (joystick == NULL) {
         SDL_Log("Couldn't open joystick %d: %s\n", joystick_index, SDL_GetError());
     } else {
         WatchJoystick(joystick);
diff --git a/libs/SDL2/test/loopwave.c b/libs/SDL2/test/loopwave.c
index 15f13658c5ea09759f86bca41a3d768129c3829c..156767c20fabc335f0cd54b450cf0eedcf70f7f2 100644
--- a/libs/SDL2/test/loopwave.c
+++ b/libs/SDL2/test/loopwave.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -127,7 +127,7 @@ int main(int argc, char *argv[])
 
     filename = GetResourceFilename(argc > 1 ? argv[1] : NULL, "sample.wav");
 
-    if (!filename) {
+    if (filename == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError());
         quit(1);
     }
diff --git a/libs/SDL2/test/loopwavequeue.c b/libs/SDL2/test/loopwavequeue.c
index 01b6ece3e39c3e9921d99054c521fbe4603ed4e2..70dd072d29ec2f8a7aee1c7efe0d43b9c6a34206 100644
--- a/libs/SDL2/test/loopwavequeue.c
+++ b/libs/SDL2/test/loopwavequeue.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -21,7 +21,7 @@
 
 #include "SDL.h"
 
-#ifdef HAVE_SIGNAL_H
+#if HAVE_SIGNAL_H
 #include <signal.h>
 #endif
 
@@ -84,7 +84,7 @@ int main(int argc, char *argv[])
 
     filename = GetResourceFilename(argc > 1 ? argv[1] : NULL, "sample.wav");
 
-    if (!filename) {
+    if (filename == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError());
         quit(1);
     }
@@ -97,7 +97,7 @@ int main(int argc, char *argv[])
 
     wave.spec.callback = NULL; /* we'll push audio. */
 
-#ifdef HAVE_SIGNAL_H
+#if HAVE_SIGNAL_H
     /* Set the signals */
 #ifdef SIGHUP
     (void)signal(SIGHUP, poked);
diff --git a/libs/SDL2/test/testatomic.c b/libs/SDL2/test/testatomic.c
index 1a599101ec339e7a06d9fd6508449c42750a9f9f..15a7a6a7d94ca86fdf7d4430aadabf16b9cfc055 100644
--- a/libs/SDL2/test/testatomic.c
+++ b/libs/SDL2/test/testatomic.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -234,8 +234,7 @@ static void RunEpicTest()
     v = SDL_AtomicGet(&good);
     SDL_Log("Atomic %d Non-Atomic %d\n", v, bad);
     SDL_assert(v == Expect);
-    /* We can't guarantee that bad != Expect, this would happen on a single core system, for example. */
-    /*SDL_assert(bad != Expect);*/
+    SDL_assert(bad != Expect);
 }
 
 /* End atomic operation test */
diff --git a/libs/SDL2/test/testaudiocapture.c b/libs/SDL2/test/testaudiocapture.c
index 523385b3ae48472a256727bc9adf94ce5f7d48dc..a8fdf5ec5ca300c5dfd8c63d95d89cf7ef05b588 100644
--- a/libs/SDL2/test/testaudiocapture.c
+++ b/libs/SDL2/test/testaudiocapture.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testaudiohotplug.c b/libs/SDL2/test/testaudiohotplug.c
index 354d4644f3c0e14e9113c62ea1dd2736b18002ed..e4bd9ac096f6c679c07a81cde0aeb93b3c1c9b80 100644
--- a/libs/SDL2/test/testaudiohotplug.c
+++ b/libs/SDL2/test/testaudiohotplug.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -17,7 +17,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#ifdef HAVE_SIGNAL_H
+#if HAVE_SIGNAL_H
 #include <signal.h>
 #endif
 
@@ -96,7 +96,7 @@ iteration()
             int index = e.adevice.which;
             int iscapture = e.adevice.iscapture;
             const char *name = SDL_GetAudioDeviceName(index, iscapture);
-            if (name) {
+            if (name != NULL) {
                 SDL_Log("New %s audio device at index %u: %s\n", devtypestr(iscapture), (unsigned int)index, name);
             } else {
                 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Got new %s device at index %u, but failed to get the name: %s\n",
@@ -152,7 +152,7 @@ int main(int argc, char *argv[])
 
     filename = GetResourceFilename(argc > 1 ? argv[1] : NULL, "sample.wav");
 
-    if (!filename) {
+    if (filename == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError());
         quit(1);
     }
@@ -163,7 +163,7 @@ int main(int argc, char *argv[])
         quit(1);
     }
 
-#ifdef HAVE_SIGNAL_H
+#if HAVE_SIGNAL_H
     /* Set the signals */
 #ifdef SIGHUP
     (void)signal(SIGHUP, poked);
diff --git a/libs/SDL2/test/testaudioinfo.c b/libs/SDL2/test/testaudioinfo.c
index ec4b86470d707bb46305a6807545d58aa5ba500b..ae59cbcc8611302408a4676681099e7990a10f4f 100644
--- a/libs/SDL2/test/testaudioinfo.c
+++ b/libs/SDL2/test/testaudioinfo.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -29,7 +29,7 @@ print_devices(int iscapture)
         int i;
         for (i = 0; i < n; i++) {
             const char *name = SDL_GetAudioDeviceName(i, iscapture);
-            if (name) {
+            if (name != NULL) {
                 SDL_Log("  %d: %s\n", i, name);
             } else {
                 SDL_Log("  %d Error: %s\n", i, SDL_GetError());
@@ -81,7 +81,7 @@ int main(int argc, char **argv)
     if (SDL_GetDefaultAudioInfo(&deviceName, &spec, 0) < 0) {
         SDL_Log("Error when calling SDL_GetDefaultAudioInfo: %s\n", SDL_GetError());
     } else {
-        SDL_Log("Default Output Name: %s\n", deviceName ? deviceName : "unknown");
+        SDL_Log("Default Output Name: %s\n", deviceName != NULL ? deviceName : "unknown");
         SDL_free(deviceName);
         SDL_Log("Sample Rate: %d\n", spec.freq);
         SDL_Log("Channels: %d\n", spec.channels);
@@ -91,7 +91,7 @@ int main(int argc, char **argv)
     if (SDL_GetDefaultAudioInfo(&deviceName, &spec, 1) < 0) {
         SDL_Log("Error when calling SDL_GetDefaultAudioInfo: %s\n", SDL_GetError());
     } else {
-        SDL_Log("Default Capture Name: %s\n", deviceName ? deviceName : "unknown");
+        SDL_Log("Default Capture Name: %s\n", deviceName != NULL ? deviceName : "unknown");
         SDL_free(deviceName);
         SDL_Log("Sample Rate: %d\n", spec.freq);
         SDL_Log("Channels: %d\n", spec.channels);
diff --git a/libs/SDL2/test/testautomation.c b/libs/SDL2/test/testautomation.c
index 3b5fad808ac8794e00dc0fd0f70c114885f66496..2150ed246be139f2f5740ea73f5aec07442d56ef 100644
--- a/libs/SDL2/test/testautomation.c
+++ b/libs/SDL2/test/testautomation.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -41,7 +41,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testautomation_audio.c b/libs/SDL2/test/testautomation_audio.c
index 16ab753e9787d320c9d6e49fb38fa78e4107bdd6..bd586314f9543b23a845239d71fde76e49a4bd51 100644
--- a/libs/SDL2/test/testautomation_audio.c
+++ b/libs/SDL2/test/testautomation_audio.c
@@ -52,42 +52,6 @@ void SDLCALL _audio_testCallback(void *userdata, Uint8 *stream, int len)
     _audio_testCallbackLength += len;
 }
 
-#if defined(__linux__)
-/* Linux builds can include many audio drivers, but some are very
- * obscure and typically unsupported on modern systems. They will
- * be skipped in tests that run against all included drivers, as
- * they are basically guaranteed to fail.
- */
-static SDL_bool DriverIsProblematic(const char *driver)
-{
-    static const char *driverList[] = {
-        /* Omnipresent in Linux builds, but deprecated since 2002,
-        * very rarely used on Linux nowadays, and is almost certainly
-        * guaranteed to fail.
-         */
-        "dsp",
-
-        /* OpenBSD sound API. Can be used on Linux, but very rare. */
-        "sndio",
-
-        /* Always fails on initialization and/or opening a device.
-         * Does anyone or anything actually use this?
-         */
-        "nas"
-    };
-
-    int i;
-
-    for (i = 0; i < SDL_arraysize(driverList); ++i) {
-        if (SDL_strcmp(driver, driverList[i]) == 0) {
-            return SDL_TRUE;
-        }
-    }
-
-    return SDL_FALSE;
-}
-#endif
-
 /* Test case functions */
 
 /**
@@ -119,43 +83,20 @@ int audio_initQuitAudio()
     int result;
     int i, iMax;
     const char *audioDriver;
-    const char *hint = SDL_GetHint(SDL_HINT_AUDIODRIVER);
 
     /* Stop SDL audio subsystem */
     SDL_QuitSubSystem(SDL_INIT_AUDIO);
     SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
 
-    /* Was a specific driver requested? */
-    audioDriver = SDL_GetHint(SDL_HINT_AUDIODRIVER);
-
-    if (audioDriver == NULL) {
-        /* Loop over all available audio drivers */
-        iMax = SDL_GetNumAudioDrivers();
-        SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
-        SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
-    } else {
-        /* A specific driver was requested for testing */
-        iMax = 1;
-    }
+    /* Loop over all available audio drivers */
+    iMax = SDL_GetNumAudioDrivers();
+    SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
+    SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
     for (i = 0; i < iMax; i++) {
-        if (audioDriver == NULL) {
-            audioDriver = SDL_GetAudioDriver(i);
-            SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
-            SDLTest_Assert(audioDriver != NULL, "Audio driver name is not NULL");
-            SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver); /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
-
-#if defined(__linux__)
-            if (DriverIsProblematic(audioDriver)) {
-                SDLTest_Log("Audio driver '%s' flagged as problematic: skipping init/quit test (set SDL_AUDIODRIVER=%s to force)", audioDriver, audioDriver);
-                audioDriver = NULL;
-                continue;
-            }
-#endif
-        }
-
-        if (hint && SDL_strcmp(audioDriver, hint) != 0) {
-            continue;
-        }
+        audioDriver = SDL_GetAudioDriver(i);
+        SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
+        SDLTest_Assert(audioDriver != NULL, "Audio driver name is not NULL");
+        SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver); /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
 
         /* Call Init */
         result = SDL_AudioInit(audioDriver);
@@ -165,8 +106,6 @@ int audio_initQuitAudio()
         /* Call Quit */
         SDL_AudioQuit();
         SDLTest_AssertPass("Call to SDL_AudioQuit()");
-
-        audioDriver = NULL;
     }
 
     /* NULL driver specification */
@@ -201,43 +140,20 @@ int audio_initOpenCloseQuitAudio()
     int i, iMax, j, k;
     const char *audioDriver;
     SDL_AudioSpec desired;
-    const char *hint = SDL_GetHint(SDL_HINT_AUDIODRIVER);
 
     /* Stop SDL audio subsystem */
     SDL_QuitSubSystem(SDL_INIT_AUDIO);
     SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
 
-    /* Was a specific driver requested? */
-    audioDriver = SDL_GetHint(SDL_HINT_AUDIODRIVER);
-
-    if (audioDriver == NULL) {
-        /* Loop over all available audio drivers */
-        iMax = SDL_GetNumAudioDrivers();
-        SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
-        SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
-    } else {
-        /* A specific driver was requested for testing */
-        iMax = 1;
-    }
+    /* Loop over all available audio drivers */
+    iMax = SDL_GetNumAudioDrivers();
+    SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
+    SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
     for (i = 0; i < iMax; i++) {
-        if (audioDriver == NULL) {
-            audioDriver = SDL_GetAudioDriver(i);
-            SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
-            SDLTest_Assert(audioDriver != NULL, "Audio driver name is not NULL");
-            SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver); /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
-
-#if defined(__linux__)
-            if (DriverIsProblematic(audioDriver)) {
-                SDLTest_Log("Audio driver '%s' flagged as problematic: skipping device open/close test (set SDL_AUDIODRIVER=%s to force)", audioDriver, audioDriver);
-                audioDriver = NULL;
-                continue;
-            }
-#endif
-        }
-
-        if (hint && SDL_strcmp(audioDriver, hint) != 0) {
-            continue;
-        }
+        audioDriver = SDL_GetAudioDriver(i);
+        SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
+        SDLTest_Assert(audioDriver != NULL, "Audio driver name is not NULL");
+        SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver); /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
 
         /* Change specs */
         for (j = 0; j < 2; j++) {
@@ -247,17 +163,6 @@ int audio_initOpenCloseQuitAudio()
             SDLTest_AssertPass("Call to SDL_AudioInit('%s')", audioDriver);
             SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0 got: %d", result);
 
-            /* Check for output devices */
-            result = SDL_GetNumAudioDevices(SDL_FALSE);
-            SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(SDL_FALSE)");
-            SDLTest_AssertCheck(result >= 0, "Validate result value; expected: >=0 got: %d", result);
-            if (result <= 0) {
-                SDLTest_Log("No output devices for '%s': skipping device open/close test", audioDriver);
-                SDL_AudioQuit();
-                SDLTest_AssertPass("Call to SDL_AudioQuit()");
-                break;
-            }
-
             /* Set spec */
             SDL_memset(&desired, 0, sizeof(desired));
             switch (j) {
@@ -302,10 +207,7 @@ int audio_initOpenCloseQuitAudio()
             }
 
         } /* spec loop */
-
-        audioDriver = NULL;
-
-    } /* driver loop */
+    }     /* driver loop */
 
     /* Restart audio again */
     _audioSetUp(NULL);
@@ -327,43 +229,20 @@ int audio_pauseUnpauseAudio()
     int originalCounter;
     const char *audioDriver;
     SDL_AudioSpec desired;
-    const char *hint = SDL_GetHint(SDL_HINT_AUDIODRIVER);
 
     /* Stop SDL audio subsystem */
     SDL_QuitSubSystem(SDL_INIT_AUDIO);
     SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
 
-    /* Was a specific driver requested? */
-    audioDriver = SDL_GetHint(SDL_HINT_AUDIODRIVER);
-
-    if (audioDriver == NULL) {
-        /* Loop over all available audio drivers */
-        iMax = SDL_GetNumAudioDrivers();
-        SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
-        SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
-    } else {
-        /* A specific driver was requested for testing */
-        iMax = 1;
-    }
+    /* Loop over all available audio drivers */
+    iMax = SDL_GetNumAudioDrivers();
+    SDLTest_AssertPass("Call to SDL_GetNumAudioDrivers()");
+    SDLTest_AssertCheck(iMax > 0, "Validate number of audio drivers; expected: >0 got: %d", iMax);
     for (i = 0; i < iMax; i++) {
-        if (audioDriver == NULL) {
-            audioDriver = SDL_GetAudioDriver(i);
-            SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
-            SDLTest_Assert(audioDriver != NULL, "Audio driver name is not NULL");
-            SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver); /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
-
-#if defined(__linux__)
-            if (DriverIsProblematic(audioDriver)) {
-                SDLTest_Log("Audio driver '%s' flagged as problematic: skipping pause/unpause test (set SDL_AUDIODRIVER=%s to force)", audioDriver, audioDriver);
-                audioDriver = NULL;
-                continue;
-            }
-#endif
-        }
-
-        if (hint && SDL_strcmp(audioDriver, hint) != 0) {
-            continue;
-        }
+        audioDriver = SDL_GetAudioDriver(i);
+        SDLTest_AssertPass("Call to SDL_GetAudioDriver(%d)", i);
+        SDLTest_Assert(audioDriver != NULL, "Audio driver name is not NULL");
+        SDLTest_AssertCheck(audioDriver[0] != '\0', "Audio driver name is not empty; got: %s", audioDriver); /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
 
         /* Change specs */
         for (j = 0; j < 2; j++) {
@@ -373,16 +252,6 @@ int audio_pauseUnpauseAudio()
             SDLTest_AssertPass("Call to SDL_AudioInit('%s')", audioDriver);
             SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0 got: %d", result);
 
-            result = SDL_GetNumAudioDevices(SDL_FALSE);
-            SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(SDL_FALSE)");
-            SDLTest_AssertCheck(result >= 0, "Validate result value; expected: >=0 got: %d", result);
-            if (result <= 0) {
-                SDLTest_Log("No output devices for '%s': skipping pause/unpause test", audioDriver);
-                SDL_AudioQuit();
-                SDLTest_AssertPass("Call to SDL_AudioQuit()");
-                break;
-            }
-
             /* Set spec */
             SDL_memset(&desired, 0, sizeof(desired));
             switch (j) {
@@ -457,10 +326,7 @@ int audio_pauseUnpauseAudio()
             SDLTest_AssertPass("Call to SDL_AudioQuit()");
 
         } /* spec loop */
-
-        audioDriver = NULL;
-
-    } /* driver loop */
+    }     /* driver loop */
 
     /* Restart audio again */
     _audioSetUp(NULL);
@@ -1159,8 +1025,8 @@ int audio_resampleLoss()
     SDLTest_AssertPass("Test resampling of %i s %i Hz %f phase sine wave from sampling rate of %i Hz to %i Hz",
                        spec->time, spec->freq, spec->phase, spec->rate_in, spec->rate_out);
 
-    ret = SDL_BuildAudioCVT(&cvt, AUDIO_F32SYS, 1, spec->rate_in, AUDIO_F32SYS, 1, spec->rate_out);
-    SDLTest_AssertPass("Call to SDL_BuildAudioCVT(&cvt, AUDIO_F32SYS, 1, %i, AUDIO_F32SYS, 1, %i)", spec->rate_in, spec->rate_out);
+    ret = SDL_BuildAudioCVT(&cvt, AUDIO_F32, 1, spec->rate_in, AUDIO_F32, 1, spec->rate_out);
+    SDLTest_AssertPass("Call to SDL_BuildAudioCVT(&cvt, AUDIO_F32, 1, %i, AUDIO_F32, 1, %i)", spec->rate_in, spec->rate_out);
     SDLTest_AssertCheck(ret == 1, "Expected SDL_BuildAudioCVT to succeed and conversion to be needed.");
     if (ret != 1) {
       return TEST_ABORTED;
diff --git a/libs/SDL2/test/testautomation_clipboard.c b/libs/SDL2/test/testautomation_clipboard.c
index ce8ea1bd3da8b68c43bb5131ef21df588b9c1adc..dbe1ef8e4007293f633b38f9048714eb8d8e943d 100644
--- a/libs/SDL2/test/testautomation_clipboard.c
+++ b/libs/SDL2/test/testautomation_clipboard.c
@@ -84,7 +84,7 @@ int clipboard_testSetClipboardText(void *arg)
     char *textRef = SDLTest_RandomAsciiString();
     char *text = SDL_strdup(textRef);
     int result;
-    result = SDL_SetClipboardText(text);
+    result = SDL_SetClipboardText((const char *)text);
     SDLTest_AssertPass("Call to SDL_SetClipboardText succeeded");
     SDLTest_AssertCheck(
         result == 0,
@@ -112,7 +112,7 @@ int clipboard_testSetPrimarySelectionText(void *arg)
     char *textRef = SDLTest_RandomAsciiString();
     char *text = SDL_strdup(textRef);
     int result;
-    result = SDL_SetPrimarySelectionText(text);
+    result = SDL_SetPrimarySelectionText((const char *)text);
     SDLTest_AssertPass("Call to SDL_SetPrimarySelectionText succeeded");
     SDLTest_AssertCheck(
         result == 0,
@@ -149,7 +149,7 @@ int clipboard_testClipboardTextFunctions(void *arg)
     boolResult = SDL_HasClipboardText();
     SDLTest_AssertPass("Call to SDL_HasClipboardText succeeded");
     if (boolResult == SDL_TRUE) {
-        intResult = SDL_SetClipboardText(NULL);
+        intResult = SDL_SetClipboardText((const char *)NULL);
         SDLTest_AssertPass("Call to SDL_SetClipboardText(NULL) succeeded");
         SDLTest_AssertCheck(
             intResult == 0,
@@ -176,7 +176,7 @@ int clipboard_testClipboardTextFunctions(void *arg)
         charResult[0] == '\0', /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
         "Verify SDL_GetClipboardText returned string with length 0, got length %i",
         (int)SDL_strlen(charResult));
-    intResult = SDL_SetClipboardText(text);
+    intResult = SDL_SetClipboardText((const char *)text);
     SDLTest_AssertPass("Call to SDL_SetClipboardText succeeded");
     SDLTest_AssertCheck(
         intResult == 0,
@@ -227,7 +227,7 @@ int clipboard_testPrimarySelectionTextFunctions(void *arg)
     boolResult = SDL_HasPrimarySelectionText();
     SDLTest_AssertPass("Call to SDL_HasPrimarySelectionText succeeded");
     if (boolResult == SDL_TRUE) {
-        intResult = SDL_SetPrimarySelectionText(NULL);
+        intResult = SDL_SetPrimarySelectionText((const char *)NULL);
         SDLTest_AssertPass("Call to SDL_SetPrimarySelectionText(NULL) succeeded");
         SDLTest_AssertCheck(
             intResult == 0,
@@ -254,7 +254,7 @@ int clipboard_testPrimarySelectionTextFunctions(void *arg)
         charResult[0] == '\0', /* NOLINT(clang-analyzer-core.NullDereference): Checked for NULL above */
         "Verify SDL_GetPrimarySelectionText returned string with length 0, got length %i",
         (int)SDL_strlen(charResult));
-    intResult = SDL_SetPrimarySelectionText(text);
+    intResult = SDL_SetPrimarySelectionText((const char *)text);
     SDLTest_AssertPass("Call to SDL_SetPrimarySelectionText succeeded");
     SDLTest_AssertCheck(
         intResult == 0,
diff --git a/libs/SDL2/test/testautomation_events.c b/libs/SDL2/test/testautomation_events.c
index d4babdafcefeefc4692dc7b5d155f18ad0f4368e..6d0f3ff533789aa55415ecd125f051c951ec38e8 100644
--- a/libs/SDL2/test/testautomation_events.c
+++ b/libs/SDL2/test/testautomation_events.c
@@ -68,10 +68,6 @@ int events_pushPumpAndPollUserevent(void *arg)
     SDLTest_AssertPass("Call to SDL_PollEvent()");
     SDLTest_AssertCheck(result == 1, "Check result from SDL_PollEvent, expected: 1, got: %d", result);
 
-    /* Need to finish getting all events and sentinel, otherwise other tests that rely on event are in bad state */
-    while (SDL_PollEvent(&event2)) {
-    }
-
     return TEST_COMPLETED;
 }
 
diff --git a/libs/SDL2/test/testautomation_guid.c b/libs/SDL2/test/testautomation_guid.c
index 81e60e8f4ba9f9baaa87234f8a663877866b7d2c..cf99dea8139a8e6f7d84703f4e08e2d8abd74f9f 100644
--- a/libs/SDL2/test/testautomation_guid.c
+++ b/libs/SDL2/test/testautomation_guid.c
@@ -125,7 +125,7 @@ TestGuidToString(void *arg)
             SDL_GUIDToString(guid, guid_str, size);
 
             /* Check bytes before guid_str_buf */
-            expected_prefix = fill_char | (fill_char << 8) | (fill_char << 16) | (((Uint32)fill_char) << 24);
+            expected_prefix = fill_char | (fill_char << 8) | (fill_char << 16) | (fill_char << 24);
             SDL_memcpy(&actual_prefix, guid_str_buf, 4);
             SDLTest_AssertCheck(expected_prefix == actual_prefix, "String buffer memory before output untouched, expected: %" SDL_PRIu32 ", got: %" SDL_PRIu32 ", at size=%d", expected_prefix, actual_prefix, size);
 
diff --git a/libs/SDL2/test/testautomation_keyboard.c b/libs/SDL2/test/testautomation_keyboard.c
index 5ed9207bca5f685aca864e8093dd9bc553eeab29..0d459d0b2dd1c9d7e7fa91abfca5668c2fb9bfe7 100644
--- a/libs/SDL2/test/testautomation_keyboard.c
+++ b/libs/SDL2/test/testautomation_keyboard.c
@@ -463,34 +463,32 @@ int keyboard_setTextInputRect(void *arg)
  */
 int keyboard_setTextInputRectNegative(void *arg)
 {
-    int platform_sets_error_message = SDL_strcmp(SDL_GetCurrentVideoDriver(), "windows") == 0 ||
-                                      SDL_strcmp(SDL_GetCurrentVideoDriver(), "android") == 0 ||
-                                      SDL_strcmp(SDL_GetCurrentVideoDriver(), "cococa") == 0;
     /* Some platforms set also an error message; prepare for checking it */
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_COCOA
     const char *expectedError = "Parameter 'rect' is invalid";
     const char *error;
 
     SDL_ClearError();
     SDLTest_AssertPass("Call to SDL_ClearError()");
+#endif
 
     /* NULL refRect */
     SDL_SetTextInputRect(NULL);
     SDLTest_AssertPass("Call to SDL_SetTextInputRect(NULL)");
 
     /* Some platforms set also an error message; so check it */
-
-    if (platform_sets_error_message) {
-        error = SDL_GetError();
-        SDLTest_AssertPass("Call to SDL_GetError()");
-        SDLTest_AssertCheck(error != NULL, "Validate that error message was not NULL");
-        if (error != NULL) {
-            SDLTest_AssertCheck(SDL_strcmp(error, expectedError) == 0,
-                                "Validate error message, expected: '%s', got: '%s'", expectedError, error);
-        }
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_COCOA
+    error = SDL_GetError();
+    SDLTest_AssertPass("Call to SDL_GetError()");
+    SDLTest_AssertCheck(error != NULL, "Validate that error message was not NULL");
+    if (error != NULL) {
+        SDLTest_AssertCheck(SDL_strcmp(error, expectedError) == 0,
+                            "Validate error message, expected: '%s', got: '%s'", expectedError, error);
     }
 
     SDL_ClearError();
     SDLTest_AssertPass("Call to SDL_ClearError()");
+#endif
 
     return TEST_COMPLETED;
 }
diff --git a/libs/SDL2/test/testautomation_log.c b/libs/SDL2/test/testautomation_log.c
deleted file mode 100644
index 4edb487ea31028e86391c14ad5cd0e6927c4bfc0..0000000000000000000000000000000000000000
--- a/libs/SDL2/test/testautomation_log.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/**
- * Log test suite
- */
-#include "SDL.h"
-#include "SDL_test.h"
-
-
-static SDL_LogOutputFunction original_function;
-static void *original_userdata;
-
-static void SDLCALL TestLogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message)
-{
-    int *message_count = (int *)userdata;
-    ++(*message_count);
-}
-
-static void EnableTestLog(int *message_count)
-{
-    *message_count = 0;
-    SDL_LogGetOutputFunction(&original_function, &original_userdata);
-    SDL_LogSetOutputFunction(TestLogOutput, message_count);
-}
-
-static void DisableTestLog()
-{
-    SDL_LogSetOutputFunction(original_function, original_userdata);
-}
-
-/* Fixture */
-
-/* Test case functions */
-
-/**
- * Check SDL_HINT_LOGGING functionality
- */
-static int log_testHint(void *arg)
-{
-    int count;
-
-    SDL_SetHint(SDL_HINT_LOGGING, NULL);
-    SDLTest_AssertPass("SDL_SetHint(SDL_HINT_LOGGING, NULL)");
-    {
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-    }
-
-    SDL_SetHint(SDL_HINT_LOGGING, "debug");
-    SDLTest_AssertPass("SDL_SetHint(SDL_HINT_LOGGING, \"debug\")");
-    {
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-    }
-
-    SDL_SetHint(SDL_HINT_LOGGING, "system=debug");
-    SDLTest_AssertPass("SDL_SetHint(SDL_HINT_LOGGING, \"system=debug\")");
-    {
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-    }
-
-    SDL_SetHint(SDL_HINT_LOGGING, "app=warn,system=debug,assert=quiet,*=info");
-    SDLTest_AssertPass("SDL_SetHint(SDL_HINT_LOGGING, \"app=warn,system=debug,assert=quiet,*=info\")");
-    {
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_CRITICAL, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_CRITICAL, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_INFO, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_INFO, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-    }
-
-    SDL_SetHint(SDL_HINT_LOGGING, "0=4,3=2,2=0,*=3");
-    SDLTest_AssertPass("SDL_SetHint(SDL_HINT_LOGGING, \"0=4,3=2,2=0,*=3\")");
-    {
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_SYSTEM, SDL_LOG_PRIORITY_VERBOSE, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_CRITICAL, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_CRITICAL, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_INFO, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_INFO, \"test\")");
-        SDLTest_AssertCheck(count == 1, "Check result value, expected: 1, got: %d", count);
-
-        EnableTestLog(&count);
-        SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_DEBUG, "test");
-        DisableTestLog();
-        SDLTest_AssertPass("SDL_LogMessage(SDL_LOG_CATEGORY_CUSTOM, SDL_LOG_PRIORITY_DEBUG, \"test\")");
-        SDLTest_AssertCheck(count == 0, "Check result value, expected: 0, got: %d", count);
-
-    }
-
-    return TEST_COMPLETED;
-}
-
-/* ================= Test References ================== */
-
-/* Log test cases */
-static const SDLTest_TestCaseReference logTestHint = {
-    (SDLTest_TestCaseFp)log_testHint, "log_testHint", "Check SDL_HINT_LOGGING functionality", TEST_ENABLED
-};
-
-/* Sequence of Log test cases */
-static const SDLTest_TestCaseReference *logTests[] = {
-    &logTestHint, NULL
-};
-
-/* Timer test suite (global) */
-SDLTest_TestSuiteReference logTestSuite = {
-    "Log",
-    NULL,
-    logTests,
-    NULL
-};
diff --git a/libs/SDL2/test/testautomation_main.c b/libs/SDL2/test/testautomation_main.c
index 78572d1a432c8e5ede6da0b600eaf82b1d9e4c94..ed72e0d950b6cef988091f12083ca4468d5fbcbe 100644
--- a/libs/SDL2/test/testautomation_main.c
+++ b/libs/SDL2/test/testautomation_main.c
@@ -9,6 +9,34 @@
 #include "SDL.h"
 #include "SDL_test.h"
 
+/* !
+ * \brief Tests SDL_Init() and SDL_Quit() of Joystick and Haptic subsystems
+ * \sa
+ * http://wiki.libsdl.org/SDL_Init
+ * http://wiki.libsdl.org/SDL_Quit
+ */
+static int main_testInitQuitJoystickHaptic(void *arg)
+{
+#if defined SDL_JOYSTICK_DISABLED || defined SDL_HAPTIC_DISABLED
+    return TEST_SKIPPED;
+#else
+    int enabled_subsystems;
+    int initialized_subsystems = SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC;
+
+    SDLTest_AssertCheck(SDL_Init(initialized_subsystems) == 0, "SDL_Init multiple systems.");
+
+    enabled_subsystems = SDL_WasInit(initialized_subsystems);
+    SDLTest_AssertCheck(enabled_subsystems == initialized_subsystems, "SDL_WasInit(SDL_INIT_EVERYTHING) contains all systems (%i)", enabled_subsystems);
+
+    SDL_Quit();
+
+    enabled_subsystems = SDL_WasInit(initialized_subsystems);
+    SDLTest_AssertCheck(enabled_subsystems == 0, "SDL_Quit should shut down everything (%i)", enabled_subsystems);
+
+    return TEST_COMPLETED;
+#endif
+}
+
 /* !
  * \brief Tests SDL_InitSubSystem() and SDL_QuitSubSystem()
  * \sa
@@ -126,18 +154,22 @@ main_testSetError(void *arg)
 #endif
 
 static const SDLTest_TestCaseReference mainTest1 = {
-    (SDLTest_TestCaseFp)main_testInitQuitSubSystem, "main_testInitQuitSubSystem", "Tests SDL_InitSubSystem/QuitSubSystem", TEST_ENABLED
+    (SDLTest_TestCaseFp)main_testInitQuitJoystickHaptic, "main_testInitQuitJoystickHaptic", "Tests SDL_Init/Quit of Joystick and Haptic subsystem", TEST_ENABLED
 };
 
 static const SDLTest_TestCaseReference mainTest2 = {
-    (SDLTest_TestCaseFp)main_testImpliedJoystickInit, "main_testImpliedJoystickInit", "Tests that init for gamecontroller properly implies joystick", TEST_ENABLED
+    (SDLTest_TestCaseFp)main_testInitQuitSubSystem, "main_testInitQuitSubSystem", "Tests SDL_InitSubSystem/QuitSubSystem", TEST_ENABLED
 };
 
 static const SDLTest_TestCaseReference mainTest3 = {
-    (SDLTest_TestCaseFp)main_testImpliedJoystickQuit, "main_testImpliedJoystickQuit", "Tests that quit for gamecontroller doesn't quit joystick if you inited it explicitly", TEST_ENABLED
+    (SDLTest_TestCaseFp)main_testImpliedJoystickInit, "main_testImpliedJoystickInit", "Tests that init for gamecontroller properly implies joystick", TEST_ENABLED
 };
 
 static const SDLTest_TestCaseReference mainTest4 = {
+    (SDLTest_TestCaseFp)main_testImpliedJoystickQuit, "main_testImpliedJoystickQuit", "Tests that quit for gamecontroller doesn't quit joystick if you inited it explicitly", TEST_ENABLED
+};
+
+static const SDLTest_TestCaseReference mainTest5 = {
     (SDLTest_TestCaseFp)main_testSetError, "main_testSetError", "Tests that SDL_SetError() handles arbitrarily large strings", TEST_ENABLED
 };
 
@@ -147,6 +179,7 @@ static const SDLTest_TestCaseReference *mainTests[] = {
     &mainTest2,
     &mainTest3,
     &mainTest4,
+    &mainTest5,
     NULL
 };
 
@@ -157,3 +190,5 @@ SDLTest_TestSuiteReference mainTestSuite = {
     mainTests,
     NULL
 };
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/test/testautomation_math.c b/libs/SDL2/test/testautomation_math.c
index ef9b40b3d32d1633720466e31b6f673151624688..87637c01db69bca39685c0d8543d3791cf4ca87f 100644
--- a/libs/SDL2/test/testautomation_math.c
+++ b/libs/SDL2/test/testautomation_math.c
@@ -49,12 +49,6 @@ typedef struct
     double expected;
 } dd_to_d;
 
-#define DD_TO_D_CASE(IDX, X, Y, E) do { \
-        cases[IDX].x_input = (X);       \
-        cases[IDX].y_input = (Y);       \
-        cases[IDX].expected = (E);      \
-    } while (0)
-
 /*
     NB: You cannot create an array of these structures containing INFINITY or NAN.
     On platforms such as OS/2, they are defined as 'extern const double' making them
@@ -70,10 +64,10 @@ typedef double(SDLCALL *dd_to_d_func)(double, double);
  * \brief Runs all the cases on a given function with a signature double -> double.
  * The result is expected to be exact.
  *
- * \param func_name a printable name for the tested function.
- * \param func the function to call.
- * \param cases an array of all the cases.
- * \param cases_size the size of the cases array.
+ * \param func_name, a printable name for the tested function.
+ * \param func, the function to call.
+ * \param cases, an array of all the cases.
+ * \param cases_size, the size of the cases array.
  */
 static int
 helper_dtod(const char *func_name, d_to_d_func func,
@@ -82,7 +76,7 @@ helper_dtod(const char *func_name, d_to_d_func func,
     Uint32 i;
     for (i = 0; i < cases_size; i++) {
         const double result = func(cases[i].input);
-        SDLTest_AssertCheck((result - cases[i].expected) < FLT_EPSILON,
+        SDLTest_AssertCheck(result == cases[i].expected,
                             "%s(%f), expected %f, got %f",
                             func_name,
                             cases[i].input,
@@ -96,10 +90,10 @@ helper_dtod(const char *func_name, d_to_d_func func,
  * \brief Runs all the cases on a given function with a signature double -> double.
  * Checks if the result between expected +/- EPSILON.
  *
- * \param func_name a printable name for the tested function.
- * \param func the function to call.
- * \param cases an array of all the cases.
- * \param cases_size the size of the cases array.
+ * \param func_name, a printable name for the tested function.
+ * \param func, the function to call.
+ * \param cases, an array of all the cases.
+ * \param cases_size, the size of the cases array.
  */
 static int
 helper_dtod_inexact(const char *func_name, d_to_d_func func,
@@ -108,15 +102,8 @@ helper_dtod_inexact(const char *func_name, d_to_d_func func,
     Uint32 i;
     for (i = 0; i < cases_size; i++) {
         const double result = func(cases[i].input);
-        double diff = result - cases[i].expected;
-        double max_err = (cases[i].expected + 1.) * EPSILON;
-        if (diff < 0) {
-            diff = -diff;
-        }
-        if (max_err < 0) {
-            max_err = -max_err;
-        }
-        SDLTest_AssertCheck(diff <= max_err,
+        SDLTest_AssertCheck(result >= cases[i].expected - EPSILON &&
+                                result <= cases[i].expected + EPSILON,
                             "%s(%f), expected [%f,%f], got %f",
                             func_name,
                             cases[i].input,
@@ -132,10 +119,10 @@ helper_dtod_inexact(const char *func_name, d_to_d_func func,
  * \brief Runs all the cases on a given function with a signature
  * (double, double) -> double. The result is expected to be exact.
  *
- * \param func_name a printable name for the tested function.
- * \param func the function to call.
- * \param cases an array of all the cases.
- * \param cases_size the size of the cases array.
+ * \param func_name, a printable name for the tested function.
+ * \param func, the function to call.
+ * \param cases, an array of all the cases.
+ * \param cases_size, the size of the cases array.
  */
 static int
 helper_ddtod(const char *func_name, dd_to_d_func func,
@@ -144,8 +131,6 @@ helper_ddtod(const char *func_name, dd_to_d_func func,
     Uint32 i;
     for (i = 0; i < cases_size; i++) {
         const double result = func(cases[i].x_input, cases[i].y_input);
-        /* By using the result as input, the compiler is less likely to use higher precision floating point number */
-        (void)SDL_sin(result);
         SDLTest_AssertCheck(result == cases[i].expected,
                             "%s(%f,%f), expected %f, got %f",
                             func_name,
@@ -160,10 +145,10 @@ helper_ddtod(const char *func_name, dd_to_d_func func,
  * \brief Runs all the cases on a given function with a signature
  * (double, double) -> double. Checks if the result between expected +/- EPSILON.
  *
- * \param func_name a printable name for the tested function.
- * \param func the function to call.
- * \param cases an array of all the cases.
- * \param cases_size the size of the cases array.
+ * \param func_name, a printable name for the tested function.
+ * \param func, the function to call.
+ * \param cases, an array of all the cases.
+ * \param cases_size, the size of the cases array.
  */
 static int
 helper_ddtod_inexact(const char *func_name, dd_to_d_func func,
@@ -172,16 +157,8 @@ helper_ddtod_inexact(const char *func_name, dd_to_d_func func,
     Uint32 i;
     for (i = 0; i < cases_size; i++) {
         const double result = func(cases[i].x_input, cases[i].y_input);
-        double diff = result - cases[i].expected;
-        double max_err = (cases[i].expected + 1.) * EPSILON;
-        if (diff < 0) {
-            diff = -diff;
-        }
-        if (max_err < 0) {
-            max_err = -max_err;
-        }
-
-        SDLTest_AssertCheck(diff <= max_err,
+        SDLTest_AssertCheck(result >= cases[i].expected - EPSILON &&
+                                result <= cases[i].expected + EPSILON,
                             "%s(%f,%f), expected [%f,%f], got %f",
                             func_name,
                             cases[i].x_input, cases[i].y_input,
@@ -199,8 +176,8 @@ helper_ddtod_inexact(const char *func_name, dd_to_d_func func,
  * This function is only meant to test functions that returns the input value if it is
  * integral: f(x) -> x for x in N.
  *
- * \param func_name a printable name for the tested function.
- * \param func the function to call.
+ * \param func_name, a printable name for the tested function.
+ * \param func, the function to call.
  */
 static int
 helper_range(const char *func_name, d_to_d_func func)
@@ -1161,7 +1138,7 @@ log_baseCases(void *args)
                         1.0, 0.0, result);
 
     result = SDL_log(EULER);
-    SDLTest_AssertCheck((result - 1.) < FLT_EPSILON,
+    SDLTest_AssertCheck(1.0 == result,
                         "Log(%f), expected %f, got %f",
                         EULER, 1.0, result);
 
@@ -1669,16 +1646,14 @@ static int
 pow_regularCases(void *args)
 {
     const dd_to_d regular_cases[] = {
-#if 0 /* These tests fail when using the Mingw C runtime, we'll disable them for now */
         { -391.25, -2.0, 0.00000653267870448815438463212659780943170062528224661946296691894531250 },
         { -72.3, 12.0, 20401381050275984310272.0 },
-#endif
         { -5.0, 3.0, -125.0 },
         { 3.0, 2.5, 15.58845726811989607085706666111946105957031250 },
         { 39.23, -1.5, 0.0040697950366865498147972424192175822099670767784118652343750 },
         { 478.972, 12.125, 315326359630449587856007411793920.0 }
     };
-    return helper_ddtod_inexact("Pow", SDL_pow, regular_cases, SDL_arraysize(regular_cases));
+    return helper_ddtod("Pow", SDL_pow, regular_cases, SDL_arraysize(regular_cases));
 }
 
 /**
@@ -2006,24 +1981,24 @@ static int
 cos_precisionTest(void *args)
 {
     const d_to_d precision_cases[] = {
-        { M_PI * 1.0 / 10.0, 0.9510565162951535 },
-        { M_PI * 2.0 / 10.0, 0.8090169943749475 },
-        { M_PI * 3.0 / 10.0, 0.5877852522924731 },
-        { M_PI * 4.0 / 10.0, 0.30901699437494745 },
+        { M_PI * 1.0 / 10.0, 0.9510565162 },
+        { M_PI * 2.0 / 10.0, 0.8090169943 },
+        { M_PI * 3.0 / 10.0, 0.5877852522 },
+        { M_PI * 4.0 / 10.0, 0.3090169943 },
         { M_PI * 5.0 / 10.0, 0.0 },
-        { M_PI * 6.0 / 10.0, -0.30901699437494734 },
-        { M_PI * 7.0 / 10.0, -0.587785252292473 },
-        { M_PI * 8.0 / 10.0, -0.8090169943749473 },
-        { M_PI * 9.0 / 10.0, -0.9510565162951535 },
-        { M_PI * -1.0 / 10.0, 0.9510565162951535 },
-        { M_PI * -2.0 / 10.0, 0.8090169943749475 },
-        { M_PI * -3.0 / 10.0, 0.5877852522924731 },
-        { M_PI * -4.0 / 10.0, 0.30901699437494745 },
+        { M_PI * 6.0 / 10.0, -0.3090169943 },
+        { M_PI * 7.0 / 10.0, -0.5877852522 },
+        { M_PI * 8.0 / 10.0, -0.8090169943 },
+        { M_PI * 9.0 / 10.0, -0.9510565162 },
+        { M_PI * -1.0 / 10.0, 0.9510565162 },
+        { M_PI * -2.0 / 10.0, 0.8090169943 },
+        { M_PI * -3.0 / 10.0, 0.5877852522 },
+        { M_PI * -4.0 / 10.0, 0.3090169943 },
         { M_PI * -5.0 / 10.0, 0.0 },
-        { M_PI * -6.0 / 10.0, -0.30901699437494734 },
-        { M_PI * -7.0 / 10.0, -0.587785252292473 },
-        { M_PI * -8.0 / 10.0, -0.8090169943749473 },
-        { M_PI * -9.0 / 10.0, -0.9510565162951535 }
+        { M_PI * -6.0 / 10.0, -0.3090169943 },
+        { M_PI * -7.0 / 10.0, -0.5877852522 },
+        { M_PI * -8.0 / 10.0, -0.8090169943 },
+        { M_PI * -9.0 / 10.0, -0.9510565162 }
     };
     return helper_dtod_inexact("Cos", SDL_cos, precision_cases, SDL_arraysize(precision_cases));
 }
@@ -2124,23 +2099,23 @@ static int
 sin_precisionTest(void *args)
 {
     const d_to_d precision_cases[] = {
-        { M_PI * 1.0 / 10.0, 0.3090169943749474 },
-        { M_PI * 2.0 / 10.0, 0.5877852522924731 },
-        { M_PI * 3.0 / 10.0, 0.8090169943749475 },
-        { M_PI * 4.0 / 10.0, 0.9510565162951535 },
-        { M_PI * 6.0 / 10.0, 0.9510565162951536 },
-        { M_PI * 7.0 / 10.0, 0.8090169943749475 },
-        { M_PI * 8.0 / 10.0, 0.5877852522924732 },
-        { M_PI * 9.0 / 10.0, 0.3090169943749475 },
+        { M_PI * 1.0 / 10.0, 0.3090169943 },
+        { M_PI * 2.0 / 10.0, 0.5877852522 },
+        { M_PI * 3.0 / 10.0, 0.8090169943 },
+        { M_PI * 4.0 / 10.0, 0.9510565162 },
+        { M_PI * 6.0 / 10.0, 0.9510565162 },
+        { M_PI * 7.0 / 10.0, 0.8090169943 },
+        { M_PI * 8.0 / 10.0, 0.5877852522 },
+        { M_PI * 9.0 / 10.0, 0.3090169943 },
         { M_PI, 0.0 },
-        { M_PI * -1.0 / 10.0, -0.3090169943749474 },
-        { M_PI * -2.0 / 10.0, -0.5877852522924731 },
-        { M_PI * -3.0 / 10.0, -0.8090169943749475 },
-        { M_PI * -4.0 / 10.0, -0.9510565162951535 },
-        { M_PI * -6.0 / 10.0, -0.9510565162951536 },
-        { M_PI * -7.0 / 10.0, -0.8090169943749475 },
-        { M_PI * -8.0 / 10.0, -0.5877852522924732 },
-        { M_PI * -9.0 / 10.0, -0.3090169943749475 },
+        { M_PI * -1.0 / 10.0, -0.3090169943 },
+        { M_PI * -2.0 / 10.0, -0.5877852522 },
+        { M_PI * -3.0 / 10.0, -0.8090169943 },
+        { M_PI * -4.0 / 10.0, -0.9510565162 },
+        { M_PI * -6.0 / 10.0, -0.9510565162 },
+        { M_PI * -7.0 / 10.0, -0.8090169943 },
+        { M_PI * -8.0 / 10.0, -0.5877852522 },
+        { M_PI * -9.0 / 10.0, -0.3090169943 },
         { -M_PI, 0.0 },
     };
     return helper_dtod_inexact("Sin", SDL_sin, precision_cases, SDL_arraysize(precision_cases));
@@ -2240,26 +2215,26 @@ static int
 tan_precisionTest(void *args)
 {
     const d_to_d precision_cases[] = {
-        { M_PI * 1.0 / 11.0, 0.29362649293836673 },
-        { M_PI * 2.0 / 11.0, 0.642660977168331 },
-        { M_PI * 3.0 / 11.0, 1.1540615205330094 },
-        { M_PI * 4.0 / 11.0, 2.189694562989681 },
-        { M_PI * 5.0 / 11.0, 6.9551527717734745 },
-        { M_PI * 6.0 / 11.0, -6.955152771773481 },
-        { M_PI * 7.0 / 11.0, -2.189694562989682 },
-        { M_PI * 8.0 / 11.0, -1.1540615205330096 },
-        { M_PI * 9.0 / 11.0, -0.6426609771683314 },
-        { M_PI * 10.0 / 11.0, -0.2936264929383667 },
-        { M_PI * -1.0 / 11.0, -0.29362649293836673 },
-        { M_PI * -2.0 / 11.0, -0.642660977168331 },
-        { M_PI * -3.0 / 11.0, -1.1540615205330094 },
-        { M_PI * -4.0 / 11.0, -2.189694562989681 },
-        { M_PI * -5.0 / 11.0, -6.9551527717734745 },
-        { M_PI * -6.0 / 11.0, 6.955152771773481 },
-        { M_PI * -7.0 / 11.0, 2.189694562989682 },
-        { M_PI * -8.0 / 11.0, 1.1540615205330096 },
-        { M_PI * -9.0 / 11.0, 0.6426609771683314 },
-        { M_PI * -10.0 / 11.0, 0.2936264929383667 }
+        { M_PI * 1.0 / 11.0, 0.2936264929 },
+        { M_PI * 2.0 / 11.0, 0.6426609771 },
+        { M_PI * 3.0 / 11.0, 1.1540615205 },
+        { M_PI * 4.0 / 11.0, 2.1896945629 },
+        { M_PI * 5.0 / 11.0, 6.9551527717 },
+        { M_PI * 6.0 / 11.0, -6.9551527717 },
+        { M_PI * 7.0 / 11.0, -2.1896945629 },
+        { M_PI * 8.0 / 11.0, -1.1540615205 },
+        { M_PI * 9.0 / 11.0, -0.6426609771 },
+        { M_PI * 10.0 / 11.0, -0.2936264929 },
+        { M_PI * -1.0 / 11.0, -0.2936264929 },
+        { M_PI * -2.0 / 11.0, -0.6426609771 },
+        { M_PI * -3.0 / 11.0, -1.1540615205 },
+        { M_PI * -4.0 / 11.0, -2.1896945629 },
+        { M_PI * -5.0 / 11.0, -6.9551527717 },
+        { M_PI * -6.0 / 11.0, 6.9551527717 },
+        { M_PI * -7.0 / 11.0, 2.1896945629 },
+        { M_PI * -8.0 / 11.0, 1.1540615205 },
+        { M_PI * -9.0 / 11.0, 0.6426609771 },
+        { M_PI * -10.0 / 11.0, 0.2936264929 }
     };
     return helper_dtod_inexact("Tan", SDL_tan, precision_cases, SDL_arraysize(precision_cases));
 }
@@ -2281,7 +2256,7 @@ acos_limitCases(void *args)
                         1.0, 0.0, result);
 
     result = SDL_acos(-1.0);
-    SDLTest_AssertCheck(SDL_fabs(M_PI - result) <= EPSILON,
+    SDLTest_AssertCheck(M_PI == result,
                         "Acos(%f), expected %f, got %f",
                         -1.0, M_PI, result);
 
@@ -2368,12 +2343,12 @@ asin_limitCases(void *args)
     double result;
 
     result = SDL_asin(1.0);
-    SDLTest_AssertCheck(SDL_fabs(M_PI / 2.0 - result) <= EPSILON,
+    SDLTest_AssertCheck(M_PI / 2.0 == result,
                         "Asin(%f), expected %f, got %f",
                         1.0, M_PI / 2.0, result);
 
     result = SDL_asin(-1.0);
-    SDLTest_AssertCheck(SDL_fabs(-M_PI / 2.0 - result) <= EPSILON,
+    SDLTest_AssertCheck(-M_PI / 2.0 == result,
                         "Asin(%f), expected %f, got %f",
                         -1.0, -M_PI / 2.0, result);
 
@@ -2424,26 +2399,26 @@ static int
 asin_precisionTest(void *args)
 {
     const d_to_d precision_cases[] = {
-        { 0.9, 1.1197695149986342 },
-        { 0.8, 0.9272952180016123 },
-        { 0.7, 0.775397496610753 },
-        { 0.6, 0.6435011087932844 },
-        { 0.5, 0.5235987755982989 },
-        { 0.4, 0.41151684606748806 },
-        { 0.3, 0.3046926540153976 },
-        { 0.2, 0.20135792079033074 },
-        { 0.1, 0.10016742116155977 },
+        { 0.9, 1.1197695149 },
+        { 0.8, 0.9272952180 },
+        { 0.7, 0.7753974966 },
+        { 0.6, 0.6435011087 },
+        { 0.5, 0.5235987755 },
+        { 0.4, 0.4115168460 },
+        { 0.3, 0.3046926540 },
+        { 0.2, 0.2013579207 },
+        { 0.1, 0.1001674211 },
         { 0.0, 0.0 },
         { -0.0, -0.0 },
-        { -0.1, -0.10016742116155977 },
-        { -0.2, -0.20135792079033074 },
-        { -0.3, -0.3046926540153976 },
-        { -0.4, -0.41151684606748806 },
-        { -0.5, -0.5235987755982989 },
-        { -0.6, -0.6435011087932844 },
-        { -0.7, -0.775397496610753 },
-        { -0.8, -0.9272952180016123 },
-        { -0.9, -1.1197695149986342 }
+        { -0.1, -0.1001674211 },
+        { -0.2, -0.2013579207 },
+        { -0.3, -0.3046926540 },
+        { -0.4, -0.4115168460 },
+        { -0.5, -0.5235987755 },
+        { -0.6, -0.6435011087 },
+        { -0.7, -0.7753974966 },
+        { -0.8, -0.9272952180 },
+        { -0.9, -1.1197695149 }
     };
     return helper_dtod_inexact("Asin", SDL_asin, precision_cases, SDL_arraysize(precision_cases));
 }
@@ -2518,24 +2493,24 @@ static int
 atan_precisionTest(void *args)
 {
     const d_to_d precision_cases[] = {
-        { 6.313751514675041, 1.413716694115407 },
-        { 3.0776835371752527, 1.2566370614359172 },
-        { 1.9626105055051504, 1.0995574287564276 },
-        { 1.3763819204711734, 0.9424777960769379 },
-        { 1.0, 0.7853981633974483 },
-        { 0.7265425280053609, 0.6283185307179586 },
-        { 0.5095254494944288, 0.47123889803846897 },
-        { 0.3249196962329063, 0.3141592653589793 },
-        { 0.15838444032453627, 0.15707963267948966 },
-        { -0.15838444032453627, -0.15707963267948966 },
-        { -0.3249196962329063, -0.3141592653589793 },
-        { -0.5095254494944288, -0.47123889803846897 },
-        { -0.7265425280053609, -0.6283185307179586 },
-        { -1.0, -0.7853981633974483 },
-        { -1.3763819204711734, -0.9424777960769379 },
-        { -1.9626105055051504, -1.0995574287564276 },
-        { -3.0776835371752527, -1.2566370614359172 },
-        { -6.313751514675041, -1.413716694115407 },
+        { 6.313751514675041, 1.4137166941 },
+        { 3.0776835371752527, 1.2566370614 },
+        { 1.9626105055051504, 1.0995574287 },
+        { 1.3763819204711734, 0.9424777960 },
+        { 1.0, 0.7853981633 },
+        { 0.7265425280053609, 0.6283185307 },
+        { 0.5095254494944288, 0.4712388980 },
+        { 0.3249196962329063, 0.3141592653 },
+        { 0.15838444032453627, 0.1570796326 },
+        { -0.15838444032453627, -0.1570796326 },
+        { -0.3249196962329063, -0.3141592653 },
+        { -0.5095254494944288, -0.4712388980 },
+        { -0.7265425280053609, -0.6283185307 },
+        { -1.0, -0.7853981633 },
+        { -1.3763819204711734, -0.9424777960 },
+        { -1.9626105055051504, -1.0995574287 },
+        { -3.0776835371752527, -1.2566370614 },
+        { -6.313751514675041, -1.4137166941 },
     };
     return helper_dtod_inexact("Atan", SDL_atan, precision_cases, SDL_arraysize(precision_cases));
 }
@@ -2560,7 +2535,7 @@ atan2_bothZeroCases(void *args)
         { 0.0, -0.0, M_PI },
         { -0.0, -0.0, -M_PI },
     };
-    return helper_ddtod_inexact("SDL_atan2", SDL_atan2, cases, SDL_arraysize(cases));
+    return helper_ddtod("SDL_atan2", SDL_atan2, cases, SDL_arraysize(cases));
 }
 
 /**
@@ -2579,7 +2554,7 @@ atan2_yZeroCases(void *args)
         { -0.0, 1.0, -0.0 },
         { -0.0, -1.0, -M_PI }
     };
-    return helper_ddtod_inexact("SDL_atan2", SDL_atan2, cases, SDL_arraysize(cases));
+    return helper_ddtod("SDL_atan2", SDL_atan2, cases, SDL_arraysize(cases));
 }
 
 /**
@@ -2595,7 +2570,7 @@ atan2_xZeroCases(void *args)
         { 1.0, -0.0, M_PI / 2.0 },
         { -1.0, -0.0, -M_PI / 2.0 }
     };
-    return helper_ddtod_inexact("SDL_atan2", SDL_atan2, cases, SDL_arraysize(cases));
+    return helper_ddtod("SDL_atan2", SDL_atan2, cases, SDL_arraysize(cases));
 }
 
 /* Infinity cases */
@@ -2611,12 +2586,29 @@ atan2_xZeroCases(void *args)
 static int
 atan2_bothInfCases(void *args)
 {
-    dd_to_d cases[4];
-    DD_TO_D_CASE(0,  INFINITY,  INFINITY,  1.0 * M_PI / 4.0);
-    DD_TO_D_CASE(1,  INFINITY, -INFINITY,  3.0 * M_PI / 4.0);
-    DD_TO_D_CASE(2, -INFINITY,  INFINITY, -1.0 * M_PI / 4.0);
-    DD_TO_D_CASE(3, -INFINITY, -INFINITY, -3.0 * M_PI / 4.0);
-    return helper_ddtod("SDL_atan2(bothInfCases)", SDL_atan2, cases, SDL_arraysize(cases));
+    double result;
+
+    result = SDL_atan2(INFINITY, INFINITY);
+    SDLTest_AssertCheck(M_PI / 4.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        INFINITY, INFINITY, M_PI / 4.0, result);
+
+    result = SDL_atan2(INFINITY, -INFINITY);
+    SDLTest_AssertCheck(3.0 * M_PI / 4.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        INFINITY, -INFINITY, 3.0 * M_PI / 4.0, result);
+
+    result = SDL_atan2(-INFINITY, INFINITY);
+    SDLTest_AssertCheck(-M_PI / 4.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        -INFINITY, INFINITY, -M_PI / 4.0, result);
+
+    result = SDL_atan2(-INFINITY, -INFINITY);
+    SDLTest_AssertCheck(-3.0 * M_PI / 4.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        -INFINITY, -INFINITY, -3.0 * M_PI / 4.0, result);
+
+    return TEST_COMPLETED;
 }
 
 /**
@@ -2626,12 +2618,29 @@ atan2_bothInfCases(void *args)
 static int
 atan2_yInfCases(void *args)
 {
-    dd_to_d cases[4];
-    DD_TO_D_CASE(0,  INFINITY,  1.0,  1.0 * M_PI / 2.0);
-    DD_TO_D_CASE(1,  INFINITY, -1.0,  1.0 * M_PI / 2.0);
-    DD_TO_D_CASE(2, -INFINITY,  1.0, -1.0 * M_PI / 2.0);
-    DD_TO_D_CASE(3, -INFINITY, -1.0, -1.0 * M_PI / 2.0);
-    return helper_ddtod("SDL_atan2(atan2_yInfCases)", SDL_atan2, cases, SDL_arraysize(cases));
+    double result;
+
+    result = SDL_atan2(INFINITY, 1.0);
+    SDLTest_AssertCheck(M_PI / 2.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        INFINITY, 1.0, M_PI / 2.0, result);
+
+    result = SDL_atan2(INFINITY, -1.0);
+    SDLTest_AssertCheck(M_PI / 2.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        INFINITY, -1.0, M_PI / 2.0, result);
+
+    result = SDL_atan2(-INFINITY, 1.0);
+    SDLTest_AssertCheck(-M_PI / 2.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        -INFINITY, 1.0, -M_PI / 2.0, result);
+
+    result = SDL_atan2(-INFINITY, -1.0);
+    SDLTest_AssertCheck(-M_PI / 2.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        -INFINITY, -1.0, -M_PI / 2.0, result);
+
+    return TEST_COMPLETED;
 }
 
 /**
@@ -2643,12 +2652,29 @@ atan2_yInfCases(void *args)
 static int
 atan2_xInfCases(void *args)
 {
-    dd_to_d cases[4];
-    DD_TO_D_CASE(0,  1.0,  INFINITY,  0.0);
-    DD_TO_D_CASE(1, -1.0,  INFINITY, -0.0);
-    DD_TO_D_CASE(2,  1.0, -INFINITY,  M_PI);
-    DD_TO_D_CASE(3, -1.0, -INFINITY, -M_PI);
-    return helper_ddtod("atan2_xInfCases(atan2_yInfCases)", SDL_atan2, cases, SDL_arraysize(cases));
+    double result;
+
+    result = SDL_atan2(1.0, INFINITY);
+    SDLTest_AssertCheck(0.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        1.0, INFINITY, 0.0, result);
+
+    result = SDL_atan2(-1.0, INFINITY);
+    SDLTest_AssertCheck(-0.0 == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        -1.0, INFINITY, -0.0, result);
+
+    result = SDL_atan2(1.0, -INFINITY);
+    SDLTest_AssertCheck(M_PI == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        1.0, -INFINITY, M_PI, result);
+
+    result = SDL_atan2(-1.0, -INFINITY);
+    SDLTest_AssertCheck(-M_PI == result,
+                        "Atan2(%f,%f), expected %f, got %f",
+                        -1.0, -INFINITY, -M_PI, result);
+
+    return TEST_COMPLETED;
 }
 
 /* Miscelanious cases */
diff --git a/libs/SDL2/test/testautomation_mouse.c b/libs/SDL2/test/testautomation_mouse.c
index 19b1a9f58ca74fd19151fe289ff7becd89f78053..22a437801814c435d6aacf2cd0949424dd0509be 100644
--- a/libs/SDL2/test/testautomation_mouse.c
+++ b/libs/SDL2/test/testautomation_mouse.c
@@ -423,7 +423,7 @@ SDL_Window *_createMouseSuiteTestWindow()
  */
 void _destroyMouseSuiteTestWindow(SDL_Window *window)
 {
-    if (window) {
+    if (window != NULL) {
         SDL_DestroyWindow(window);
         window = NULL;
         SDLTest_AssertPass("SDL_DestroyWindow()");
@@ -458,7 +458,7 @@ int mouse_warpMouseInWindow(void *arg)
     yPositions[5] = h + 1;
     /* Create test window */
     window = _createMouseSuiteTestWindow();
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
@@ -503,7 +503,6 @@ int mouse_getMouseFocus(void *arg)
     int x, y;
     SDL_Window *window;
     SDL_Window *focusWindow;
-    const SDL_bool video_driver_is_wayland = !SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland");
 
     /* Get focus - focus non-deterministic */
     focusWindow = SDL_GetMouseFocus();
@@ -511,37 +510,32 @@ int mouse_getMouseFocus(void *arg)
 
     /* Create test window */
     window = _createMouseSuiteTestWindow();
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
-    /* Wayland explicitly disallows warping the mouse pointer, so this test must be skipped. */
-    if (!video_driver_is_wayland) {
-        /* Mouse to random position inside window */
-        x = SDLTest_RandomIntegerInRange(1, w - 1);
-        y = SDLTest_RandomIntegerInRange(1, h - 1);
-        SDL_WarpMouseInWindow(window, x, y);
-        SDLTest_AssertPass("SDL_WarpMouseInWindow(...,%i,%i)", x, y);
-
-        /* Pump events to update focus state */
-        SDL_Delay(100);
-        SDL_PumpEvents();
-        SDLTest_AssertPass("SDL_PumpEvents()");
-
-        /* Get focus with explicit window setup - focus deterministic */
-        focusWindow = SDL_GetMouseFocus();
-        SDLTest_AssertPass("SDL_GetMouseFocus()");
-        SDLTest_AssertCheck(focusWindow != NULL, "Check returned window value is not NULL");
-        SDLTest_AssertCheck(focusWindow == window, "Check returned window value is test window");
-
-        /* Mouse to random position outside window */
-        x = SDLTest_RandomIntegerInRange(-9, -1);
-        y = SDLTest_RandomIntegerInRange(-9, -1);
-        SDL_WarpMouseInWindow(window, x, y);
-        SDLTest_AssertPass("SDL_WarpMouseInWindow(...,%i,%i)", x, y);
-    } else {
-        SDLTest_Log("Skipping mouse warp focus tests: Wayland does not support warping the mouse pointer");
-    }
+    /* Mouse to random position inside window */
+    x = SDLTest_RandomIntegerInRange(1, w - 1);
+    y = SDLTest_RandomIntegerInRange(1, h - 1);
+    SDL_WarpMouseInWindow(window, x, y);
+    SDLTest_AssertPass("SDL_WarpMouseInWindow(...,%i,%i)", x, y);
+
+    /* Pump events to update focus state */
+    SDL_Delay(100);
+    SDL_PumpEvents();
+    SDLTest_AssertPass("SDL_PumpEvents()");
+
+    /* Get focus with explicit window setup - focus deterministic */
+    focusWindow = SDL_GetMouseFocus();
+    SDLTest_AssertPass("SDL_GetMouseFocus()");
+    SDLTest_AssertCheck(focusWindow != NULL, "Check returned window value is not NULL");
+    SDLTest_AssertCheck(focusWindow == window, "Check returned window value is test window");
+
+    /* Mouse to random position outside window */
+    x = SDLTest_RandomIntegerInRange(-9, -1);
+    y = SDLTest_RandomIntegerInRange(-9, -1);
+    SDL_WarpMouseInWindow(window, x, y);
+    SDLTest_AssertPass("SDL_WarpMouseInWindow(...,%i,%i)", x, y);
 
     /* Clean up test window */
     _destroyMouseSuiteTestWindow(window);
diff --git a/libs/SDL2/test/testautomation_pixels.c b/libs/SDL2/test/testautomation_pixels.c
index 12cf632490c757cb4d01cc4be5f5fb7821037052..d5440e5b4db47dc16bc46458096a054fad7df037 100644
--- a/libs/SDL2/test/testautomation_pixels.c
+++ b/libs/SDL2/test/testautomation_pixels.c
@@ -14,8 +14,6 @@ const int _numRGBPixelFormats = 31;
 Uint32 _RGBPixelFormats[] = {
     SDL_PIXELFORMAT_INDEX1LSB,
     SDL_PIXELFORMAT_INDEX1MSB,
-    SDL_PIXELFORMAT_INDEX2LSB,
-    SDL_PIXELFORMAT_INDEX2MSB,
     SDL_PIXELFORMAT_INDEX4LSB,
     SDL_PIXELFORMAT_INDEX4MSB,
     SDL_PIXELFORMAT_INDEX8,
@@ -49,8 +47,6 @@ Uint32 _RGBPixelFormats[] = {
 const char *_RGBPixelFormatsVerbose[] = {
     "SDL_PIXELFORMAT_INDEX1LSB",
     "SDL_PIXELFORMAT_INDEX1MSB",
-    "SDL_PIXELFORMAT_INDEX2LSB",
-    "SDL_PIXELFORMAT_INDEX2MSB",
     "SDL_PIXELFORMAT_INDEX4LSB",
     "SDL_PIXELFORMAT_INDEX4MSB",
     "SDL_PIXELFORMAT_INDEX8",
diff --git a/libs/SDL2/test/testautomation_platform.c b/libs/SDL2/test/testautomation_platform.c
index bd2aabed68eab34137fbac4799093d15d26b86e1..ac85eef23a9b29ed992739f7e7dcb3488bf0901d 100644
--- a/libs/SDL2/test/testautomation_platform.c
+++ b/libs/SDL2/test/testautomation_platform.c
@@ -386,7 +386,7 @@ int platform_testSetErrorEmptyInput(void *arg)
 int platform_testSetErrorInvalidInput(void *arg)
 {
     int result;
-    const char *invalidError = "";
+    const char *invalidError = NULL;
     const char *probeError = "Testing";
     char *lastError;
     size_t len;
diff --git a/libs/SDL2/test/testautomation_render.c b/libs/SDL2/test/testautomation_render.c
index 45198a826ee1a775868371295ccdf9546062f9f3..74b96314609b1bda041a908d168d3d9f8e0c17cc 100644
--- a/libs/SDL2/test/testautomation_render.c
+++ b/libs/SDL2/test/testautomation_render.c
@@ -43,7 +43,6 @@ static int _isSupported(int code);
 void InitCreateRenderer(void *arg)
 {
     int posX = 100, posY = 100, width = 320, height = 240;
-    int renderer_flags = SDL_RENDERER_ACCELERATED;
     renderer = NULL;
     window = SDL_CreateWindow("render_testCreateRenderer", posX, posY, width, height, 0);
     SDLTest_AssertPass("SDL_CreateWindow()");
@@ -52,11 +51,7 @@ void InitCreateRenderer(void *arg)
         return;
     }
 
-    if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "dummy") == 0) {
-        renderer_flags = 0;
-    }
-
-    renderer = SDL_CreateRenderer(window, -1, renderer_flags);
+    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
     SDLTest_AssertPass("SDL_CreateRenderer()");
     SDLTest_AssertCheck(renderer != NULL, "Check SDL_CreateRenderer result");
     if (renderer == NULL) {
@@ -70,13 +65,13 @@ void InitCreateRenderer(void *arg)
  */
 void CleanupDestroyRenderer(void *arg)
 {
-    if (renderer) {
+    if (renderer != NULL) {
         SDL_DestroyRenderer(renderer);
         renderer = NULL;
         SDLTest_AssertPass("SDL_DestroyRenderer()");
     }
 
-    if (window) {
+    if (window != NULL) {
         SDL_DestroyWindow(window);
         window = NULL;
         SDLTest_AssertPass("SDL_DestroyWindow");
@@ -943,12 +938,12 @@ _loadTestFace(void)
     SDL_Texture *tface;
 
     face = SDLTest_ImageFace();
-    if (!face) {
+    if (face == NULL) {
         return NULL;
     }
 
     tface = SDL_CreateTextureFromSurface(renderer, face);
-    if (!tface) {
+    if (tface == NULL) {
         SDLTest_LogError("SDL_CreateTextureFromSurface() failed with error: %s", SDL_GetError());
     }
 
@@ -975,7 +970,7 @@ _hasTexColor(void)
 
     /* Get test face. */
     tface = _loadTestFace();
-    if (!tface) {
+    if (tface == NULL) {
         return 0;
     }
 
@@ -1019,7 +1014,7 @@ _hasTexAlpha(void)
 
     /* Get test face. */
     tface = _loadTestFace();
-    if (!tface) {
+    if (tface == NULL) {
         return 0;
     }
 
@@ -1048,7 +1043,7 @@ _hasTexAlpha(void)
 /**
  * @brief Compares screen pixels with image pixels. Helper function.
  *
- * @param referenceSurface Image to compare against.
+ * @param s Image to compare against.
  *
  * \sa
  * http://wiki.libsdl.org/SDL_RenderReadPixels
diff --git a/libs/SDL2/test/testautomation_stdlib.c b/libs/SDL2/test/testautomation_stdlib.c
index ed9f13ea35d981f8e31f9496037423d82de995b8..a75e4570b5ea22999585bdc19409d0092cf9eb39 100644
--- a/libs/SDL2/test/testautomation_stdlib.c
+++ b/libs/SDL2/test/testautomation_stdlib.c
@@ -53,7 +53,7 @@ int stdlib_snprintf(void *arg)
     int result;
     int predicted;
     char text[1024];
-    const char *expected, *expected2, *expected3, *expected4, *expected5;
+    const char *expected;
     size_t size;
 
     result = SDL_snprintf(text, sizeof(text), "%s", "foo");
@@ -175,61 +175,6 @@ int stdlib_snprintf(void *arg)
     SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0, "Check text, expected: '%s', got: '%s'", expected, text);
     SDLTest_AssertCheck(result == 7, "Check result value, expected: 7, got: %d", result);
 
-    result = SDL_snprintf(text, sizeof(text), "%p", (void *)0x1234abcd);
-    expected = "0x1234abcd";
-    expected2 = "1234ABCD";
-    expected3 = "000000001234ABCD";
-    expected4 = "1234abcd";
-    expected5 = "000000001234abcd";
-    SDLTest_AssertPass("Call to SDL_snprintf(text, sizeof(text), \"%%p\", 0x1234abcd)");
-    SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0 ||
-                        SDL_strcmp(text, expected2) == 0 ||
-                        SDL_strcmp(text, expected3) == 0 ||
-                        SDL_strcmp(text, expected4) == 0 ||
-                        SDL_strcmp(text, expected5) == 0,
-        "Check text, expected: '%s', got: '%s'", expected, text);
-    SDLTest_AssertCheck(result == SDL_strlen(expected) ||
-                        result == SDL_strlen(expected2) ||
-                        result == SDL_strlen(expected3) ||
-                        result == SDL_strlen(expected4) ||
-                        result == SDL_strlen(expected5),
-        "Check result value, expected: %d, got: %d", (int)SDL_strlen(expected), result);
-
-    result = SDL_snprintf(text, sizeof(text), "A %p B", (void *)0x1234abcd);
-    expected = "A 0x1234abcd B";
-    expected2 = "A 1234ABCD B";
-    expected3 = "A 000000001234ABCD B";
-    expected4 = "A 1234abcd B";
-    expected5 = "A 000000001234abcd B";
-    SDLTest_AssertPass("Call to SDL_snprintf(text, sizeof(text), \"A %%p B\", 0x1234abcd)");
-    SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0 ||
-                        SDL_strcmp(text, expected2) == 0 ||
-                        SDL_strcmp(text, expected3) == 0 ||
-                        SDL_strcmp(text, expected4) == 0 ||
-                        SDL_strcmp(text, expected5) == 0,
-        "Check text, expected: '%s', got: '%s'", expected, text);
-    SDLTest_AssertCheck(result == SDL_strlen(expected) ||
-                        result == SDL_strlen(expected2) ||
-                        result == SDL_strlen(expected3) ||
-                        result == SDL_strlen(expected4) ||
-                        result == SDL_strlen(expected5),
-        "Check result value, expected: %d, got: %d", (int)SDL_strlen(expected), result);
-
-    if (sizeof(void *) >= 8) {
-        result = SDL_snprintf(text, sizeof(text), "%p", (void *)0x1ba07bddf60L);
-        expected = "0x1ba07bddf60";
-        expected2 = "000001BA07BDDF60";
-        expected3 = "000001ba07bddf60";
-        SDLTest_AssertPass("Call to SDL_snprintf(text, sizeof(text), \"%%p\", 0x1ba07bddf60)");
-        SDLTest_AssertCheck(SDL_strcmp(text, expected) == 0 ||
-                            SDL_strcmp(text, expected2) == 0 ||
-                            SDL_strcmp(text, expected3) == 0,
-            "Check text, expected: '%s', got: '%s'", expected, text);
-        SDLTest_AssertCheck(result == SDL_strlen(expected) ||
-                            result == SDL_strlen(expected2) ||
-                            result == SDL_strlen(expected3),
-            "Check result value, expected: %d, got: %d", (int)SDL_strlen(expected), result);
-    }
     return TEST_COMPLETED;
 }
 
@@ -262,10 +207,10 @@ int stdlib_getsetenv(void *arg)
 
         text = SDL_getenv(name);
         SDLTest_AssertPass("Call to SDL_getenv('%s')", name);
-        if (text) {
+        if (text != NULL) {
             SDLTest_Log("Expected: NULL, Got: '%s' (%i)", text, (int)SDL_strlen(text));
         }
-    } while (text);
+    } while (text != NULL);
 
     /* Create random values to set */
     value1 = SDLTest_RandomAsciiStringOfSize(10);
diff --git a/libs/SDL2/test/testautomation_subsystems.c b/libs/SDL2/test/testautomation_subsystems.c
deleted file mode 100644
index d25edeeb7ce82624e90ad5da35783e05e8e79ceb..0000000000000000000000000000000000000000
--- a/libs/SDL2/test/testautomation_subsystems.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/**
- * Subsystem test suite
- */
-
-#include "SDL.h"
-#include "SDL_test.h"
-
-/* ================= Test Case Implementation ================== */
-
-/* Fixture */
-
-static void subsystemsSetUp(void *arg)
-{
-    /* Reset each one of the SDL subsystems */
-    /* CHECKME: can we use SDL_Quit here, or this will break the flow of tests? */
-    SDL_Quit();
-    /* Alternate variant without SDL_Quit:
-        while (SDL_WasInit(SDL_INIT_EVERYTHING) != 0) {
-            SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
-        }
-    */
-    SDLTest_AssertPass("Reset all subsystems before subsystems test");
-    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_EVERYTHING) == 0, "Check result from SDL_WasInit(SDL_INIT_EVERYTHING)");
-}
-
-static void subsystemsTearDown(void *arg)
-{
-    /* Reset each one of the SDL subsystems */
-    SDL_Quit();
-
-    SDLTest_AssertPass("Cleanup of subsystems test completed");
-}
-
-/* Test case functions */
-
-/**
- * \brief Inits and Quits particular subsystem, checking its Init status.
- *
- * \sa SDL_InitSubSystem
- * \sa SDL_QuitSubSystem
- *
- */
-static int subsystems_referenceCount()
-{
-    const int system = SDL_INIT_VIDEO;
-    int result;
-    /* Ensure that we start with a non-initialized subsystem. */
-    SDLTest_AssertCheck(SDL_WasInit(system) == 0, "Check result from SDL_WasInit(0x%x)", system);
-
-    /* Init subsystem once, and quit once */
-    SDL_InitSubSystem(system);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(0x%x)", system);
-    result = SDL_WasInit(system);
-    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
-
-    SDL_QuitSubSystem(system);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x)", system);
-    result = SDL_WasInit(system);
-    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(0x%x), expected: 0, got: 0x%x", system, result);
-
-    /* Init subsystem number of times, then decrement reference count until it's disposed of. */
-    SDL_InitSubSystem(system);
-    SDL_InitSubSystem(system);
-    SDL_InitSubSystem(system);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(0x%x) x3 times", system);
-    result = SDL_WasInit(system);
-    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
-
-    SDL_QuitSubSystem(system);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x) x1", system);
-    result = SDL_WasInit(system);
-    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
-    SDL_QuitSubSystem(system);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x) x2", system);
-    result = SDL_WasInit(system);
-    SDLTest_AssertCheck(result == system, "Check result from SDL_WasInit(0x%x), expected: 0x%x, got: 0x%x", system, system, result);
-    SDL_QuitSubSystem(system);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(0x%x) x3", system);
-    result = SDL_WasInit(system);
-    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(0x%x), expected: 0, got: 0x%x", system, result);
-
-    return TEST_COMPLETED;
-}
-
-/**
- * \brief Inits and Quits subsystems that have another as dependency;
- *        check that the dependency is not removed before the last of its dependents.
- *
- * \sa SDL_InitSubSystem
- * \sa SDL_QuitSubSystem
- *
- */
-static int subsystems_dependRefCountInitAllQuitByOne()
-{
-    int result;
-    /* Ensure that we start with reset subsystems. */
-    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS) == 0,
-                        "Check result from SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS)");
-
-    /* Following should init SDL_INIT_EVENTS and give it +3 ref counts. */
-    SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-
-    /* Quit systems one by one. */
-    SDL_QuitSubSystem(SDL_INIT_VIDEO);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_VIDEO)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-    SDL_QuitSubSystem(SDL_INIT_AUDIO);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-    SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_JOYSTICK)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0, got: 0x%x", result);
-
-    return TEST_COMPLETED;
-}
-
-/**
- * \brief Inits and Quits subsystems that have another as dependency;
- *        check that the dependency is not removed before the last of its dependents.
- *
- * \sa SDL_InitSubSystem
- * \sa SDL_QuitSubSystem
- *
- */
-static int subsystems_dependRefCountInitByOneQuitAll()
-{
-    int result;
-    /* Ensure that we start with reset subsystems. */
-    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS) == 0,
-                        "Check result from SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS)");
-
-    /* Following should init SDL_INIT_EVENTS and give it +3 ref counts. */
-    SDL_InitSubSystem(SDL_INIT_VIDEO);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_VIDEO)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-    SDL_InitSubSystem(SDL_INIT_AUDIO);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_AUDIO)");
-    SDL_InitSubSystem(SDL_INIT_JOYSTICK);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_JOYSTICK)");
-
-    /* Quit systems all at once. */
-    SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0, got: 0x%x", result);
-
-    return TEST_COMPLETED;
-}
-
-/**
- * \brief Inits and Quits subsystems that have another as dependency,
- *        but also inits that dependency explicitly, giving it extra ref count.
- *        Check that the dependency is not removed before the last reference is gone.
- *
- * \sa SDL_InitSubSystem
- * \sa SDL_QuitSubSystem
- *
- */
-static int subsystems_dependRefCountWithExtraInit()
-{
-    int result;
-    /* Ensure that we start with reset subsystems. */
-    SDLTest_AssertCheck(SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS) == 0,
-                        "Check result from SDL_WasInit(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS)");
-
-    /* Init EVENTS explicitly, +1 ref count. */
-    SDL_InitSubSystem(SDL_INIT_EVENTS);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_EVENTS)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-    /* Following should init SDL_INIT_EVENTS and give it +3 ref counts. */
-    SDL_InitSubSystem(SDL_INIT_VIDEO);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_VIDEO)");
-    SDL_InitSubSystem(SDL_INIT_AUDIO);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_AUDIO)");
-    SDL_InitSubSystem(SDL_INIT_JOYSTICK);
-    SDLTest_AssertPass("Call to SDL_InitSubSystem(SDL_INIT_JOYSTICK)");
-
-    /* Quit EVENTS explicitly, -1 ref count. */
-    SDL_QuitSubSystem(SDL_INIT_EVENTS);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_EVENTS)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-
-    /* Quit systems one by one. */
-    SDL_QuitSubSystem(SDL_INIT_VIDEO);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_VIDEO)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-    SDL_QuitSubSystem(SDL_INIT_AUDIO);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_AUDIO)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == SDL_INIT_EVENTS, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0x4000, got: 0x%x", result);
-    SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
-    SDLTest_AssertPass("Call to SDL_QuitSubSystem(SDL_INIT_JOYSTICK)");
-    result = SDL_WasInit(SDL_INIT_EVENTS);
-    SDLTest_AssertCheck(result == 0, "Check result from SDL_WasInit(SDL_INIT_EVENTS), expected: 0, got: 0x%x", result);
-
-    return TEST_COMPLETED;
-}
-
-/* ================= Test References ================== */
-
-/* Subsystems test cases */
-static const SDLTest_TestCaseReference subsystemsTest1 = {
-    (SDLTest_TestCaseFp)subsystems_referenceCount, "subsystems_referenceCount", "Makes sure that subsystem stays until number of quits matches inits.", TEST_ENABLED
-};
-
-static const SDLTest_TestCaseReference subsystemsTest2 = {
-    (SDLTest_TestCaseFp)subsystems_dependRefCountInitAllQuitByOne, "subsystems_dependRefCountInitAllQuitByOne", "Check reference count of subsystem dependencies.", TEST_ENABLED
-};
-
-static const SDLTest_TestCaseReference subsystemsTest3 = {
-    (SDLTest_TestCaseFp)subsystems_dependRefCountInitByOneQuitAll, "subsystems_dependRefCountInitByOneQuitAll", "Check reference count of subsystem dependencies.", TEST_ENABLED
-};
-
-static const SDLTest_TestCaseReference subsystemsTest4 = {
-    (SDLTest_TestCaseFp)subsystems_dependRefCountWithExtraInit, "subsystems_dependRefCountWithExtraInit", "Check reference count of subsystem dependencies.", TEST_ENABLED
-};
-
-/* Sequence of Events test cases */
-static const SDLTest_TestCaseReference *subsystemsTests[] = {
-    &subsystemsTest1, &subsystemsTest2, &subsystemsTest3, &subsystemsTest4, NULL
-};
-
-/* Events test suite (global) */
-SDLTest_TestSuiteReference subsystemsTestSuite = {
-    "Subsystems",
-    subsystemsSetUp,
-    subsystemsTests,
-    subsystemsTearDown
-};
diff --git a/libs/SDL2/test/testautomation_suites.h b/libs/SDL2/test/testautomation_suites.h
index 95528f271fbeb9bf1367ccad218e56fed015a3f0..6fdcd83889dfa28f521d3a4dc27e0951860b707a 100644
--- a/libs/SDL2/test/testautomation_suites.h
+++ b/libs/SDL2/test/testautomation_suites.h
@@ -16,7 +16,6 @@ extern SDLTest_TestSuiteReference guidTestSuite;
 extern SDLTest_TestSuiteReference hintsTestSuite;
 extern SDLTest_TestSuiteReference joystickTestSuite;
 extern SDLTest_TestSuiteReference keyboardTestSuite;
-extern SDLTest_TestSuiteReference logTestSuite;
 extern SDLTest_TestSuiteReference mainTestSuite;
 extern SDLTest_TestSuiteReference mathTestSuite;
 extern SDLTest_TestSuiteReference mouseTestSuite;
@@ -27,7 +26,6 @@ extern SDLTest_TestSuiteReference renderTestSuite;
 extern SDLTest_TestSuiteReference rwopsTestSuite;
 extern SDLTest_TestSuiteReference sdltestTestSuite;
 extern SDLTest_TestSuiteReference stdlibTestSuite;
-extern SDLTest_TestSuiteReference subsystemsTestSuite;
 extern SDLTest_TestSuiteReference surfaceTestSuite;
 extern SDLTest_TestSuiteReference syswmTestSuite;
 extern SDLTest_TestSuiteReference timerTestSuite;
@@ -42,7 +40,6 @@ SDLTest_TestSuiteReference *testSuites[] = {
     &hintsTestSuite,
     &joystickTestSuite,
     &keyboardTestSuite,
-    &logTestSuite,
     &mainTestSuite,
     &mathTestSuite,
     &mouseTestSuite,
@@ -57,7 +54,6 @@ SDLTest_TestSuiteReference *testSuites[] = {
     &syswmTestSuite,
     &timerTestSuite,
     &videoTestSuite,
-    &subsystemsTestSuite, /* run last, not interfere with other test enviroment */
     NULL
 };
 
diff --git a/libs/SDL2/test/testautomation_surface.c b/libs/SDL2/test/testautomation_surface.c
index fcc4bc14cb7af0bd6925a89ce7a7f973fa0b233a..41aa24142c0c6e56bea354ec9fe1d6c6d98c8ee7 100644
--- a/libs/SDL2/test/testautomation_surface.c
+++ b/libs/SDL2/test/testautomation_surface.c
@@ -668,34 +668,6 @@ int surface_testOverflow(void *arg)
                         surface != NULL ? "(success)" : SDL_GetError());
     SDL_FreeSurface(surface);
 
-    /* SDL_PIXELFORMAT_INDEX2* needs 1 byte per 4 pixels. */
-    surface = SDL_CreateRGBSurfaceWithFormatFrom(buf, 12, 1, 2, 3, SDL_PIXELFORMAT_INDEX2LSB);
-    SDLTest_AssertCheck(surface != NULL, "12px * 2 bits per px fits in 3 bytes: %s",
-                        surface != NULL ? "(success)" : SDL_GetError());
-    SDL_FreeSurface(surface);
-    surface = SDL_CreateRGBSurfaceFrom(buf, 12, 1, 2, 3, 0, 0, 0, 0);
-    SDLTest_AssertCheck(surface != NULL, "12px * 2 bits per px fits in 3 bytes: %s",
-                        surface != NULL ? "(success)" : SDL_GetError());
-    SDL_FreeSurface(surface);
-
-    surface = SDL_CreateRGBSurfaceWithFormatFrom(buf, 13, 1, 2, 3, SDL_PIXELFORMAT_INDEX2LSB);
-    SDLTest_AssertCheck(surface == NULL, "Should detect pitch < width * bpp (%d)", surface ? surface->pitch : 0);
-    SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
-                        "Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
-    surface = SDL_CreateRGBSurfaceFrom(buf, 13, 1, 2, 3, 0, 0, 0, 0);
-    SDLTest_AssertCheck(surface == NULL, "Should detect pitch < width * bpp");
-    SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
-                        "Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
-
-    surface = SDL_CreateRGBSurfaceWithFormatFrom(buf, 13, 1, 2, 4, SDL_PIXELFORMAT_INDEX2LSB);
-    SDLTest_AssertCheck(surface != NULL, "13px * 2 bits per px fits in 4 bytes: %s",
-                        surface != NULL ? "(success)" : SDL_GetError());
-    SDL_FreeSurface(surface);
-    surface = SDL_CreateRGBSurfaceFrom(buf, 13, 1, 2, 4, 0, 0, 0, 0);
-    SDLTest_AssertCheck(surface != NULL, "13px * 2 bits per px fits in 4 bytes: %s",
-                        surface != NULL ? "(success)" : SDL_GetError());
-    SDL_FreeSurface(surface);
-
     /* SDL_PIXELFORMAT_INDEX1* needs 1 byte per 8 pixels. */
     surface = SDL_CreateRGBSurfaceWithFormatFrom(buf, 16, 1, 1, 2, SDL_PIXELFORMAT_INDEX1LSB);
     SDLTest_AssertCheck(surface != NULL, "16px * 1 bit per px fits in 2 bytes: %s",
@@ -765,26 +737,19 @@ int surface_testOverflow(void *arg)
                         "Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
 
     if (sizeof(size_t) == 4 && sizeof(int) >= 4) {
-        SDL_ClearError();
         expectedError = "Out of memory";
-        /* 0x5555'5555 * 3bpp = 0xffff'ffff which fits in size_t, but adding
-         * alignment padding makes it overflow */
-        surface = SDL_CreateRGBSurfaceWithFormat(0, 0x55555555, 1, 24, SDL_PIXELFORMAT_RGB24);
+        surface = SDL_CreateRGBSurfaceWithFormat(0, SDL_MAX_SINT32, 1, 8, SDL_PIXELFORMAT_INDEX8);
         SDLTest_AssertCheck(surface == NULL, "Should detect overflow in width + alignment");
         SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
                             "Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
-        SDL_ClearError();
-        /* 0x4000'0000 * 4bpp = 0x1'0000'0000 which (just) overflows */
-        surface = SDL_CreateRGBSurfaceWithFormat(0, 0x40000000, 1, 32, SDL_PIXELFORMAT_ARGB8888);
+        surface = SDL_CreateRGBSurfaceWithFormat(0, SDL_MAX_SINT32 / 2, 1, 32, SDL_PIXELFORMAT_ARGB8888);
         SDLTest_AssertCheck(surface == NULL, "Should detect overflow in width * bytes per pixel");
         SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
                             "Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
-        SDL_ClearError();
         surface = SDL_CreateRGBSurfaceWithFormat(0, (1 << 29) - 1, (1 << 29) - 1, 8, SDL_PIXELFORMAT_INDEX8);
         SDLTest_AssertCheck(surface == NULL, "Should detect overflow in width * height");
         SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
                             "Expected \"%s\", got \"%s\"", expectedError, SDL_GetError());
-        SDL_ClearError();
         surface = SDL_CreateRGBSurfaceWithFormat(0, (1 << 15) + 1, (1 << 15) + 1, 32, SDL_PIXELFORMAT_ARGB8888);
         SDLTest_AssertCheck(surface == NULL, "Should detect overflow in width * height * bytes per pixel");
         SDLTest_AssertCheck(SDL_strcmp(SDL_GetError(), expectedError) == 0,
diff --git a/libs/SDL2/test/testautomation_timer.c b/libs/SDL2/test/testautomation_timer.c
index a7160e76c05e73bffa47af306ef3cb841e95a2c4..1002a36eba79cc6388fc78d17c3cbdfd2283f2bf 100644
--- a/libs/SDL2/test/testautomation_timer.c
+++ b/libs/SDL2/test/testautomation_timer.c
@@ -94,10 +94,7 @@ int timer_delayAndGetTicks(void *arg)
     SDLTest_AssertCheck(result2 > 0, "Check result value, expected: >0, got: %" SDL_PRIu32, result2);
     difference = result2 - result;
     SDLTest_AssertCheck(difference > (testDelay - marginOfError), "Check difference, expected: >%" SDL_PRIu32 ", got: %" SDL_PRIu32, testDelay - marginOfError, difference);
-#if 0
-    /* Disabled because this might fail on non-interactive systems. Moved to testtimer. */
     SDLTest_AssertCheck(difference < (testDelay + marginOfError), "Check difference, expected: <%" SDL_PRIu32 ", got: %" SDL_PRIu32, testDelay + marginOfError, difference);
-#endif
 
     return TEST_COMPLETED;
 }
diff --git a/libs/SDL2/test/testautomation_video.c b/libs/SDL2/test/testautomation_video.c
index dd8f1c5c25b85a6278b30ec40d367cb15807e9e3..aa9e7b92b360ede7df22884aa60db0c1823582f8 100644
--- a/libs/SDL2/test/testautomation_video.c
+++ b/libs/SDL2/test/testautomation_video.c
@@ -28,7 +28,6 @@ SDL_Window *_createVideoSuiteTestWindow(const char *title)
     SDL_Window *window;
     int x, y, w, h;
     SDL_WindowFlags flags;
-    SDL_bool needs_renderer = SDL_FALSE;
 
     /* Standard window */
     x = SDLTest_RandomIntegerInRange(1, 100);
@@ -41,35 +40,6 @@ SDL_Window *_createVideoSuiteTestWindow(const char *title)
     SDLTest_AssertPass("Call to SDL_CreateWindow('Title',%d,%d,%d,%d,%d)", x, y, w, h, flags);
     SDLTest_AssertCheck(window != NULL, "Validate that returned window struct is not NULL");
 
-    /* Wayland and XWayland windows require that a frame be presented before they are fully mapped and visible onscreen.
-     * This is required for the mouse/keyboard grab tests to pass.
-     */
-    if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
-        needs_renderer = SDL_TRUE;
-    } else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
-        /* Try to detect if the x11 driver is running under XWayland */
-        const char *session_type = SDL_getenv("XDG_SESSION_TYPE");
-        if (session_type && SDL_strcasecmp(session_type, "wayland") == 0) {
-            needs_renderer = SDL_TRUE;
-        }
-    }
-
-    if (needs_renderer) {
-        SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
-        if (renderer) {
-            SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
-            SDL_RenderClear(renderer);
-            SDL_RenderPresent(renderer);
-
-            /* Some desktops don't display the window immediately after presentation,
-             * so delay to give the window time to actually appear on the desktop.
-             */
-            SDL_Delay(100);
-        } else {
-            SDLTest_Log("Unable to create a renderer, some tests may fail on Wayland/XWayland");
-        }
-    }
-
     return window;
 }
 
@@ -78,7 +48,7 @@ SDL_Window *_createVideoSuiteTestWindow(const char *title)
  */
 void _destroyVideoSuiteTestWindow(SDL_Window *window)
 {
-    if (window) {
+    if (window != NULL) {
         SDL_DestroyWindow(window);
         window = NULL;
         SDLTest_AssertPass("Call to SDL_DestroyWindow()");
@@ -308,8 +278,6 @@ int video_createWindowVariousFlags(void *arg)
             break;
         case 2:
             flags = SDL_WINDOW_OPENGL;
-            /* Skip - not every video driver supports OpenGL; comment out next line to run test */
-            continue;
             break;
         case 3:
             flags = SDL_WINDOW_SHOWN;
@@ -608,7 +576,7 @@ int video_getWindowDisplayMode(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (window) {
+    if (window != NULL) {
         result = SDL_GetWindowDisplayMode(window, &mode);
         SDLTest_AssertPass("Call to SDL_GetWindowDisplayMode()");
         SDLTest_AssertCheck(result == 0, "Validate result value; expected: 0, got: %d", result);
@@ -702,7 +670,7 @@ video_getWindowGammaRamp(void *arg)
 
   /* Call against new test window */
   window = _createVideoSuiteTestWindow(title);
-  if (!window) return TEST_ABORTED;
+  if (window == NULL) return TEST_ABORTED;
 
   /* Retrieve no channel */
   result = SDL_GetWindowGammaRamp(window, NULL, NULL, NULL);
@@ -852,33 +820,13 @@ int video_getSetWindowGrab(void *arg)
     const char *title = "video_getSetWindowGrab Test Window";
     SDL_Window *window;
     SDL_bool originalMouseState, originalKeyboardState;
-    SDL_bool hasFocusGained = SDL_FALSE;
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
-    /* Need to raise the window to have and SDL_EVENT_WINDOW_FOCUS_GAINED,
-     * so that the window gets the flags SDL_WINDOW_INPUT_FOCUS,
-     * so that it can be "grabbed" */
-    SDL_RaiseWindow(window);
-
-    {
-        SDL_Event evt;
-        SDL_zero(evt);
-        while (SDL_PollEvent(&evt)) {
-            if (evt.type == SDL_WINDOWEVENT) {
-                if (evt.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
-                    hasFocusGained = SDL_TRUE;
-                }
-            }
-        }
-    }
-
-    SDLTest_AssertCheck(hasFocusGained == SDL_TRUE, "Expected window with focus");
-
     /* Get state */
     originalMouseState = SDL_GetWindowMouseGrab(window);
     SDLTest_AssertPass("Call to SDL_GetWindowMouseGrab()");
@@ -1019,7 +967,7 @@ int video_getWindowId(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
@@ -1074,7 +1022,7 @@ int video_getWindowPixelFormat(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
@@ -1137,58 +1085,28 @@ int video_getSetWindowPosition(void *arg)
 {
     const char *title = "video_getSetWindowPosition Test Window";
     SDL_Window *window;
-    int maxxVariation, maxyVariation;
     int xVariation, yVariation;
     int referenceX, referenceY;
     int currentX, currentY;
     int desiredX, desiredY;
-    SDL_Rect display_bounds;
-
-    if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
-        SDLTest_Log("Skipping test: wayland does not support window positioning");
-        return TEST_SKIPPED;
-    }
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
-    if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
-        /* The X11 server allows arbitrary window placement, but compositing
-         * window managers such as GNOME and KDE force windows to be within
-         * desktop bounds.
-         */
-        maxxVariation = 2;
-        maxyVariation = 2;
-
-        SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(window), &display_bounds);
-    } else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "cocoa") == 0) {
-        /* Platform doesn't allow windows with negative Y desktop bounds */
-        maxxVariation = 4;
-        maxyVariation = 3;
-
-        SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(window), &display_bounds);
-    } else {
-        /* Platform allows windows to be placed out of bounds */
-        maxxVariation = 4;
-        maxyVariation = 4;
-
-        SDL_GetDisplayBounds(SDL_GetWindowDisplayIndex(window), &display_bounds);
-    }
-
-    for (xVariation = 0; xVariation < maxxVariation; xVariation++) {
-        for (yVariation = 0; yVariation < maxyVariation; yVariation++) {
+    for (xVariation = 0; xVariation < 4; xVariation++) {
+        for (yVariation = 0; yVariation < 4; yVariation++) {
             switch (xVariation) {
             default:
             case 0:
                 /* Zero X Position */
-                desiredX = display_bounds.x > 0 ? display_bounds.x : 0;
+                desiredX = 0;
                 break;
             case 1:
                 /* Random X position inside screen */
-                desiredX = SDLTest_RandomIntegerInRange(display_bounds.x + 1, display_bounds.x + 100);
+                desiredX = SDLTest_RandomIntegerInRange(1, 100);
                 break;
             case 2:
                 /* Random X position outside screen (positive) */
@@ -1203,15 +1121,15 @@ int video_getSetWindowPosition(void *arg)
             switch (yVariation) {
             default:
             case 0:
-                /* Zero Y Position */
-                desiredY = display_bounds.y > 0 ? display_bounds.y : 0;
+                /* Zero X Position */
+                desiredY = 0;
                 break;
             case 1:
-                /* Random Y position inside screen */
-                desiredY = SDLTest_RandomIntegerInRange(display_bounds.y + 1, display_bounds.y + 100);
+                /* Random X position inside screen */
+                desiredY = SDLTest_RandomIntegerInRange(1, 100);
                 break;
             case 2:
-                /* Random Y position outside screen (positive) */
+                /* Random X position outside screen (positive) */
                 desiredY = SDLTest_RandomIntegerInRange(10000, 11000);
                 break;
             case 3:
@@ -1337,7 +1255,7 @@ int video_getSetWindowSize(void *arg)
     int desiredW, desiredH;
 
     /* Get display bounds for size range */
-    result = SDL_GetDisplayUsableBounds(0, &display);
+    result = SDL_GetDisplayBounds(0, &display);
     SDLTest_AssertPass("SDL_GetDisplayBounds()");
     SDLTest_AssertCheck(result == 0, "Verify return value; expected: 0, got: %d", result);
     if (result != 0) {
@@ -1346,20 +1264,19 @@ int video_getSetWindowSize(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
-    if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "windows") == 0 ||
-        SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
-        /* Platform clips window size to screen size */
-        maxwVariation = 4;
-        maxhVariation = 4;
-    } else {
-        /* Platform allows window size >= screen size */
-        maxwVariation = 5;
-        maxhVariation = 5;
-    }
+#ifdef __WIN32__
+    /* Platform clips window size to screen size */
+    maxwVariation = 4;
+    maxhVariation = 4;
+#else
+    /* Platform allows window size >= screen size */
+    maxwVariation = 5;
+    maxhVariation = 5;
+#endif
 
     for (wVariation = 0; wVariation < maxwVariation; wVariation++) {
         for (hVariation = 0; hVariation < maxhVariation; hVariation++) {
@@ -1438,6 +1355,7 @@ int video_getSetWindowSize(void *arg)
                 }
             }
 
+
             /* Get just width */
             currentW = desiredW + 1;
             SDL_GetWindowSize(window, &currentW, NULL);
@@ -1529,7 +1447,7 @@ int video_getSetWindowMinimumSize(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
@@ -1671,7 +1589,7 @@ int video_getSetWindowMaximumSize(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
@@ -1809,30 +1727,30 @@ int video_getSetWindowData(void *arg)
 
     /* Call against new test window */
     window = _createVideoSuiteTestWindow(title);
-    if (!window) {
+    if (window == NULL) {
         return TEST_ABORTED;
     }
 
     /* Create testdata */
     datasize = SDLTest_RandomIntegerInRange(1, 32);
     referenceUserdata = SDLTest_RandomAsciiStringOfSize(datasize);
-    if (!referenceUserdata) {
+    if (referenceUserdata == NULL) {
         returnValue = TEST_ABORTED;
         goto cleanup;
     }
     userdata = SDL_strdup(referenceUserdata);
-    if (!userdata) {
+    if (userdata == NULL) {
         returnValue = TEST_ABORTED;
         goto cleanup;
     }
     datasize = SDLTest_RandomIntegerInRange(1, 32);
     referenceUserdata2 = SDLTest_RandomAsciiStringOfSize(datasize);
-    if (!referenceUserdata2) {
+    if (referenceUserdata2 == NULL) {
         returnValue = TEST_ABORTED;
         goto cleanup;
     }
     userdata2 = SDL_strdup(referenceUserdata2);
-    if (!userdata2) {
+    if (userdata2 == NULL) {
         returnValue = TEST_ABORTED;
         goto cleanup;
     }
@@ -2017,11 +1935,6 @@ int video_setWindowCenteredOnDisplay(void *arg)
     SDL_Rect display0, display1;
 
     displayNum = SDL_GetNumVideoDisplays();
-    SDLTest_AssertPass("SDL_GetNumVideoDisplays()");
-    SDLTest_AssertCheck(displayNum >= 1, "Validate result (current: %d, expected >= 1)", displayNum);
-    if (displayNum <= 0) {
-        return TEST_ABORTED;
-    }
 
     /* Get display bounds */
     result = SDL_GetDisplayBounds(0 % displayNum, &display0);
@@ -2046,7 +1959,6 @@ int video_setWindowCenteredOnDisplay(void *arg)
             int currentDisplay;
             int expectedDisplay;
             SDL_Rect expectedDisplayRect;
-            SDL_bool video_driver_is_wayland = SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0;
 
             /* xVariation is the display we start on */
             expectedDisplay = xVariation % displayNum;
@@ -2058,46 +1970,20 @@ int video_setWindowCenteredOnDisplay(void *arg)
             expectedX = (expectedDisplayRect.x + ((expectedDisplayRect.w - w) / 2));
             expectedY = (expectedDisplayRect.y + ((expectedDisplayRect.h - h) / 2));
 
-            window = SDL_CreateWindow(title, x, y, w, h, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_BORDERLESS);
+            window = SDL_CreateWindow(title, x, y, w, h, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
             SDLTest_AssertPass("Call to SDL_CreateWindow('Title',%d,%d,%d,%d,SHOWN)", x, y, w, h);
             SDLTest_AssertCheck(window != NULL, "Validate that returned window struct is not NULL");
 
-            /* Wayland windows require that a frame be presented before they are fully mapped and visible onscreen. */
-            if (video_driver_is_wayland) {
-                SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
-
-                if (renderer) {
-                    SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
-                    SDL_RenderClear(renderer);
-                    SDL_RenderPresent(renderer);
-
-                    /* Some desktops don't display the window immediately after presentation,
-                     * so delay to give the window time to actually appear on the desktop.
-                     */
-                    SDL_Delay(100);
-                } else {
-                    SDLTest_Log("Unable to create a renderer, tests may fail under Wayland");
-                }
-            }
-
             /* Check the window is centered on the requested display */
             currentDisplay = SDL_GetWindowDisplayIndex(window);
             SDL_GetWindowSize(window, &currentW, &currentH);
             SDL_GetWindowPosition(window, &currentX, &currentY);
 
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
-            } else {
-                SDLTest_Log("Skipping display index validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
             SDLTest_AssertCheck(currentW == w, "Validate width (current: %d, expected: %d)", currentW, w);
             SDLTest_AssertCheck(currentH == h, "Validate height (current: %d, expected: %d)", currentH, h);
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentX == expectedX, "Validate x (current: %d, expected: %d)", currentX, expectedX);
-                SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
-            } else {
-                SDLTest_Log("Skipping window position validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentX == expectedX, "Validate x (current: %d, expected: %d)", currentX, expectedX);
+            SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
 
             /* Enter fullscreen desktop */
             result = SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
@@ -2108,19 +1994,11 @@ int video_setWindowCenteredOnDisplay(void *arg)
             SDL_GetWindowSize(window, &currentW, &currentH);
             SDL_GetWindowPosition(window, &currentX, &currentY);
 
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
-            } else {
-                SDLTest_Log("Skipping display index validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
             SDLTest_AssertCheck(currentW == expectedDisplayRect.w, "Validate width (current: %d, expected: %d)", currentW, expectedDisplayRect.w);
             SDLTest_AssertCheck(currentH == expectedDisplayRect.h, "Validate height (current: %d, expected: %d)", currentH, expectedDisplayRect.h);
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentX == expectedDisplayRect.x, "Validate x (current: %d, expected: %d)", currentX, expectedDisplayRect.x);
-                SDLTest_AssertCheck(currentY == expectedDisplayRect.y, "Validate y (current: %d, expected: %d)", currentY, expectedDisplayRect.y);
-            } else {
-                SDLTest_Log("Skipping window position validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentX == expectedDisplayRect.x, "Validate x (current: %d, expected: %d)", currentX, expectedDisplayRect.x);
+            SDLTest_AssertCheck(currentY == expectedDisplayRect.y, "Validate y (current: %d, expected: %d)", currentY, expectedDisplayRect.y);
 
             /* Leave fullscreen desktop */
             result = SDL_SetWindowFullscreen(window, 0);
@@ -2131,19 +2009,11 @@ int video_setWindowCenteredOnDisplay(void *arg)
             SDL_GetWindowSize(window, &currentW, &currentH);
             SDL_GetWindowPosition(window, &currentX, &currentY);
 
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
-            } else {
-                SDLTest_Log("Skipping display index validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
             SDLTest_AssertCheck(currentW == w, "Validate width (current: %d, expected: %d)", currentW, w);
             SDLTest_AssertCheck(currentH == h, "Validate height (current: %d, expected: %d)", currentH, h);
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentX == expectedX, "Validate x (current: %d, expected: %d)", currentX, expectedX);
-                SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
-            } else {
-                SDLTest_Log("Skipping window position validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentX == expectedX, "Validate x (current: %d, expected: %d)", currentX, expectedX);
+            SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
 
             /* Center on display yVariation, and check window properties */
 
@@ -2159,19 +2029,11 @@ int video_setWindowCenteredOnDisplay(void *arg)
             SDL_GetWindowSize(window, &currentW, &currentH);
             SDL_GetWindowPosition(window, &currentX, &currentY);
 
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
-            } else {
-                SDLTest_Log("Skipping display index validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentDisplay == expectedDisplay, "Validate display index (current: %d, expected: %d)", currentDisplay, expectedDisplay);
             SDLTest_AssertCheck(currentW == w, "Validate width (current: %d, expected: %d)", currentW, w);
             SDLTest_AssertCheck(currentH == h, "Validate height (current: %d, expected: %d)", currentH, h);
-            if (!video_driver_is_wayland) {
-                SDLTest_AssertCheck(currentX == expectedX, "Validate x (current: %d, expected: %d)", currentX, expectedX);
-                SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
-            } else {
-                SDLTest_Log("Skipping window position validation: Wayland driver does not support window positioning");
-            }
+            SDLTest_AssertCheck(currentX == expectedX, "Validate x (current: %d, expected: %d)", currentX, expectedX);
+            SDLTest_AssertCheck(currentY == expectedY, "Validate y (current: %d, expected: %d)", currentY, expectedY);
 
             /* Clean up */
             _destroyVideoSuiteTestWindow(window);
diff --git a/libs/SDL2/test/testbounds.c b/libs/SDL2/test/testbounds.c
index 9bd73ac962d18dbf97e1a750f975401ba1aa1f81..42213f5464b899db0aa4c24a7572059726cd4156 100644
--- a/libs/SDL2/test/testbounds.c
+++ b/libs/SDL2/test/testbounds.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testcustomcursor.c b/libs/SDL2/test/testcustomcursor.c
index aec3c78aa3e2b44971f3af7117cb710d521375b4..dc1c3718cc8618e9b70facc4b3d544895e678bd0 100644
--- a/libs/SDL2/test/testcustomcursor.c
+++ b/libs/SDL2/test/testcustomcursor.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -242,7 +242,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
diff --git a/libs/SDL2/test/testdisplayinfo.c b/libs/SDL2/test/testdisplayinfo.c
index 9740ab174287834a84f0edc583c6ce2d67705528..66cc5d875a4207164c9a5c3470df885ad2a2b7e8 100644
--- a/libs/SDL2/test/testdisplayinfo.c
+++ b/libs/SDL2/test/testdisplayinfo.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -20,7 +20,7 @@
 static void
 print_mode(const char *prefix, const SDL_DisplayMode *mode)
 {
-    if (!mode) {
+    if (mode == NULL) {
         return;
     }
 
diff --git a/libs/SDL2/test/testdraw2.c b/libs/SDL2/test/testdraw2.c
index 43aa1843b18160cfe490614cae9ec63be84ee88e..f660c284584a15abf7e2b9ea119f50cefd6906d0 100644
--- a/libs/SDL2/test/testdraw2.c
+++ b/libs/SDL2/test/testdraw2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -227,7 +227,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
diff --git a/libs/SDL2/test/testdrawchessboard.c b/libs/SDL2/test/testdrawchessboard.c
index 4dffe06bd764ac01b1bec5c03eb2e3669669e781..8ff21a4c4ee5e619cff05c71de2b22700518b504 100644
--- a/libs/SDL2/test/testdrawchessboard.c
+++ b/libs/SDL2/test/testdrawchessboard.c
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+   Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
@@ -50,7 +50,6 @@ void DrawChessBoard()
             SDL_RenderFillRect(renderer, &rect);
         }
     }
-    SDL_RenderPresent(renderer);
 }
 
 void loop()
@@ -107,13 +106,13 @@ int main(int argc, char *argv[])
 
     /* Create window and renderer for given surface */
     window = SDL_CreateWindow("Chess Board", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_RESIZABLE);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Window creation fail : %s\n", SDL_GetError());
         return 1;
     }
     surface = SDL_GetWindowSurface(window);
     renderer = SDL_CreateSoftwareRenderer(surface);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Render creation for surface fail : %s\n", SDL_GetError());
         return 1;
     }
diff --git a/libs/SDL2/test/testdropfile.c b/libs/SDL2/test/testdropfile.c
index 2184f062eed782593db2aafaa4d2122142953faa..b80633365603688e07757835c21c376ed88fb9bb 100644
--- a/libs/SDL2/test/testdropfile.c
+++ b/libs/SDL2/test/testdropfile.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -35,7 +35,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testerror.c b/libs/SDL2/test/testerror.c
index 25874d1ea78f75d3e181a1c352bac77c63433077..f3f11b661736b83c7a5a007b13b599970424d79c 100644
--- a/libs/SDL2/test/testerror.c
+++ b/libs/SDL2/test/testerror.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -65,7 +65,7 @@ int main(int argc, char *argv[])
 
     alive = 1;
     thread = SDL_CreateThread(ThreadFunc, NULL, "#1");
-    if (!thread) {
+    if (thread == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError());
         quit(1);
     }
diff --git a/libs/SDL2/test/testevdev.c b/libs/SDL2/test/testevdev.c
index 67124ae0f461e3c133b6a55678898b8eac1c3aef..e61579158748b06d5dadb6811175b7f20a82ecf1 100644
--- a/libs/SDL2/test/testevdev.c
+++ b/libs/SDL2/test/testevdev.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
   Copyright (C) 2020-2022 Collabora Ltd.
 
   This software is provided 'as-is', without any express or implied
@@ -18,7 +18,7 @@
 
 static int run_test(void);
 
-#if defined(HAVE_LIBUDEV_H) || defined(SDL_JOYSTICK_LINUX)
+#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
 
 #include <stdint.h>
 
diff --git a/libs/SDL2/test/testfile.c b/libs/SDL2/test/testfile.c
index a35da02bd714fbbd02f549443d0907ae2abb2263..40d52ca22b13e81bbb1b3377bcf415b4b56440c8 100644
--- a/libs/SDL2/test/testfile.c
+++ b/libs/SDL2/test/testfile.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -107,25 +107,25 @@ int main(int argc, char *argv[])
         RWOP_ERR_QUIT(rwops);
     }
     rwops = SDL_RWFromFile(FBASENAME2, "wb");
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     rwops->close(rwops);
     unlink(FBASENAME2);
     rwops = SDL_RWFromFile(FBASENAME2, "wb+");
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     rwops->close(rwops);
     unlink(FBASENAME2);
     rwops = SDL_RWFromFile(FBASENAME2, "ab");
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     rwops->close(rwops);
     unlink(FBASENAME2);
     rwops = SDL_RWFromFile(FBASENAME2, "ab+");
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     rwops->close(rwops);
@@ -136,7 +136,7 @@ int main(int argc, char *argv[])
                 test : w mode, r mode, w+ mode
      */
     rwops = SDL_RWFromFile(FBASENAME1, "wb"); /* write only */
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     if (1 != rwops->write(rwops, "1234567890", 10, 1)) {
@@ -158,7 +158,7 @@ int main(int argc, char *argv[])
     rwops->close(rwops);
 
     rwops = SDL_RWFromFile(FBASENAME1, "rb"); /* read mode, file must exists */
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     if (0 != rwops->seek(rwops, 0L, RW_SEEK_SET)) {
@@ -196,7 +196,7 @@ int main(int argc, char *argv[])
 
     /* test 3: same with w+ mode */
     rwops = SDL_RWFromFile(FBASENAME1, "wb+"); /* write + read + truncation */
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     if (1 != rwops->write(rwops, "1234567890", 10, 1)) {
@@ -247,7 +247,7 @@ int main(int argc, char *argv[])
 
     /* test 4: same in r+ mode */
     rwops = SDL_RWFromFile(FBASENAME1, "rb+"); /* write + read + file must exists, no truncation */
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     if (1 != rwops->write(rwops, "1234567890", 10, 1)) {
@@ -298,7 +298,7 @@ int main(int argc, char *argv[])
 
     /* test5 : append mode */
     rwops = SDL_RWFromFile(FBASENAME1, "ab+"); /* write + read + append */
-    if (!rwops) {
+    if (rwops == NULL) {
         RWOP_ERR_QUIT(rwops);
     }
     if (1 != rwops->write(rwops, "1234567890", 10, 1)) {
diff --git a/libs/SDL2/test/testfilesystem.c b/libs/SDL2/test/testfilesystem.c
index af0bd9f05a38189296ad3f4a8dbe17a129773064..f452d7761ff2908b1c2f10ce85d33a618d40a021 100644
--- a/libs/SDL2/test/testfilesystem.c
+++ b/libs/SDL2/test/testfilesystem.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -28,7 +28,7 @@ int main(int argc, char *argv[])
     }
 
     base_path = SDL_GetBasePath();
-    if (!base_path) {
+    if (base_path == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find base path: %s\n",
                      SDL_GetError());
     } else {
@@ -37,7 +37,7 @@ int main(int argc, char *argv[])
     }
 
     pref_path = SDL_GetPrefPath("libsdl", "test_filesystem");
-    if (!pref_path) {
+    if (pref_path == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path: %s\n",
                      SDL_GetError());
     } else {
@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
     }
 
     pref_path = SDL_GetPrefPath(NULL, "test_filesystem");
-    if (!pref_path) {
+    if (pref_path == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path without organization: %s\n",
                      SDL_GetError());
     } else {
diff --git a/libs/SDL2/test/testfilesystem_pre.c b/libs/SDL2/test/testfilesystem_pre.c
index 11615abd281f53417eeeae9441d663477492f773..dba8b51fb67545b52f2fa1bd45264632d797c0bd 100644
--- a/libs/SDL2/test/testfilesystem_pre.c
+++ b/libs/SDL2/test/testfilesystem_pre.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testgamecontroller.c b/libs/SDL2/test/testgamecontroller.c
index 52d3b2d853ba3085770633391dd0cfc6c1ecb560..e2bdebdec5fda45b7ae5d635d8d47ce60577ffec 100644
--- a/libs/SDL2/test/testgamecontroller.c
+++ b/libs/SDL2/test/testgamecontroller.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -109,7 +109,7 @@ static SDL_GameControllerButton virtual_button_active = SDL_CONTROLLER_BUTTON_IN
 
 static void UpdateWindowTitle()
 {
-    if (!window) {
+    if (window == NULL) {
         return;
     }
 
@@ -201,13 +201,13 @@ static void AddController(int device_index, SDL_bool verbose)
     }
 
     controller = SDL_GameControllerOpen(device_index);
-    if (!controller) {
+    if (controller == NULL) {
         SDL_Log("Couldn't open controller: %s\n", SDL_GetError());
         return;
     }
 
     controllers = (SDL_GameController **)SDL_realloc(gamecontrollers, (num_controllers + 1) * sizeof(*controllers));
-    if (!controllers) {
+    if (controllers == NULL) {
         SDL_GameControllerClose(controller);
         return;
     }
@@ -221,7 +221,6 @@ static void AddController(int device_index, SDL_bool verbose)
         const char *name = SDL_GameControllerName(gamecontroller);
         const char *path = SDL_GameControllerPath(gamecontroller);
         SDL_Log("Opened game controller %s%s%s\n", name, path ? ", " : "", path ? path : "");
-        SDL_Log("Mapping: %s\n", SDL_GameControllerMapping(gamecontroller));
     }
 
     firmware_version = SDL_GameControllerGetFirmwareVersion(gamecontroller);
@@ -414,7 +413,7 @@ static void OpenVirtualController()
         SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
     } else {
         virtual_joystick = SDL_JoystickOpen(virtual_index);
-        if (!virtual_joystick) {
+        if (virtual_joystick == NULL) {
             SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
         }
     }
@@ -625,8 +624,7 @@ void loop(void *arg)
             if (event.type == SDL_CONTROLLERBUTTONDOWN) {
                 SetController(event.cbutton.which);
             }
-            SDL_Log("Controller %" SDL_PRIs32 " button %s %s\n", event.cbutton.which, SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button),
-                    event.cbutton.state ? "pressed" : "released");
+            SDL_Log("Controller %" SDL_PRIs32 " button %s %s\n", event.cbutton.which, SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button), event.cbutton.state ? "pressed" : "released");
 
             /* Cycle PS5 trigger effects when the microphone button is pressed */
             if (event.type == SDL_CONTROLLERBUTTONDOWN &&
@@ -898,13 +896,13 @@ int main(int argc, char *argv[])
     window = SDL_CreateWindow("Game Controller Test", SDL_WINDOWPOS_CENTERED,
                               SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
                               SCREEN_HEIGHT, 0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
         return 2;
     }
 
     screen = SDL_CreateRenderer(window, -1, 0);
-    if (!screen) {
+    if (screen == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
         SDL_DestroyWindow(window);
         return 2;
@@ -922,7 +920,7 @@ int main(int argc, char *argv[])
     button_texture = LoadTexture(screen, "button.bmp", SDL_TRUE, NULL, NULL);
     axis_texture = LoadTexture(screen, "axis.bmp", SDL_TRUE, NULL, NULL);
 
-    if (!background_front || !background_back || !button_texture || !axis_texture) {
+    if (background_front == NULL || background_back == NULL || button_texture == NULL || axis_texture == NULL) {
         SDL_DestroyRenderer(screen);
         SDL_DestroyWindow(window);
         return 2;
diff --git a/libs/SDL2/test/testgeometry.c b/libs/SDL2/test/testgeometry.c
index e09c38332f8b6fb8e23b6cf4a90624f77784272a..9742a14162a79937010dc8315e07b993c4cccfeb 100644
--- a/libs/SDL2/test/testgeometry.c
+++ b/libs/SDL2/test/testgeometry.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -172,7 +172,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
@@ -216,7 +216,7 @@ int main(int argc, char *argv[])
     /* Create the windows, initialize the renderers, and load the textures */
     sprites =
         (SDL_Texture **)SDL_malloc(state->num_windows * sizeof(*sprites));
-    if (!sprites) {
+    if (sprites == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
         quit(2);
     }
diff --git a/libs/SDL2/test/testgesture.c b/libs/SDL2/test/testgesture.c
index 9870b6059c43d1072902db7bce5fc90fe8010302..f37635f3319d38f4c67b583c1ff6556ebeeb9060 100644
--- a/libs/SDL2/test/testgesture.c
+++ b/libs/SDL2/test/testgesture.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -131,7 +131,7 @@ DrawScreen(SDL_Window *window)
     SDL_Surface *screen = SDL_GetWindowSurface(window);
     int i;
 
-    if (!screen) {
+    if (screen == NULL) {
         return;
     }
 
@@ -251,7 +251,7 @@ loop(void)
             break;
 
         case SDL_DOLLARRECORD:
-            SDL_Log("Recorded gesture: %" SDL_PRIs64, event.dgesture.gestureId);
+            SDL_Log("Recorded gesture: %" SDL_PRIs64 "", event.dgesture.gestureId);
             break;
         }
     }
@@ -272,7 +272,7 @@ loop(void)
 int main(int argc, char *argv[])
 {
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testgl2.c b/libs/SDL2/test/testgl2.c
index d14ae1675183b466eddf201bb571c826c2aa2985..b58798c32295ee8fd08e591782055666a6d33f12 100644
--- a/libs/SDL2/test/testgl2.c
+++ b/libs/SDL2/test/testgl2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -40,11 +40,11 @@ static GL_Context ctx;
 
 static int LoadContext(GL_Context *data)
 {
-#ifdef SDL_VIDEO_DRIVER_UIKIT
+#if SDL_VIDEO_DRIVER_UIKIT
 #define __SDL_NOGETPROCADDR__
-#elif defined(SDL_VIDEO_DRIVER_ANDROID)
+#elif SDL_VIDEO_DRIVER_ANDROID
 #define __SDL_NOGETPROCADDR__
-#elif defined(SDL_VIDEO_DRIVER_PANDORA)
+#elif SDL_VIDEO_DRIVER_PANDORA
 #define __SDL_NOGETPROCADDR__
 #endif
 
@@ -205,11 +205,6 @@ Render()
     ctx.glRotatef(5.0, 1.0, 1.0, 1.0);
 }
 
-static void LogSwapInterval(void)
-{
-    SDL_Log("Swap Interval : %d\n", SDL_GL_GetSwapInterval());
-}
-
 int main(int argc, char *argv[])
 {
     int fsaa, accel;
@@ -231,7 +226,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
@@ -305,9 +300,7 @@ int main(int argc, char *argv[])
 
     SDL_GetCurrentDisplayMode(0, &mode);
     SDL_Log("Screen BPP    : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode.format));
-
-    LogSwapInterval();
-
+    SDL_Log("Swap Interval : %d\n", SDL_GL_GetSwapInterval());
     SDL_GetWindowSize(state->windows[0], &dw, &dh);
     SDL_Log("Window Size   : %d,%d\n", dw, dh);
     SDL_GL_GetDrawableSize(state->windows[0], &dw, &dh);
@@ -415,7 +408,6 @@ int main(int argc, char *argv[])
             SDL_GL_MakeCurrent(state->windows[i], context);
             if (update_swap_interval) {
                 SDL_GL_SetSwapInterval(swap_interval);
-                LogSwapInterval();
             }
             SDL_GL_GetDrawableSize(state->windows[i], &w, &h);
             ctx.glViewport(0, 0, w, h);
diff --git a/libs/SDL2/test/testgles.c b/libs/SDL2/test/testgles.c
index b1577cd8ef23b79f38c48721920aa078cdb01172..498dbce5c2e161c2c0919008766a2ec2942d69d0 100644
--- a/libs/SDL2/test/testgles.c
+++ b/libs/SDL2/test/testgles.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -34,7 +34,7 @@ quit(int rc)
 {
     int i;
 
-    if (context) {
+    if (context != NULL) {
         for (i = 0; i < state->num_windows; i++) {
             if (context[i]) {
                 SDL_GL_DeleteContext(context[i]);
@@ -114,7 +114,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
@@ -169,7 +169,7 @@ int main(int argc, char *argv[])
     }
 
     context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context));
-    if (!context) {
+    if (context == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
         quit(2);
     }
diff --git a/libs/SDL2/test/testgles2.c b/libs/SDL2/test/testgles2.c
index bafc524ef4be767ba1c6b533d566696668513492..656e5e6111104fa07d4151d0c2b7b2641989e9d5 100644
--- a/libs/SDL2/test/testgles2.c
+++ b/libs/SDL2/test/testgles2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -65,11 +65,11 @@ static GLES2_Context ctx;
 
 static int LoadContext(GLES2_Context *data)
 {
-#ifdef SDL_VIDEO_DRIVER_UIKIT
+#if SDL_VIDEO_DRIVER_UIKIT
 #define __SDL_NOGETPROCADDR__
-#elif defined(SDL_VIDEO_DRIVER_ANDROID)
+#elif SDL_VIDEO_DRIVER_ANDROID
 #define __SDL_NOGETPROCADDR__
-#elif defined(SDL_VIDEO_DRIVER_PANDORA)
+#elif SDL_VIDEO_DRIVER_PANDORA
 #define __SDL_NOGETPROCADDR__
 #endif
 
@@ -96,7 +96,7 @@ quit(int rc)
 {
     int i;
 
-    if (context) {
+    if (context != NULL) {
         for (i = 0; i < state->num_windows; i++) {
             if (context[i]) {
                 SDL_GL_DeleteContext(context[i]);
@@ -636,7 +636,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
@@ -696,7 +696,7 @@ int main(int argc, char *argv[])
     }
 
     context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context));
-    if (!context) {
+    if (context == NULL) {
         SDL_Log("Out of memory!\n");
         quit(2);
     }
@@ -893,9 +893,9 @@ int main(int argc, char *argv[])
         SDL_Log("%2.2f frames per second\n",
                 ((double)frames * 1000) / (now - then));
     }
-#if !defined(__ANDROID__) && !defined(__NACL__)
+#if !defined(__ANDROID__) && !defined(__NACL__)  
     quit(0);
-#endif
+#endif    
     return 0;
 }
 
diff --git a/libs/SDL2/test/testgles2_sdf.c b/libs/SDL2/test/testgles2_sdf.c
index 3b15f7298f0a77a07d859c88aea34192784aed42..91f49064a60802cfb98df1e5f88087704ea91c60 100644
--- a/libs/SDL2/test/testgles2_sdf.c
+++ b/libs/SDL2/test/testgles2_sdf.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -63,11 +63,11 @@ static GLES2_Context ctx;
 
 static int LoadContext(GLES2_Context *data)
 {
-#ifdef SDL_VIDEO_DRIVER_UIKIT
+#if SDL_VIDEO_DRIVER_UIKIT
 #define __SDL_NOGETPROCADDR__
-#elif defined(SDL_VIDEO_DRIVER_ANDROID)
+#elif SDL_VIDEO_DRIVER_ANDROID
 #define __SDL_NOGETPROCADDR__
-#elif defined(SDL_VIDEO_DRIVER_PANDORA)
+#elif SDL_VIDEO_DRIVER_PANDORA
 #define __SDL_NOGETPROCADDR__
 #endif
 
@@ -94,7 +94,7 @@ quit(int rc)
 {
     int i;
 
-    if (context) {
+    if (context != NULL) {
         for (i = 0; i < state->num_windows; i++) {
             if (context[i]) {
                 SDL_GL_DeleteContext(context[i]);
@@ -445,7 +445,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
@@ -502,7 +502,7 @@ int main(int argc, char *argv[])
     }
 
     context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context));
-    if (!context) {
+    if (context == NULL) {
         SDL_Log("Out of memory!\n");
         quit(2);
     }
@@ -543,17 +543,17 @@ int main(int argc, char *argv[])
 #if 1
         path = GetNearbyFilename(f);
 
-        if (!path) {
+        if (path == NULL) {
             path = SDL_strdup(f);
         }
 
-        if (!path) {
+        if (path == NULL) {
             SDL_Log("out of memory\n");
             exit(-1);
         }
 
         tmp = SDL_LoadBMP(path);
-        if (!tmp) {
+        if (tmp == NULL) {
             SDL_Log("missing image file: %s", path);
             exit(-1);
         } else {
diff --git a/libs/SDL2/test/testhaptic.c b/libs/SDL2/test/testhaptic.c
index 56602cafb43d8b1fe5a9c02af04f0f70df241b59..fa41863767a94e7444a48794bd80eaa9e0ee7e05 100644
--- a/libs/SDL2/test/testhaptic.c
+++ b/libs/SDL2/test/testhaptic.c
@@ -16,8 +16,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  */
 #include "SDL.h"
 
-#include <stdlib.h>
-
 #ifndef SDL_HAPTIC_DISABLED
 
 static SDL_Haptic *haptic;
@@ -71,7 +69,7 @@ int main(int argc, char **argv)
     SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics());
     if (SDL_NumHaptics() > 0) {
         /* We'll just use index or the first force feedback device found */
-        if (!name) {
+        if (name == NULL) {
             i = (index != -1) ? index : 0;
         }
         /* Try to find matching device */
@@ -90,7 +88,7 @@ int main(int argc, char **argv)
         }
 
         haptic = SDL_HapticOpen(i);
-        if (!haptic) {
+        if (haptic == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
                          SDL_GetError());
             return 1;
@@ -281,7 +279,7 @@ int main(int argc, char **argv)
     }
 
     /* Quit */
-    if (haptic) {
+    if (haptic != NULL) {
         SDL_HapticClose(haptic);
     }
     SDL_Quit();
diff --git a/libs/SDL2/test/testhittesting.c b/libs/SDL2/test/testhittesting.c
index 94c5ea9aea4b3ae5bab76fce7c1fa62cce92eaa2..92ddf8c42c69711285b094b6e7cd8b2e2af52eed 100644
--- a/libs/SDL2/test/testhittesting.c
+++ b/libs/SDL2/test/testhittesting.c
@@ -106,7 +106,7 @@ int main(int argc, char **argv)
                 if (e.key.keysym.sym == SDLK_ESCAPE) {
                     done = 1;
                 } else if (e.key.keysym.sym == SDLK_x) {
-                    if (!areas) {
+                    if (areas == NULL) {
                         areas = drag_areas;
                         numareas = SDL_arraysize(drag_areas);
                     } else {
diff --git a/libs/SDL2/test/testhotplug.c b/libs/SDL2/test/testhotplug.c
index aca1741d7c141818ab3960f447e813d4b054c698..1ac73a7fbb682bf75632d2f6bbf077b7b8f1cd1c 100644
--- a/libs/SDL2/test/testhotplug.c
+++ b/libs/SDL2/test/testhotplug.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -68,7 +68,7 @@ int main(int argc, char *argv[])
                 keepGoing = SDL_FALSE;
                 break;
             case SDL_JOYDEVICEADDED:
-                if (joystick) {
+                if (joystick != NULL) {
                     SDL_Log("Only one joystick supported by this test\n");
                 } else {
                     joystick = SDL_JoystickOpen(event.jdevice.which);
diff --git a/libs/SDL2/test/testiconv.c b/libs/SDL2/test/testiconv.c
index fcdd72892f198256290292f3b9c8c3062eb8b3cc..b2d13a6aa538165044d20aa2ca3c182dd4f53d19 100644
--- a/libs/SDL2/test/testiconv.c
+++ b/libs/SDL2/test/testiconv.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -61,7 +61,7 @@ int main(int argc, char *argv[])
 
     fname = GetResourceFilename(argc > 1 ? argv[1] : NULL, "utf8.txt");
     file = fopen(fname, "rb");
-    if (!file) {
+    if (file == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to open %s\n", fname);
         return 1;
     }
diff --git a/libs/SDL2/test/testime.c b/libs/SDL2/test/testime.c
index fb5756dcba58b7daf0637773ad6e7c6f2189040c..51f685b1eb4a4eaedfe8ee51d670646b386b220d 100644
--- a/libs/SDL2/test/testime.c
+++ b/libs/SDL2/test/testime.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -29,7 +29,7 @@
 #ifdef HAVE_SDL_TTF
 #ifdef __MACOSX__
 #define DEFAULT_FONT "/System/Library/Fonts/华文细黑.ttf"
-#elif defined(__WIN32__)
+#elif __WIN32__
 /* Some japanese font present on at least Windows 8.1. */
 #define DEFAULT_FONT "C:\\Windows\\Fonts\\yugothic.ttf"
 #else
@@ -97,7 +97,7 @@ static Uint8 validate_hex(const char *cp, size_t len, Uint32 *np)
         }
         n = (n << 4) | c;
     }
-    if (np) {
+    if (np != NULL) {
         *np = n;
     }
     return 1;
@@ -116,7 +116,7 @@ static int unifont_init(const char *fontname)
 
     /* Allocate memory for the glyph data so the file can be closed after initialization. */
     unifontGlyph = (struct UnifontGlyph *)SDL_malloc(unifontGlyphSize);
-    if (!unifontGlyph) {
+    if (unifontGlyph == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.\n", (int)(unifontGlyphSize + 1023) / 1024);
         return -1;
     }
@@ -124,20 +124,20 @@ static int unifont_init(const char *fontname)
 
     /* Allocate memory for texture pointers for all renderers. */
     unifontTexture = (SDL_Texture **)SDL_malloc(unifontTextureSize);
-    if (!unifontTexture) {
+    if (unifontTexture == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.\n", (int)(unifontTextureSize + 1023) / 1024);
         return -1;
     }
     SDL_memset(unifontTexture, 0, unifontTextureSize);
 
     filename = GetResourceFilename(NULL, fontname);
-    if (!filename) {
+    if (filename == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n");
         return -1;
     }
     hexFile = SDL_RWFromFile(filename, "rb");
     SDL_free(filename);
-    if (!hexFile) {
+    if (hexFile == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s\n", fontname);
         return -1;
     }
@@ -269,7 +269,7 @@ static int unifont_load_texture(Uint32 textureID)
     }
 
     textureRGBA = (Uint8 *)SDL_malloc(UNIFONT_TEXTURE_SIZE);
-    if (!textureRGBA) {
+    if (textureRGBA == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024);
         return -1;
     }
@@ -324,7 +324,7 @@ static Sint32 unifont_draw_glyph(Uint32 codepoint, int rendererID, SDL_Rect *dst
         }
     }
     texture = unifontTexture[UNIFONT_NUM_TEXTURES * rendererID + textureID];
-    if (texture) {
+    if (texture != NULL) {
         const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
         srcrect.x = cInTex % UNIFONT_GLYPHS_IN_ROW * 16;
         srcrect.y = cInTex / UNIFONT_GLYPHS_IN_ROW * 16;
@@ -338,12 +338,12 @@ static void unifont_cleanup()
     int i, j;
     for (i = 0; i < state->num_windows; ++i) {
         SDL_Renderer *renderer = state->renderers[i];
-        if (state->windows[i] == NULL || !renderer) {
+        if (state->windows[i] == NULL || renderer == NULL) {
             continue;
         }
         for (j = 0; j < UNIFONT_NUM_TEXTURES; j++) {
             SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + j];
-            if (tex) {
+            if (tex != NULL) {
                 SDL_DestroyTexture(tex);
             }
         }
@@ -530,7 +530,7 @@ void _Redraw(int rendererID)
         if (cursor) {
             char *p = utf8_advance(markedText, cursor);
             char c = 0;
-            if (!p) {
+            if (p == NULL) {
                 p = &markedText[SDL_strlen(markedText)];
             }
 
@@ -626,7 +626,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc; i++) {
@@ -660,7 +660,7 @@ int main(int argc, char *argv[])
     TTF_Init();
 
     font = TTF_OpenFont(fontname, DEFAULT_PTSIZE);
-    if (!font) {
+    if (font == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError());
         return -1;
     }
diff --git a/libs/SDL2/test/testintersections.c b/libs/SDL2/test/testintersections.c
index bb95fbe937fba37cc601b3eaee89f4c393691e13..f24d9fbf52ece7a61ee44a3aad92e13cbed177ab 100644
--- a/libs/SDL2/test/testintersections.c
+++ b/libs/SDL2/test/testintersections.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -289,7 +289,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
diff --git a/libs/SDL2/test/testjoystick.c b/libs/SDL2/test/testjoystick.c
index 38985804943f16abba680f8f40570927aab76a91..adb31dc14fe0ee7811c54b49675112a3e7d62134 100644
--- a/libs/SDL2/test/testjoystick.c
+++ b/libs/SDL2/test/testjoystick.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -117,7 +117,7 @@ void loop(void *arg)
 
         case SDL_JOYDEVICEADDED:
             SDL_Log("Joystick device %d added.\n", (int)event.jdevice.which);
-            if (!joystick) {
+            if (joystick == NULL) {
                 joystick = SDL_JoystickOpen(event.jdevice.which);
                 if (joystick) {
                     PrintJoystick(joystick);
@@ -296,13 +296,13 @@ int main(int argc, char *argv[])
     window = SDL_CreateWindow("Joystick Test", SDL_WINDOWPOS_CENTERED,
                               SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
                               SCREEN_HEIGHT, 0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
         return SDL_FALSE;
     }
 
     screen = SDL_CreateRenderer(window, -1, 0);
-    if (!screen) {
+    if (screen == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
         SDL_DestroyWindow(window);
         return SDL_FALSE;
diff --git a/libs/SDL2/test/testkeys.c b/libs/SDL2/test/testkeys.c
index c7b120b4f52979bcb935f81c593ab6dd770bc251..f80f0b9dccec1d367f98e6964e4a1b5b43259c84 100644
--- a/libs/SDL2/test/testkeys.c
+++ b/libs/SDL2/test/testkeys.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testloadso.c b/libs/SDL2/test/testloadso.c
index fa6923b97a59181cc84fe848ac990564614d95dc..f404a6813372976a10752428ff7afcac04a18757 100644
--- a/libs/SDL2/test/testloadso.c
+++ b/libs/SDL2/test/testloadso.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -53,13 +53,13 @@ int main(int argc, char *argv[])
     }
 
     lib = SDL_LoadObject(libname);
-    if (!lib) {
+    if (lib == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadObject('%s') failed: %s\n",
                      libname, SDL_GetError());
         retval = 3;
     } else {
         fn = (fntype)SDL_LoadFunction(lib, symname);
-        if (!fn) {
+        if (fn == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadFunction('%s') failed: %s\n",
                          symname, SDL_GetError());
             retval = 4;
diff --git a/libs/SDL2/test/testlocale.c b/libs/SDL2/test/testlocale.c
index 6e371ca10175aebb6e63c5da64cd8b076143755c..f8ff1a37b0307792241544ceff4a1cbdab3ddb86 100644
--- a/libs/SDL2/test/testlocale.c
+++ b/libs/SDL2/test/testlocale.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -17,7 +17,7 @@
 static void log_locales(void)
 {
     SDL_Locale *locales = SDL_GetPreferredLocales();
-    if (!locales) {
+    if (locales == NULL) {
         SDL_Log("Couldn't determine locales: %s", SDL_GetError());
     } else {
         SDL_Locale *l;
diff --git a/libs/SDL2/test/testlock.c b/libs/SDL2/test/testlock.c
index 1af8846fac1d6b89764bb7b632c5846fd68dff10..544ec322b000af3bad5444226ad7eaa9b6db88df 100644
--- a/libs/SDL2/test/testlock.c
+++ b/libs/SDL2/test/testlock.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -106,7 +106,7 @@ int main(int argc, char *argv[])
     SDL_AtomicSet(&doterminate, 0);
 
     mutex = SDL_CreateMutex();
-    if (!mutex) {
+    if (mutex == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create mutex: %s\n", SDL_GetError());
         exit(1);
     }
diff --git a/libs/SDL2/test/testmessage.c b/libs/SDL2/test/testmessage.c
index d3de67ee7660234e40d18647ed82d6b6ef797c0d..f805f8301a89adc8996bb87e3a3f97a4a6d953a5 100644
--- a/libs/SDL2/test/testmessage.c
+++ b/libs/SDL2/test/testmessage.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testmouse.c b/libs/SDL2/test/testmouse.c
index 0583ead5a1d61569baf34390e85d2e718b1b8ca5..d1c4edc06b606b401588422af3dc9193fbed2373 100644
--- a/libs/SDL2/test/testmouse.c
+++ b/libs/SDL2/test/testmouse.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -83,7 +83,7 @@ void DrawObject(SDL_Renderer *renderer, Object *object)
 void DrawObjects(SDL_Renderer *renderer)
 {
     Object *next = objects;
-    while (next) {
+    while (next != NULL) {
         DrawObject(renderer, next);
         next = next->next;
     }
@@ -93,7 +93,7 @@ void AppendObject(Object *object)
 {
     if (objects) {
         Object *next = objects;
-        while (next->next) {
+        while (next->next != NULL) {
             next = next->next;
         }
         next->next = object;
@@ -130,7 +130,7 @@ void loop(void *arg)
             break;
 
         case SDL_MOUSEMOTION:
-            if (!active) {
+            if (active == NULL) {
                 break;
             }
 
@@ -139,7 +139,7 @@ void loop(void *arg)
             break;
 
         case SDL_MOUSEBUTTONDOWN:
-            if (!active) {
+            if (active == NULL) {
                 active = SDL_calloc(1, sizeof(*active));
                 active->x1 = active->x2 = event.button.x;
                 active->y1 = active->y2 = event.button.y;
@@ -173,7 +173,7 @@ void loop(void *arg)
             break;
 
         case SDL_MOUSEBUTTONUP:
-            if (!active) {
+            if (active == NULL) {
                 break;
             }
 
@@ -266,13 +266,13 @@ int main(int argc, char *argv[])
     window = SDL_CreateWindow("Mouse Test", SDL_WINDOWPOS_CENTERED,
                               SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
                               SCREEN_HEIGHT, 0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
         return SDL_FALSE;
     }
 
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
         SDL_DestroyWindow(window);
         return SDL_FALSE;
diff --git a/libs/SDL2/test/testmultiaudio.c b/libs/SDL2/test/testmultiaudio.c
index 593942038c370dee0f4b3af188577b0bc55dbdbe..2fd352b52e6394ad8ee76747372772995e27735f 100644
--- a/libs/SDL2/test/testmultiaudio.c
+++ b/libs/SDL2/test/testmultiaudio.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnative.c b/libs/SDL2/test/testnative.c
index ad47e4a07db5de2ff73e8cf7a1788cde77499d2f..e803b822dd2dca9bde6c4aba3bd23181f67d6caa 100644
--- a/libs/SDL2/test/testnative.c
+++ b/libs/SDL2/test/testnative.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -47,7 +47,7 @@ static void
 quit(int rc)
 {
     SDL_VideoQuit();
-    if (native_window && factory) {
+    if (native_window != NULL && factory != NULL) {
         factory->DestroyNativeWindow(native_window);
     }
     exit(rc);
@@ -119,19 +119,19 @@ int main(int argc, char *argv[])
             break;
         }
     }
-    if (!factory) {
+    if (factory == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find native window code for %s driver\n",
                      driver);
         quit(2);
     }
     SDL_Log("Creating native window for %s driver\n", driver);
     native_window = factory->CreateNativeWindow(WINDOW_W, WINDOW_H);
-    if (!native_window) {
+    if (native_window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create native window\n");
         quit(3);
     }
     window = SDL_CreateWindowFrom(native_window);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create SDL window: %s\n", SDL_GetError());
         quit(4);
     }
@@ -139,7 +139,7 @@ int main(int argc, char *argv[])
 
     /* Create the renderer */
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
         quit(5);
     }
@@ -149,7 +149,7 @@ int main(int argc, char *argv[])
     SDL_RenderClear(renderer);
 
     sprite = LoadTexture(renderer, "icon.bmp", SDL_TRUE, NULL, NULL);
-    if (!sprite) {
+    if (sprite == NULL) {
         quit(6);
     }
 
@@ -158,7 +158,7 @@ int main(int argc, char *argv[])
     SDL_QueryTexture(sprite, NULL, NULL, &sprite_w, &sprite_h);
     positions = (SDL_Rect *)SDL_malloc(NUM_SPRITES * sizeof(SDL_Rect));
     velocities = (SDL_Rect *)SDL_malloc(NUM_SPRITES * sizeof(SDL_Rect));
-    if (!positions || !velocities) {
+    if (positions == NULL || velocities == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
         quit(2);
     }
diff --git a/libs/SDL2/test/testnative.h b/libs/SDL2/test/testnative.h
index e2643902e89e6e4d8d785436ac31109d6752fb10..2ba9005866fa9301d1ca179207df1f11aa424e28 100644
--- a/libs/SDL2/test/testnative.h
+++ b/libs/SDL2/test/testnative.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnativeos2.c b/libs/SDL2/test/testnativeos2.c
index bbdbe9025eece64d2640ec8caba3f82f65fe2c0c..e0f249121aa967d416bd39ce16ea005664ddd9c8 100644
--- a/libs/SDL2/test/testnativeos2.c
+++ b/libs/SDL2/test/testnativeos2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testnativew32.c b/libs/SDL2/test/testnativew32.c
index dfd0b63f4761e8730fd64e2f62d5c74a20e68b4b..e1574583db4e01e91294bebc7cc9c96cdc813d23 100644
--- a/libs/SDL2/test/testnativew32.c
+++ b/libs/SDL2/test/testnativew32.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -66,7 +66,7 @@ CreateWindowNative(int w, int h)
         CreateWindow("SDL Test", "", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
                      CW_USEDEFAULT, w, h, NULL, NULL, GetModuleHandle(NULL),
                      NULL);
-    if (!hwnd) {
+    if (hwnd == NULL) {
         MessageBox(NULL, "Window Creation Failed!", "Error!",
                    MB_ICONEXCLAMATION | MB_OK);
         return 0;
diff --git a/libs/SDL2/test/testnativex11.c b/libs/SDL2/test/testnativex11.c
index a891f466ea66d966888b7beb3b58f8bcafe58385..95dc3d64473fd22a7b94bd22a00c0933f71b0d7d 100644
--- a/libs/SDL2/test/testnativex11.c
+++ b/libs/SDL2/test/testnativex11.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testoffscreen.c b/libs/SDL2/test/testoffscreen.c
index 09ef7fcdd772b3474bf46e12e8767562ae98584b..fa511e8cef688213c692a64c4d8bb8feb15c2560 100644
--- a/libs/SDL2/test/testoffscreen.c
+++ b/libs/SDL2/test/testoffscreen.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -115,14 +115,14 @@ int main(int argc, char *argv[])
                               SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                               width, height, 0);
 
-    if (!window) {
+    if (window == NULL) {
         SDL_Log("Couldn't create window: %s\n", SDL_GetError());
         return SDL_FALSE;
     }
 
     renderer = SDL_CreateRenderer(window, -1, 0);
 
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_Log("Couldn't create renderer: %s\n",
                 SDL_GetError());
         return SDL_FALSE;
diff --git a/libs/SDL2/test/testoverlay2.c b/libs/SDL2/test/testoverlay2.c
index ccfa8e5b4024071ebf6cbcea307d9deaa653fd0b..a5dba68633b767526b81ad88aaf73e64d50b0757 100644
--- a/libs/SDL2/test/testoverlay2.c
+++ b/libs/SDL2/test/testoverlay2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -311,21 +311,21 @@ int main(int argc, char **argv)
     }
 
     RawMooseData = (Uint8 *)SDL_malloc(MOOSEFRAME_SIZE * MOOSEFRAMES_COUNT);
-    if (!RawMooseData) {
+    if (RawMooseData == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't allocate memory for movie !\n");
         quit(1);
     }
 
     /* load the trojan moose images */
     filename = GetResourceFilename(NULL, "moose.dat");
-    if (!filename) {
+    if (filename == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n");
         SDL_free(RawMooseData);
         return -1;
     }
     handle = SDL_RWFromFile(filename, "rb");
     SDL_free(filename);
-    if (!handle) {
+    if (handle == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !\n");
         SDL_free(RawMooseData);
         quit(2);
@@ -343,21 +343,21 @@ int main(int argc, char **argv)
                               SDL_WINDOWPOS_UNDEFINED,
                               window_w, window_h,
                               SDL_WINDOW_RESIZABLE);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s\n", SDL_GetError());
         SDL_free(RawMooseData);
         quit(4);
     }
 
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s\n", SDL_GetError());
         SDL_free(RawMooseData);
         quit(4);
     }
 
     MooseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H);
-    if (!MooseTexture) {
+    if (MooseTexture == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError());
         SDL_free(RawMooseData);
         quit(5);
diff --git a/libs/SDL2/test/testplatform.c b/libs/SDL2/test/testplatform.c
index 353758a7dac2c7b33ac102150811d577fd70b8d8..7e89d2f8199186b9b222c06fc6b81ae780a1bb88 100644
--- a/libs/SDL2/test/testplatform.c
+++ b/libs/SDL2/test/testplatform.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -366,7 +366,7 @@ int Test64Bit(SDL_bool verbose)
     LL_Test *t;
     int failed = 0;
 
-    for (t = LL_Tests; t->routine; t++) {
+    for (t = LL_Tests; t->routine != NULL; t++) {
         unsigned long long result = 0;
         unsigned int *al = (unsigned int *)&t->a;
         unsigned int *bl = (unsigned int *)&t->b;
diff --git a/libs/SDL2/test/testpower.c b/libs/SDL2/test/testpower.c
index 1c13b4dbaf5893a75c9ccf85ab94cedc057b70ae..af60258d792c72f79aa20cbe84141bc897f2063b 100644
--- a/libs/SDL2/test/testpower.c
+++ b/libs/SDL2/test/testpower.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testqsort.c b/libs/SDL2/test/testqsort.c
index 9c1f7646d95c0c7876363617c6511a9ddd2cd25f..271671e91cd10f9fe811143eecc6eb6df63e1109 100644
--- a/libs/SDL2/test/testqsort.c
+++ b/libs/SDL2/test/testqsort.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testrelative.c b/libs/SDL2/test/testrelative.c
index 3f777cd83d8782b93b098e3ede095e4535d03fc8..88ed0bf5ab111e6af91ba598f5abe1d7d5cdd99b 100644
--- a/libs/SDL2/test/testrelative.c
+++ b/libs/SDL2/test/testrelative.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -91,7 +91,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc; ++i) {
diff --git a/libs/SDL2/test/testrendercopyex.c b/libs/SDL2/test/testrendercopyex.c
index 832101aa376b2ec7acca61a7dd93169f2825df90..de7bc019a37b8567c3c7a4f7bdcfa38c6a8167d3 100644
--- a/libs/SDL2/test/testrendercopyex.c
+++ b/libs/SDL2/test/testrendercopyex.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -121,7 +121,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testrendertarget.c b/libs/SDL2/test/testrendertarget.c
index 9693df4f84fb902cc3a714abe66b1dfb3cfc982d..1ae609987436cb6c63054eedd3e8ecdb06bdafcf 100644
--- a/libs/SDL2/test/testrendertarget.c
+++ b/libs/SDL2/test/testrendertarget.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -138,7 +138,7 @@ Draw(DrawState *s)
     SDL_RenderGetViewport(s->renderer, &viewport);
 
     target = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, viewport.w, viewport.h);
-    if (!target) {
+    if (target == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create render target texture: %s\n", SDL_GetError());
         return SDL_FALSE;
     }
@@ -214,7 +214,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
     for (i = 1; i < argc;) {
diff --git a/libs/SDL2/test/testresample.c b/libs/SDL2/test/testresample.c
index 21ff8e170ce5194dc7e6a76b5703144e18a9dfea..8bb603ac20671f831dc34cff99d1efb20aed5f18 100644
--- a/libs/SDL2/test/testresample.c
+++ b/libs/SDL2/test/testresample.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -57,7 +57,7 @@ int main(int argc, char **argv)
 
     cvt.len = len;
     cvt.buf = (Uint8 *)SDL_malloc((size_t)len * cvt.len_mult);
-    if (!cvt.buf) {
+    if (cvt.buf == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory.\n");
         SDL_FreeWAV(data);
         SDL_Quit();
@@ -75,7 +75,7 @@ int main(int argc, char **argv)
 
     /* write out a WAV header... */
     io = SDL_RWFromFile(argv[2], "wb");
-    if (!io) {
+    if (io == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "fopen('%s') failed: %s\n", argv[2], SDL_GetError());
         SDL_free(cvt.buf);
         SDL_FreeWAV(data);
diff --git a/libs/SDL2/test/testrumble.c b/libs/SDL2/test/testrumble.c
index 401b7605e293a4a7e4fa571173d5a671ee7f4265..d6288d59230b19876b50f856d7415b11ac6ebb07 100644
--- a/libs/SDL2/test/testrumble.c
+++ b/libs/SDL2/test/testrumble.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -71,7 +71,7 @@ int main(int argc, char **argv)
     SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics());
     if (SDL_NumHaptics() > 0) {
         /* We'll just use index or the first force feedback device found */
-        if (!name) {
+        if (name == NULL) {
             i = (index != -1) ? index : 0;
         }
         /* Try to find matching device */
@@ -90,7 +90,7 @@ int main(int argc, char **argv)
         }
 
         haptic = SDL_HapticOpen(i);
-        if (!haptic) {
+        if (haptic == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
                          SDL_GetError());
             return 1;
@@ -129,7 +129,7 @@ int main(int argc, char **argv)
     SDL_Delay(2000);
 
     /* Quit */
-    if (haptic) {
+    if (haptic != NULL) {
         SDL_HapticClose(haptic);
     }
     SDL_Quit();
diff --git a/libs/SDL2/test/testscale.c b/libs/SDL2/test/testscale.c
index 3659c91490783b9bca1464881b91e31e126e53b6..dca3d09600afeb568b26d769f7e57ab656f681ec 100644
--- a/libs/SDL2/test/testscale.c
+++ b/libs/SDL2/test/testscale.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -111,7 +111,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testsem.c b/libs/SDL2/test/testsem.c
index 5740833f43082b210b3e7da783192209706ba38a..c0036e882f613fcc03aa9af42f6339cfd1ead698 100644
--- a/libs/SDL2/test/testsem.c
+++ b/libs/SDL2/test/testsem.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testsensor.c b/libs/SDL2/test/testsensor.c
index 2b9af5835ffd40f24e92cc7252691e0b03fc40f0..3da7e015e7f8228d7b147cce26dded573ea5c331 100644
--- a/libs/SDL2/test/testsensor.c
+++ b/libs/SDL2/test/testsensor.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -36,7 +36,7 @@ static const char *GetSensorTypeString(SDL_SensorType type)
 static void HandleSensorEvent(SDL_SensorEvent *event)
 {
     SDL_Sensor *sensor = SDL_SensorFromInstanceID(event->which);
-    if (!sensor) {
+    if (sensor == NULL) {
         SDL_Log("Couldn't get sensor for sensor event\n");
         return;
     }
@@ -78,7 +78,7 @@ int main(int argc, char **argv)
 
         if (SDL_SensorGetDeviceType(i) != SDL_SENSOR_UNKNOWN) {
             SDL_Sensor *sensor = SDL_SensorOpen(i);
-            if (!sensor) {
+            if (sensor == NULL) {
                 SDL_Log("Couldn't open sensor %" SDL_PRIs32 ": %s\n", SDL_SensorGetDeviceInstanceID(i), SDL_GetError());
             } else {
                 ++num_opened;
diff --git a/libs/SDL2/test/testshader.c b/libs/SDL2/test/testshader.c
index 48535dca78d2d0b8ad501748208cd4b3e2269171..2371fcefbc87258db1e7a95a0349819d3edac15f 100644
--- a/libs/SDL2/test/testshader.c
+++ b/libs/SDL2/test/testshader.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -109,36 +109,36 @@ static ShaderData shaders[NUM_SHADERS] = {
       "}" },
 };
 
-static PFNGLATTACHOBJECTARBPROC pglAttachObjectARB;
-static PFNGLCOMPILESHADERARBPROC pglCompileShaderARB;
-static PFNGLCREATEPROGRAMOBJECTARBPROC pglCreateProgramObjectARB;
-static PFNGLCREATESHADEROBJECTARBPROC pglCreateShaderObjectARB;
-static PFNGLDELETEOBJECTARBPROC pglDeleteObjectARB;
-static PFNGLGETINFOLOGARBPROC pglGetInfoLogARB;
-static PFNGLGETOBJECTPARAMETERIVARBPROC pglGetObjectParameterivARB;
-static PFNGLGETUNIFORMLOCATIONARBPROC pglGetUniformLocationARB;
-static PFNGLLINKPROGRAMARBPROC pglLinkProgramARB;
-static PFNGLSHADERSOURCEARBPROC pglShaderSourceARB;
-static PFNGLUNIFORM1IARBPROC pglUniform1iARB;
-static PFNGLUSEPROGRAMOBJECTARBPROC pglUseProgramObjectARB;
+static PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
+static PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
+static PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
+static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
+static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
+static PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
+static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
+static PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
+static PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
+static PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
+static PFNGLUNIFORM1IARBPROC glUniform1iARB;
+static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
 
 static SDL_bool CompileShader(GLhandleARB shader, const char *source)
 {
     GLint status = 0;
 
-    pglShaderSourceARB(shader, 1, &source, NULL);
-    pglCompileShaderARB(shader);
-    pglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+    glShaderSourceARB(shader, 1, &source, NULL);
+    glCompileShaderARB(shader);
+    glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
     if (status == 0) {
         GLint length = 0;
         char *info;
 
-        pglGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+        glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
         info = (char *)SDL_malloc((size_t)length + 1);
-        if (!info) {
+        if (info == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
         } else {
-            pglGetInfoLogARB(shader, length, NULL, info);
+            glGetInfoLogARB(shader, length, NULL, info);
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info);
             SDL_free(info);
         }
@@ -152,21 +152,21 @@ static SDL_bool LinkProgram(ShaderData *data)
 {
     GLint status = 0;
 
-    pglAttachObjectARB(data->program, data->vert_shader);
-    pglAttachObjectARB(data->program, data->frag_shader);
-    pglLinkProgramARB(data->program);
+    glAttachObjectARB(data->program, data->vert_shader);
+    glAttachObjectARB(data->program, data->frag_shader);
+    glLinkProgramARB(data->program);
 
-    pglGetObjectParameterivARB(data->program, GL_OBJECT_LINK_STATUS_ARB, &status);
+    glGetObjectParameterivARB(data->program, GL_OBJECT_LINK_STATUS_ARB, &status);
     if (status == 0) {
         GLint length = 0;
         char *info;
 
-        pglGetObjectParameterivARB(data->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+        glGetObjectParameterivARB(data->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
         info = (char *)SDL_malloc((size_t)length + 1);
-        if (!info) {
+        if (info == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
         } else {
-            pglGetInfoLogARB(data->program, length, NULL, info);
+            glGetInfoLogARB(data->program, length, NULL, info);
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:\n%s", info);
             SDL_free(info);
         }
@@ -185,16 +185,16 @@ static SDL_bool CompileShaderProgram(ShaderData *data)
     glGetError();
 
     /* Create one program object to rule them all */
-    data->program = pglCreateProgramObjectARB();
+    data->program = glCreateProgramObjectARB();
 
     /* Create the vertex shader */
-    data->vert_shader = pglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+    data->vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
     if (!CompileShader(data->vert_shader, data->vert_source)) {
         return SDL_FALSE;
     }
 
     /* Create the fragment shader */
-    data->frag_shader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+    data->frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
     if (!CompileShader(data->frag_shader, data->frag_source)) {
         return SDL_FALSE;
     }
@@ -205,16 +205,16 @@ static SDL_bool CompileShaderProgram(ShaderData *data)
     }
 
     /* Set up some uniform variables */
-    pglUseProgramObjectARB(data->program);
+    glUseProgramObjectARB(data->program);
     for (i = 0; i < num_tmus_bound; ++i) {
         char tex_name[5];
         (void)SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
-        location = pglGetUniformLocationARB(data->program, tex_name);
+        location = glGetUniformLocationARB(data->program, tex_name);
         if (location >= 0) {
-            pglUniform1iARB(location, i);
+            glUniform1iARB(location, i);
         }
     }
-    pglUseProgramObjectARB(0);
+    glUseProgramObjectARB(0);
 
     return (glGetError() == GL_NO_ERROR) ? SDL_TRUE : SDL_FALSE;
 }
@@ -222,9 +222,9 @@ static SDL_bool CompileShaderProgram(ShaderData *data)
 static void DestroyShaderProgram(ShaderData *data)
 {
     if (shaders_supported) {
-        pglDeleteObjectARB(data->vert_shader);
-        pglDeleteObjectARB(data->frag_shader);
-        pglDeleteObjectARB(data->program);
+        glDeleteObjectARB(data->vert_shader);
+        glDeleteObjectARB(data->frag_shader);
+        glDeleteObjectARB(data->program);
     }
 }
 
@@ -238,30 +238,30 @@ static SDL_bool InitShaders()
         SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
         SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
         SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
-        pglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB");
-        pglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB");
-        pglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB");
-        pglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB");
-        pglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB");
-        pglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB");
-        pglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB");
-        pglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB");
-        pglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB");
-        pglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB");
-        pglUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB");
-        pglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB");
-        if (pglAttachObjectARB &&
-            pglCompileShaderARB &&
-            pglCreateProgramObjectARB &&
-            pglCreateShaderObjectARB &&
-            pglDeleteObjectARB &&
-            pglGetInfoLogARB &&
-            pglGetObjectParameterivARB &&
-            pglGetUniformLocationARB &&
-            pglLinkProgramARB &&
-            pglShaderSourceARB &&
-            pglUniform1iARB &&
-            pglUseProgramObjectARB) {
+        glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB");
+        glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB");
+        glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB");
+        glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB");
+        glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB");
+        glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB");
+        glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB");
+        glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB");
+        glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB");
+        glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB");
+        glUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB");
+        glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB");
+        if (glAttachObjectARB &&
+            glCompileShaderARB &&
+            glCreateProgramObjectARB &&
+            glCreateShaderObjectARB &&
+            glDeleteObjectARB &&
+            glGetInfoLogARB &&
+            glGetObjectParameterivARB &&
+            glGetUniformLocationARB &&
+            glLinkProgramARB &&
+            glShaderSourceARB &&
+            glUniform1iARB &&
+            glUseProgramObjectARB) {
             shaders_supported = SDL_TRUE;
         }
     }
@@ -329,7 +329,7 @@ SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord)
                                  0x00FF0000, 0x0000FF00, 0x000000FF
 #endif
     );
-    if (!image) {
+    if (image == NULL) {
         return 0;
     }
 
@@ -420,7 +420,7 @@ void DrawGLScene(SDL_Window *window, GLuint texture, GLfloat *texcoord)
     glBindTexture(GL_TEXTURE_2D, texture);
     glColor3f(1.0f, 1.0f, 1.0f);
     if (shaders_supported) {
-        pglUseProgramObjectARB(shaders[current_shader].program);
+        glUseProgramObjectARB(shaders[current_shader].program);
     }
 
     glBegin(GL_QUADS); /* start drawing a polygon (4 sided) */
@@ -435,7 +435,7 @@ void DrawGLScene(SDL_Window *window, GLuint texture, GLfloat *texcoord)
     glEnd();                        /* done with the polygon */
 
     if (shaders_supported) {
-        pglUseProgramObjectARB(0);
+        glUseProgramObjectARB(0);
     }
     glDisable(GL_TEXTURE_2D);
 
@@ -462,7 +462,7 @@ int main(int argc, char **argv)
 
     /* Create a 640x480 OpenGL screen */
     window = SDL_CreateWindow("Shader Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL window: %s\n", SDL_GetError());
         SDL_Quit();
         exit(2);
@@ -475,7 +475,7 @@ int main(int argc, char **argv)
     }
 
     surface = SDL_LoadBMP("icon.bmp");
-    if (!surface) {
+    if (surface == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load icon.bmp: %s\n", SDL_GetError());
         SDL_Quit();
         exit(3);
diff --git a/libs/SDL2/test/testshape.c b/libs/SDL2/test/testshape.c
index 112ec0c60b41eb018ab56745e3b02368c7365ccc..4e3c12cdddaff878c525db7e2fe7f0846ba84464 100644
--- a/libs/SDL2/test/testshape.c
+++ b/libs/SDL2/test/testshape.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -71,7 +71,7 @@ int main(int argc, char **argv)
 
     num_pictures = argc - 1;
     pictures = (LoadedPicture *)SDL_malloc(sizeof(LoadedPicture) * num_pictures);
-    if (!pictures) {
+    if (pictures == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not allocate memory.");
         exit(1);
     }
@@ -106,7 +106,7 @@ int main(int argc, char **argv)
                                     SHAPED_WINDOW_DIMENSION, SHAPED_WINDOW_DIMENSION,
                                     0);
     SDL_SetWindowPosition(window, SHAPED_WINDOW_X, SHAPED_WINDOW_Y);
-    if (!window) {
+    if (window == NULL) {
         for (i = 0; i < num_pictures; i++) {
             SDL_FreeSurface(pictures[i].surface);
         }
@@ -116,7 +116,7 @@ int main(int argc, char **argv)
         exit(-4);
     }
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_DestroyWindow(window);
         for (i = 0; i < num_pictures; i++) {
             SDL_FreeSurface(pictures[i].surface);
diff --git a/libs/SDL2/test/testsprite2.c b/libs/SDL2/test/testsprite2.c
index 71b565678b211b9fd3dfbf7f86642726de565c9a..89037fd09c5538ce360b20e51a9a7e137a74c9f8 100644
--- a/libs/SDL2/test/testsprite2.c
+++ b/libs/SDL2/test/testsprite2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -392,30 +392,22 @@ void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
     SDL_RenderPresent(renderer);
 }
 
-static void MoveAllSprites()
-{
-    int i;
-
-    for (i = 0; i < state->num_windows; ++i) {
-        if (state->windows[i] == NULL) {
-            continue;
-        }
-        MoveSprites(state->renderers[i], sprites[i]);
-    }
-}
-
 void loop()
 {
     Uint32 now;
+    int i;
     SDL_Event event;
 
     /* Check for events */
     while (SDL_PollEvent(&event)) {
         SDLTest_CommonEvent(state, &event, &done);
     }
-
-    MoveAllSprites();
-
+    for (i = 0; i < state->num_windows; ++i) {
+        if (state->windows[i] == NULL) {
+            continue;
+        }
+        MoveSprites(state->renderers[i], sprites[i]);
+    }
 #ifdef __EMSCRIPTEN__
     if (done) {
         emscripten_cancel_main_loop();
@@ -434,14 +426,6 @@ void loop()
     }
 }
 
-static int SDLCALL ExposeEventWatcher(void *userdata, SDL_Event *event)
-{
-    if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_EXPOSED) {
-        MoveAllSprites();
-    }
-    return 0;
-}
-
 int main(int argc, char *argv[])
 {
     int i;
@@ -453,7 +437,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
@@ -541,7 +525,7 @@ int main(int argc, char *argv[])
     /* Create the windows, initialize the renderers, and load the textures */
     sprites =
         (SDL_Texture **)SDL_malloc(state->num_windows * sizeof(*sprites));
-    if (!sprites) {
+    if (sprites == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
         quit(2);
     }
@@ -557,7 +541,7 @@ int main(int argc, char *argv[])
     /* Allocate memory for the sprite info */
     positions = (SDL_Rect *)SDL_malloc(num_sprites * sizeof(SDL_Rect));
     velocities = (SDL_Rect *)SDL_malloc(num_sprites * sizeof(SDL_Rect));
-    if (!positions || !velocities) {
+    if (positions == NULL || velocities == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
         quit(2);
     }
@@ -584,9 +568,6 @@ int main(int argc, char *argv[])
         }
     }
 
-    /* Add an event watcher to redraw from within modal window resize/move loops */
-    SDL_AddEventWatch(ExposeEventWatcher, NULL);
-
     /* Main render loop */
     frames = 0;
     next_fps_check = SDL_GetTicks() + fps_check_delay;
diff --git a/libs/SDL2/test/testspriteminimal.c b/libs/SDL2/test/testspriteminimal.c
index b81101eb5d05b2f97b1eff26f83a53f150bd6827..16b4fa4a368516051461123af39d1927bfbe9556 100644
--- a/libs/SDL2/test/testspriteminimal.c
+++ b/libs/SDL2/test/testspriteminimal.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -109,7 +109,7 @@ int main(int argc, char *argv[])
 
     sprite = LoadTexture(renderer, "icon.bmp", SDL_TRUE, &sprite_w, &sprite_h);
 
-    if (!sprite) {
+    if (sprite == NULL) {
         quit(2);
     }
 
diff --git a/libs/SDL2/test/teststreaming.c b/libs/SDL2/test/teststreaming.c
index 45202a7797d148253ed5008fcb96bde4aa59797f..15c1aefea39d8bec6cdbf34aa5fb638af46fd18c 100644
--- a/libs/SDL2/test/teststreaming.c
+++ b/libs/SDL2/test/teststreaming.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -141,13 +141,13 @@ int main(int argc, char **argv)
 
     /* load the moose images */
     filename = GetResourceFilename(NULL, "moose.dat");
-    if (!filename) {
+    if (filename == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n");
         return -1;
     }
     handle = SDL_RWFromFile(filename, "rb");
     SDL_free(filename);
-    if (!handle) {
+    if (handle == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Can't find the file moose.dat !\n");
         quit(2);
     }
@@ -160,19 +160,19 @@ int main(int argc, char **argv)
                               SDL_WINDOWPOS_UNDEFINED,
                               MOOSEPIC_W * 4, MOOSEPIC_H * 4,
                               SDL_WINDOW_RESIZABLE);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s\n", SDL_GetError());
         quit(3);
     }
 
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s\n", SDL_GetError());
         quit(4);
     }
 
     MooseTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, MOOSEPIC_W, MOOSEPIC_H);
-    if (!MooseTexture) {
+    if (MooseTexture == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError());
         quit(5);
     }
diff --git a/libs/SDL2/test/testsurround.c b/libs/SDL2/test/testsurround.c
index b7dc7d7818cce50b7a30d7d1ce6da87ba34cbb99..b28436977edbc6a6ddda47f6203aac74c8a23339 100644
--- a/libs/SDL2/test/testsurround.c
+++ b/libs/SDL2/test/testsurround.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testthread.c b/libs/SDL2/test/testthread.c
index 5ceac05ffac38ef8b45f6c0d21a51e78ff28e85c..f6d967560f7c12f62259d9024f742d8166f1482c 100644
--- a/libs/SDL2/test/testthread.c
+++ b/libs/SDL2/test/testthread.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -114,7 +114,7 @@ int main(int argc, char *argv[])
 
     alive = 1;
     thread = SDL_CreateThread(ThreadFunc, "One", "#1");
-    if (!thread) {
+    if (thread == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError());
         quit(1);
     }
@@ -128,7 +128,7 @@ int main(int argc, char *argv[])
     alive = 1;
     (void)signal(SIGTERM, killed);
     thread = SDL_CreateThread(ThreadFunc, "Two", "#2");
-    if (!thread) {
+    if (thread == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError());
         quit(1);
     }
diff --git a/libs/SDL2/test/testtimer.c b/libs/SDL2/test/testtimer.c
index eea9730c534ec5f9a21b2e06c4d4faa4c99f2954..54a903ad087dc0d30e21de7b6ab6c9d2ff3d843a 100644
--- a/libs/SDL2/test/testtimer.c
+++ b/libs/SDL2/test/testtimer.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -18,38 +18,9 @@
 #include <stdio.h>
 
 #include "SDL.h"
-#include "SDL_test.h"
 
 #define DEFAULT_RESOLUTION 1
 
-static int test_sdl_delay_within_bounds(void) {
-    const int testDelay = 100;
-    const int marginOfError = 25;
-    Uint64 result;
-    Uint64 result2;
-    Sint64 difference;
-
-    SDLTest_ResetAssertSummary();
-
-    /* Get ticks count - should be non-zero by now */
-    result = SDL_GetTicks();
-    SDLTest_AssertPass("Call to SDL_GetTicks()");
-    SDLTest_AssertCheck(result > 0, "Check result value, expected: >0, got: %" SDL_PRIu64, result);
-
-    /* Delay a bit longer and measure ticks and verify difference */
-    SDL_Delay(testDelay);
-    SDLTest_AssertPass("Call to SDL_Delay(%d)", testDelay);
-    result2 = SDL_GetTicks();
-    SDLTest_AssertPass("Call to SDL_GetTicks()");
-    SDLTest_AssertCheck(result2 > 0, "Check result value, expected: >0, got: %" SDL_PRIu64, result2);
-    difference = result2 - result;
-    SDLTest_AssertCheck(difference > (testDelay - marginOfError), "Check difference, expected: >%d, got: %" SDL_PRIu64, testDelay - marginOfError, difference);
-    /* Disabled because this might fail on non-interactive systems. */
-    SDLTest_AssertCheck(difference < (testDelay + marginOfError), "Check difference, expected: <%d, got: %" SDL_PRIu64, testDelay + marginOfError, difference);
-
-    return SDLTest_AssertSummaryToTestResult() == TEST_RESULT_PASSED ? 0 : 1;
-}
-
 static int ticks = 0;
 
 static Uint32 SDLCALL
@@ -68,43 +39,15 @@ callback(Uint32 interval, void *param)
 
 int main(int argc, char *argv[])
 {
-    int i;
-    int desired = -1;
+    int i, desired;
     SDL_TimerID t1, t2, t3;
     Uint64 start64, now64;
     Uint32 start32, now32;
     Uint64 start, now;
-    SDL_bool run_interactive_tests = SDL_FALSE;
-    int return_code = 0;
 
     /* Enable standard application logging */
     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
 
-    /* Parse commandline */
-    for (i = 1; i < argc;) {
-        int consumed = 0;
-
-        if (!consumed) {
-            if (SDL_strcmp(argv[i], "--interactive") == 0) {
-                run_interactive_tests = SDL_TRUE;
-                consumed = 1;
-            } else if (desired < 0) {
-                char *endptr;
-
-                desired = SDL_strtoul(argv[i], &endptr, 0);
-                if (desired != 0 && endptr != argv[i] && *endptr == '\0') {
-                    consumed = 1;
-                }
-            }
-        }
-        if (consumed <= 0) {
-            SDL_Log("Usage: %s [--interactive] [interval]", argv[0]);
-            return 1;
-        }
-
-        i += consumed;
-    }
-
     if (SDL_Init(SDL_INIT_TIMER) < 0) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
         return 1;
@@ -131,11 +74,14 @@ int main(int argc, char *argv[])
         }
     }
 
-    if (desired < 0) {
+    /* Start the timer */
+    desired = 0;
+    if (argv[1]) {
+        desired = SDL_atoi(argv[1]);
+    }
+    if (desired == 0) {
         desired = DEFAULT_RESOLUTION;
     }
-
-    /* Start the timer */
     t1 = SDL_AddTimer(desired, ticktock, NULL);
 
     /* Wait 10 seconds */
@@ -156,17 +102,14 @@ int main(int argc, char *argv[])
     t1 = SDL_AddTimer(100, callback, (void *)1);
     if (!t1) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 1: %s\n", SDL_GetError());
-        return_code = 1;
     }
     t2 = SDL_AddTimer(50, callback, (void *)2);
     if (!t2) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 2: %s\n", SDL_GetError());
-        return_code = 1;
     }
     t3 = SDL_AddTimer(233, callback, (void *)3);
     if (!t3) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 3: %s\n", SDL_GetError());
-        return_code = 1;
     }
 
     /* Wait 10 seconds */
@@ -198,11 +141,8 @@ int main(int argc, char *argv[])
     now32 = SDL_GetTicks();
     SDL_Log("Delay 1 second = %d ms in ticks, %d ms in ticks64, %f ms according to performance counter\n", (int)(now32 - start32), (int)(now64 - start64), (double)((now - start) * 1000) / SDL_GetPerformanceFrequency());
 
-    if (run_interactive_tests) {
-        return_code |= test_sdl_delay_within_bounds();
-    }
     SDL_Quit();
-    return return_code;
+    return 0;
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/libs/SDL2/test/testurl.c b/libs/SDL2/test/testurl.c
index 2008186f3a69f442af4486752b1fe715d721d9b9..ef22083ffb91081f1e7e94d4e1d13ed643021a62 100644
--- a/libs/SDL2/test/testurl.c
+++ b/libs/SDL2/test/testurl.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testutils.c b/libs/SDL2/test/testutils.c
index 3b76ea8331f15704ef6bea2cfbb2cfec14d59913..20efef027a37afa5864494ba014c91bd9bbe7d1a 100644
--- a/libs/SDL2/test/testutils.c
+++ b/libs/SDL2/test/testutils.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
   Copyright 2022 Collabora Ltd.
 
   This software is provided 'as-is', without any express or implied
@@ -28,13 +28,13 @@ GetNearbyFilename(const char *file)
 
     base = SDL_GetBasePath();
 
-    if (base) {
+    if (base != NULL) {
         SDL_RWops *rw;
         size_t len = SDL_strlen(base) + SDL_strlen(file) + 1;
 
         path = SDL_malloc(len);
 
-        if (!path) {
+        if (path == NULL) {
             SDL_free(base);
             SDL_OutOfMemory();
             return NULL;
@@ -54,7 +54,7 @@ GetNearbyFilename(const char *file)
     }
 
     path = SDL_strdup(file);
-    if (!path) {
+    if (path == NULL) {
         SDL_OutOfMemory();
     }
     return path;
@@ -72,10 +72,10 @@ GetNearbyFilename(const char *file)
 char *
 GetResourceFilename(const char *user_specified, const char *def)
 {
-    if (user_specified) {
+    if (user_specified != NULL) {
         char *ret = SDL_strdup(user_specified);
 
-        if (!ret) {
+        if (ret == NULL) {
             SDL_OutOfMemory();
         }
 
@@ -105,12 +105,12 @@ LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent,
 
     path = GetNearbyFilename(file);
 
-    if (path) {
+    if (path != NULL) {
         file = path;
     }
 
     temp = SDL_LoadBMP(file);
-    if (!temp) {
+    if (temp == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
     } else {
         /* Set transparent pixel as the pixel at (0,0) */
@@ -137,16 +137,16 @@ LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent,
             }
         }
 
-        if (width_out) {
+        if (width_out != NULL) {
             *width_out = temp->w;
         }
 
-        if (height_out) {
+        if (height_out != NULL) {
             *height_out = temp->h;
         }
 
         texture = SDL_CreateTextureFromSurface(renderer, temp);
-        if (!texture) {
+        if (texture == NULL) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
         }
     }
diff --git a/libs/SDL2/test/testutils.h b/libs/SDL2/test/testutils.h
index a10aaadd311ba2f815f20facc99e7c287c1e46b4..1f69673ce0d7a73f34a2f2f8fffac1c2f5145db3 100644
--- a/libs/SDL2/test/testutils.h
+++ b/libs/SDL2/test/testutils.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
   Copyright 2022 Collabora Ltd.
 
   This software is provided 'as-is', without any express or implied
diff --git a/libs/SDL2/test/testver.c b/libs/SDL2/test/testver.c
index 409b1f12f3967d81759bec4566963874a5cf381a..eeecb14a69d535562b9d44e1f533cea386a5d40a 100644
--- a/libs/SDL2/test/testver.c
+++ b/libs/SDL2/test/testver.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testviewport.c b/libs/SDL2/test/testviewport.c
index ee76a3782f9b612a3e2859382ee22dd8981e0943..932f24832549ec434cbfac027ddbf6374fb9f158 100644
--- a/libs/SDL2/test/testviewport.c
+++ b/libs/SDL2/test/testviewport.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -152,7 +152,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
@@ -180,7 +180,7 @@ int main(int argc, char *argv[])
 
     sprite = LoadTexture(state->renderers[0], "icon.bmp", SDL_TRUE, &sprite_w, &sprite_h);
 
-    if (!sprite) {
+    if (sprite == NULL) {
         quit(2);
     }
 
diff --git a/libs/SDL2/test/testvulkan.c b/libs/SDL2/test/testvulkan.c
index 8a4ac893491e4192a8fcd61ad6e7d1a6d1face31..acdde28fd2e8a66666a4c8e7f608d3949829b220 100644
--- a/libs/SDL2/test/testvulkan.c
+++ b/libs/SDL2/test/testvulkan.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -236,7 +236,7 @@ static void createInstance(void)
         quit(2);
     }
     extensions = (const char **)SDL_malloc(sizeof(const char *) * extensionCount);
-    if (!extensions) {
+    if (extensions == NULL) {
         SDL_OutOfMemory();
         quit(2);
     }
@@ -312,7 +312,7 @@ static void findPhysicalDevice(void)
         quit(2);
     }
     physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
-    if (!physicalDevices) {
+    if (physicalDevices == NULL) {
         SDL_OutOfMemory();
         quit(2);
     }
@@ -346,7 +346,7 @@ static void findPhysicalDevice(void)
             SDL_free(queueFamiliesProperties);
             queueFamiliesPropertiesAllocatedSize = queueFamiliesCount;
             queueFamiliesProperties = (VkQueueFamilyProperties *)SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize);
-            if (!queueFamiliesProperties) {
+            if (queueFamiliesProperties == NULL) {
                 SDL_free(physicalDevices);
                 SDL_free(deviceExtensions);
                 SDL_OutOfMemory();
@@ -408,7 +408,7 @@ static void findPhysicalDevice(void)
             SDL_free(deviceExtensions);
             deviceExtensionsAllocatedSize = deviceExtensionCount;
             deviceExtensions = SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize);
-            if (!deviceExtensions) {
+            if (deviceExtensions == NULL) {
                 SDL_free(physicalDevices);
                 SDL_free(queueFamiliesProperties);
                 SDL_OutOfMemory();
@@ -929,7 +929,7 @@ static void initVulkan(void)
     SDL_Vulkan_LoadLibrary(NULL);
 
     vulkanContexts = (VulkanContext *)SDL_calloc(state->num_windows, sizeof(VulkanContext));
-    if (!vulkanContexts) {
+    if (vulkanContexts == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
         quit(2);
     }
@@ -1092,7 +1092,7 @@ int main(int argc, char **argv)
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testwm2.c b/libs/SDL2/test/testwm2.c
index 5236a7f5b97c2562fbc9514edac8704623cabcc4..7fc189bd75357a61a0215685d0c7b6731b733595 100644
--- a/libs/SDL2/test/testwm2.c
+++ b/libs/SDL2/test/testwm2.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -208,7 +208,7 @@ void loop()
         }
         if (event.type == SDL_MOUSEBUTTONUP) {
             SDL_Window *window = SDL_GetMouseFocus();
-            if (highlighted_mode != -1 && window) {
+            if (highlighted_mode != -1 && window != NULL) {
                 const int display_index = SDL_GetWindowDisplayIndex(window);
                 SDL_DisplayMode mode;
                 if (0 != SDL_GetDisplayMode(display_index, highlighted_mode, &mode)) {
@@ -223,7 +223,7 @@ void loop()
     for (i = 0; i < state->num_windows; ++i) {
         SDL_Window *window = state->windows[i];
         SDL_Renderer *renderer = state->renderers[i];
-        if (window && renderer) {
+        if (window != NULL && renderer != NULL) {
             int y = 0;
             SDL_Rect viewport, menurect;
 
@@ -262,7 +262,7 @@ int main(int argc, char *argv[])
 
     /* Initialize test framework */
     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
-    if (!state) {
+    if (state == NULL) {
         return 1;
     }
 
diff --git a/libs/SDL2/test/testyuv.c b/libs/SDL2/test/testyuv.c
index e9038ed0d3df28b49aa046f215800e92d73267a1..e7373a8b129e9e97dc89e5c0ed4360a60e3799f5 100644
--- a/libs/SDL2/test/testyuv.c
+++ b/libs/SDL2/test/testyuv.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -75,7 +75,7 @@ static SDL_bool verify_yuv_data(Uint32 format, const Uint8 *yuv, int yuv_pitch,
     SDL_bool result = SDL_FALSE;
 
     rgb = (Uint8 *)SDL_malloc(size);
-    if (!rgb) {
+    if (rgb == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory");
         return SDL_FALSE;
     }
@@ -126,7 +126,7 @@ static int run_automated_tests(int pattern_size, int extra_pitch)
     int yuv1_pitch, yuv2_pitch;
     int result = -1;
 
-    if (!pattern || !yuv1 || !yuv2) {
+    if (pattern == NULL || yuv1 == NULL || yuv2 == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't allocate test surfaces");
         goto done;
     }
@@ -327,7 +327,7 @@ int main(int argc, char **argv)
         filename = "testyuv.bmp";
     }
     original = SDL_ConvertSurfaceFormat(SDL_LoadBMP(filename), SDL_PIXELFORMAT_RGB24, 0);
-    if (!original) {
+    if (original == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError());
         return 3;
     }
@@ -339,7 +339,7 @@ int main(int argc, char **argv)
     pitch = CalculateYUVPitch(yuv_format, original->w);
 
     converted = SDL_CreateRGBSurfaceWithFormat(0, original->w, original->h, 0, rgb_format);
-    if (!converted) {
+    if (converted == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create converted surface: %s\n", SDL_GetError());
         return 3;
     }
@@ -356,13 +356,13 @@ int main(int argc, char **argv)
                               SDL_WINDOWPOS_UNDEFINED,
                               original->w, original->h,
                               0);
-    if (!window) {
+    if (window == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
         return 4;
     }
 
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (!renderer) {
+    if (renderer == NULL) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
         return 4;
     }
diff --git a/libs/SDL2/test/testyuv_cvt.c b/libs/SDL2/test/testyuv_cvt.c
index d78e5b196451e986f4b693f40c28cd363c89f85d..3bd2df3ff027da50e999b6f686df07daaf7959c8 100644
--- a/libs/SDL2/test/testyuv_cvt.c
+++ b/libs/SDL2/test/testyuv_cvt.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/testyuv_cvt.h b/libs/SDL2/test/testyuv_cvt.h
index fa736be3c3b2a2ccb403f59cad2ab9294e5904e7..781b632ea7f1de61124d2a42cd5152a31aca8076 100644
--- a/libs/SDL2/test/testyuv_cvt.h
+++ b/libs/SDL2/test/testyuv_cvt.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/torturethread.c b/libs/SDL2/test/torturethread.c
index b612cda497766416e0a94ab469988685fb1b908f..1976800f0aeb957add2173a5a9fde7e4dd8fcebe 100644
--- a/libs/SDL2/test/torturethread.c
+++ b/libs/SDL2/test/torturethread.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/test/watcom.mif b/libs/SDL2/test/watcom.mif
index b81dad831e372d992a2b09f79a63123dcc9a01f6..2189fd49c2760eb453cee0929796d53651ae417e 100644
--- a/libs/SDL2/test/watcom.mif
+++ b/libs/SDL2/test/watcom.mif
@@ -53,13 +53,12 @@ TASRCS = testautomation.c &
 	testautomation_audio.c testautomation_clipboard.c &
 	testautomation_events.c testautomation_guid.c &
 	testautomation_hints.c testautomation_joystick.c &
-	testautomation_keyboard.c testautomation_log.c &
-	testautomation_main.c testautomation_math.c &
-	testautomation_mouse.c testautomation_pixels.c &
-	testautomation_platform.c testautomation_rect.c &
-	testautomation_render.c testautomation_rwops.c &
-	testautomation_sdltest.c testautomation_stdlib.c &
-	testautomation_subsystems.c testautomation_surface.c &
+	testautomation_keyboard.c testautomation_main.c &
+	testautomation_math.c testautomation_mouse.c &
+	testautomation_pixels.c testautomation_platform.c &
+	testautomation_rect.c testautomation_render.c &
+	testautomation_rwops.c testautomation_sdltest.c &
+	testautomation_stdlib.c testautomation_surface.c &
 	testautomation_syswm.c testautomation_timer.c &
 	testautomation_video.c
 
@@ -70,6 +69,8 @@ TNOBJS = $(TNSRCS:.c=.obj)
 
 all: testutils.lib $(TARGETS)
 
+.c: ../src/test
+
 .obj.exe:
   wlink SYS $(SYSTEM) libpath $(LIBPATH) lib {$(LIBS)} op q op el file {$<} name $@
 
@@ -81,9 +82,6 @@ testvulkan.obj: testvulkan.c
   # new vulkan headers result in lots of W202 warnings
   wcc386 $(CFLAGS) -wcd=202 -fo=$^@ $<
 
-testautomation_stdlib.obj: testautomation_stdlib.c
-  wcc386 $(CFLAGS) -wcd=201 -fo=$^@ $<
-
 testautomation.exe: $(TAOBJS)
   wlink SYS $(SYSTEM) libpath $(LIBPATH) lib {$(LIBS)} op q op el file {$<} name $@
 
diff --git a/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll b/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll
index 878760628d4855ee65934869a1f47050b6920678..e26bcb1c3be11930053e594bc070df85b68d7b89 100755
Binary files a/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll and b/libs/SDL2/x86_64-w64-mingw32/bin/SDL2.dll differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config b/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config
index c1368c020946c7c021bb63e3274e2c9e9eef87ad..65b2fd1996fb92edafa69f4922236005d1e9bef3 100755
--- a/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config
+++ b/libs/SDL2/x86_64-w64-mingw32/bin/sdl2-config
@@ -43,7 +43,7 @@ while test $# -gt 0; do
       echo $exec_prefix
       ;;
     --version)
-      echo 2.30.0
+      echo 2.28.5
       ;;
     --cflags)
       echo -I${prefix}/include/SDL2  -Dmain=SDL_main
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h
index 20c903b2fe4f60836b397cb19af7e07ca19f3071..9ba8f68c6e7966906d5832985a0f4ebc400a8878 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h
index a396d4e02ed20041a742e22ffb4efaa68995db03..7ce823ec5433f2d168889d7ac9239cd9f6ac6171 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h
index 1fa18f49fe078348ec235adca77cbb6374a62e25..1dd816a3826e307f8b7cb436ce95edd28cee7a5c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -209,7 +209,7 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
-#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
+#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__)
 #ifdef __thumb__
 /* The mcr instruction isn't available in thumb mode, use real functions */
 #define SDL_MEMORY_BARRIER_USES_FUNCTION
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h
index bd8e7ab6fa6d8336bf78fe732726782105f65dfe..ccd35982df124d75a8007791bce88da405c76a75 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h
index 83e8a78c783c473184dd1674279fbdb4caafab8e..81161ae5f30633f2d708e9b7806ba005bdd9c21a 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h
index 09d01477d8db63ecf6e9de2483472b9d17641567..4ecbe50785e9d37fcd57325a5301df6d25237997 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -65,8 +65,8 @@ typedef enum
 typedef enum
 {
     SDL_BLENDOPERATION_ADD              = 0x1,  /**< dst + src: supported by all renderers */
-    SDL_BLENDOPERATION_SUBTRACT         = 0x2,  /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
-    SDL_BLENDOPERATION_REV_SUBTRACT     = 0x3,  /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
+    SDL_BLENDOPERATION_SUBTRACT         = 0x2,  /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */
+    SDL_BLENDOPERATION_REV_SUBTRACT     = 0x3,  /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */
     SDL_BLENDOPERATION_MINIMUM          = 0x4,  /**< min(dst, src) : supported by D3D9, D3D11 */
     SDL_BLENDOPERATION_MAXIMUM          = 0x5   /**< max(dst, src) : supported by D3D9, D3D11 */
 } SDL_BlendOperation;
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h
index bd4b044c6dd4ec0f0ed298f4333d3aed79702001..7c351fbb9c98aacbbf9136b3373b04ad321fe456 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h
index dba78086016e4d11489ccdb27cda9972ec0d862d..01322c1829401fecea1b72889dfe4d313c5f0175 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h
index 2a9dd380c2e7b8d4ba5f6e8aec4c13d5becd565d..ed5e97915e314132f76df1747f76a5633dbd2b44 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h
index a4276e6810b2fe059720cb2fe81e234e599e663c..6f51c0831afb94f82f03f92fdec39c622b0b3858 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h
index 591ccac4256adc9f17c7ba0234ff745e1fb71a31..71bc06729b6425ad9a4a96ca12e430409fb50514 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h
index 2df6463ad92f2183c0ac3c936bf1277bdef02e22..31c22616ccb0f276d3cab3caef4a769c5381b0ae 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h
index eccbba2553b4fce528c41741b15d7419597afcf6..9d097031805f33ff18e0a9bf381e22fb0f662dd0 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -131,8 +131,6 @@ typedef enum
     SDL_CONTROLLERTOUCHPADMOTION,      /**< Game controller touchpad finger was moved */
     SDL_CONTROLLERTOUCHPADUP,          /**< Game controller touchpad finger was lifted */
     SDL_CONTROLLERSENSORUPDATE,        /**< Game controller sensor was updated */
-    SDL_CONTROLLERUPDATECOMPLETE_RESERVED_FOR_SDL3,
-    SDL_CONTROLLERSTEAMHANDLEUPDATED,  /**< Game controller Steam handle has changed */
 
     /* Touch events */
     SDL_FINGERDOWN      = 0x700,
@@ -448,7 +446,7 @@ typedef struct SDL_ControllerButtonEvent
  */
 typedef struct SDL_ControllerDeviceEvent
 {
-    Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, ::SDL_CONTROLLERDEVICEREMAPPED, or ::SDL_CONTROLLERSTEAMHANDLEUPDATED */
+    Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, or ::SDL_CONTROLLERDEVICEREMAPPED */
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
     Sint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */
 } SDL_ControllerDeviceEvent;
@@ -582,6 +580,15 @@ typedef struct SDL_QuitEvent
     Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
 } SDL_QuitEvent;
 
+/**
+ *  \brief OS Specific event
+ */
+typedef struct SDL_OSEvent
+{
+    Uint32 type;        /**< ::SDL_QUIT */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+} SDL_OSEvent;
+
 /**
  *  \brief A user-defined event type (event.user.*)
  */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h
index 07498898d3238d6b7c824761c46421e46991c84d..4cad657ec86e7b245a4a3046effd2ed783085932 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -64,7 +64,7 @@ extern "C" {
  * directory of the application as it is uncommon to store resources outside
  * the executable. As such it is not a writable directory.
  *
- * The returned path is guaranteed to end with a path separator ('\\' on
+ * The returned path is guaranteed to end with a path separator ('\' on
  * Windows, '/' on most other platforms).
  *
  * The pointer returned is owned by the caller. Please call SDL_free() on the
@@ -120,7 +120,7 @@ extern DECLSPEC char *SDLCALL SDL_GetBasePath(void);
  * - ...only use letters, numbers, and spaces. Avoid punctuation like "Game
  *   Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
  *
- * The returned path is guaranteed to end with a path separator ('\\' on
+ * The returned path is guaranteed to end with a path separator ('\' on
  * Windows, '/' on most other platforms).
  *
  * The pointer returned is owned by the caller. Please call SDL_free() on the
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h
index 281fa356c63f58cfa5701ff6ae80f1d83c0f6aa8..140054d36ee625c57be7cc976087691b8746f7f4 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -73,8 +73,7 @@ typedef enum
     SDL_CONTROLLER_TYPE_NVIDIA_SHIELD,
     SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
     SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
-    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR,
-    SDL_CONTROLLER_TYPE_MAX
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
 } SDL_GameControllerType;
 
 typedef enum
@@ -524,20 +523,6 @@ extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetFirmwareVersion(SDL_GameCont
  */
 extern DECLSPEC const char * SDLCALL SDL_GameControllerGetSerial(SDL_GameController *gamecontroller);
 
-/**
- * Get the Steam Input handle of an opened controller, if available.
- *
- * Returns an InputHandle_t for the controller that can be used with Steam Input API:
- * https://partner.steamgames.com/doc/api/ISteamInput
- *
- * \param gamecontroller the game controller object to query.
- * \returns the gamepad handle, or 0 if unavailable.
- *
- * \since This function is available since SDL 2.30.0.
- */
-extern DECLSPEC Uint64 SDLCALL SDL_GameControllerGetSteamHandle(SDL_GameController *gamecontroller);
-
-
 /**
  * Check if a controller has been opened and is currently connected.
  *
@@ -613,9 +598,7 @@ extern DECLSPEC void SDLCALL SDL_GameControllerUpdate(void);
  *  and are centered within ~8000 of zero, though advanced UI will allow users to set
  *  or autodetect the dead zone, which varies between controllers.
  *
- *  Trigger axis values range from 0 (released) to SDL_JOYSTICK_AXIS_MAX
- *  (fully pressed) when reported by SDL_GameControllerGetAxis(). Note that this is not the
- *  same range that will be reported by the lower-level SDL_GetJoystickAxis().
+ *  Trigger axis values range from 0 to SDL_JOYSTICK_AXIS_MAX.
  */
 typedef enum
 {
@@ -704,13 +687,8 @@ SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameController
  *
  * The axis indices start at index 0.
  *
- * For thumbsticks, the state is a value ranging from -32768 (up/left)
- * to 32767 (down/right).
- *
- * Triggers range from 0 when released to 32767 when fully pressed, and
- * never return a negative value. Note that this differs from the value
- * reported by the lower-level SDL_GetJoystickAxis(), which normally uses
- * the full range.
+ * The state is a value ranging from -32768 to 32767. Triggers, however, range
+ * from 0 to 32767 (they never return a negative value).
  *
  * \param gamecontroller a game controller
  * \param axis an axis index (one of the SDL_GameControllerAxis values)
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h
index 4fffa5f3e87df75d287da5c6ed0e795ab49d7768..db70b4dd843d983dea8988a60b12f92a739faa0a 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_guid.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_guid.h
index 7daa5f1f585c3d7482108e915ea0ea8fa263751b..d964223c62ca79b46bdb6aa69ba9ed4e256d1f9b 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_guid.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_guid.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h
index c9ed847df02387a5f4d5f5fd02055695cd46a5e6..2462a1e47b3731a20f68af4a2d0d9cdfa5c76e59 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hidapi.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hidapi.h
index b9d8ffac3881e2a297da348e8afb832b0b4afea9..0575100357798a4b34365b5f37d0ef57d1cf831c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hidapi.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hidapi.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h
index e775a6509bc0e4834be32411ddadd1cfd0f2a99b..00beef51e29ed9e610182c7db3d88da70a98230f 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -631,110 +631,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
 
-/**
- *  A variable containing a list of arcade stick style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES "SDL_JOYSTICK_ARCADESTICK_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not arcade stick style controllers. This will override SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED "SDL_JOYSTICK_ARCADESTICK_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices that should not be considerd joysticks.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_BLACKLIST_DEVICES "SDL_JOYSTICK_BLACKLIST_DEVICES"
-
-/**
- *  A variable containing a list of devices that should be considered joysticks. This will override SDL_HINT_JOYSTICK_BLACKLIST_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED "SDL_JOYSTICK_BLACKLIST_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of flightstick style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES "SDL_JOYSTICK_FLIGHTSTICK_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not flightstick style controllers. This will override SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED "SDL_JOYSTICK_FLIGHTSTICK_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices known to have a GameCube form factor.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES "SDL_JOYSTICK_GAMECUBE_DEVICES"
-
-/**
- *  A variable containing a list of devices known not to have a GameCube form factor. This will override SDL_HINT_JOYSTICK_GAMECUBE_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED "SDL_JOYSTICK_GAMECUBE_DEVICES_EXCLUDED"
-
 /**
  *  \brief  A variable controlling whether the HIDAPI joystick drivers should be used.
  *
@@ -943,17 +839,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
 
-/**
- *  \brief  A variable controlling whether the HIDAPI driver for the Steam Deck builtin controller should be used.
- *
- *  This variable can be set to the following values:
- *    "0"       - HIDAPI driver is not used
- *    "1"       - HIDAPI driver is used
- *
- *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
- */
-#define SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK "SDL_JOYSTICK_HIDAPI_STEAMDECK"
-
 /**
  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used.
  *
@@ -1080,24 +965,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED"
 
-/**
-  *  A variable controlling whether IOKit should be used for controller handling.
-  *
-  *  This variable can be set to the following values:
-  *    "0"       - IOKit is not used
-  *    "1"       - IOKit is used (the default)
-  */
-#define SDL_HINT_JOYSTICK_IOKIT "SDL_JOYSTICK_IOKIT"
-
-/**
-  *  A variable controlling whether GCController should be used for controller handling.
-  *
-  *  This variable can be set to the following values:
-  *    "0"       - GCController is not used
-  *    "1"       - GCController is used (the default)
-  */
-#define SDL_HINT_JOYSTICK_MFI "SDL_JOYSTICK_MFI"
-
 /**
   *  \brief  A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
   *
@@ -1140,32 +1007,6 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_THREAD "SDL_JOYSTICK_THREAD"
 
-/**
- *  A variable containing a list of throttle style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_THROTTLE_DEVICES "SDL_JOYSTICK_THROTTLE_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not throttle style controllers. This will override SDL_HINT_JOYSTICK_THROTTLE_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_THROTTLE_DEVICES_EXCLUDED "SDL_JOYSTICK_THROTTLE_DEVICES_EXCLUDED"
-
 /**
   *  \brief  A variable controlling whether Windows.Gaming.Input should be used for controller handling.
   *
@@ -1175,45 +1016,6 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_WGI "SDL_JOYSTICK_WGI"
 
-/**
- *  A variable containing a list of wheel style controllers.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_WHEEL_DEVICES "SDL_JOYSTICK_WHEEL_DEVICES"
-
-/**
- *  A variable containing a list of devices that are not wheel style controllers. This will override SDL_HINT_JOYSTICK_WHEEL_DEVICES and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_WHEEL_DEVICES_EXCLUDED "SDL_JOYSTICK_WHEEL_DEVICES_EXCLUDED"
-
-/**
- *  A variable containing a list of devices known to have all axes centered at zero.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES"
-
 /**
  * \brief Determines whether SDL enforces that DRM master is required in order
  *        to initialize the KMSDRM video backend.
@@ -1282,22 +1084,6 @@ extern "C" {
   */
 #define SDL_HINT_LINUX_JOYSTICK_DEADZONES "SDL_LINUX_JOYSTICK_DEADZONES"
 
-/**
- *  \brief A variable controlling the default SDL log levels.
- *
- *  This variable is a comma separated set of category=level tokens that define the default logging levels for SDL applications.
- *
- *  The category can be a numeric category, one of "app", "error", "assert", "system", "audio", "video", "render", "input", "test", or `*` for any unspecified category.
- *
- *  The level can be a numeric level, one of "verbose", "debug", "info", "warn", "error", "critical", or "quiet" to disable that category.
- *
- *  You can omit the category if you want to set the logging level for all categories.
- *
- *  If this hint isn't set, the default log levels are equivalent to:
- *  "app=info,assert=warn,test=verbose,*=error"
- */
-#define SDL_HINT_LOGGING   "SDL_LOGGING"
-
 /**
 *  \brief  When set don't force the SDL app to become a foreground process
 *
@@ -1699,32 +1485,6 @@ extern "C" {
  */
 #define SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE "SDL_RENDER_METAL_PREFER_LOW_POWER_DEVICE"
 
-/**
- *  A variable containing a list of ROG gamepad capable mice.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_ROG_GAMEPAD_MICE "SDL_ROG_GAMEPAD_MICE"
-
-/**
- *  A variable containing a list of devices that are not ROG gamepad capable mice. This will override SDL_HINT_ROG_GAMEPAD_MICE and the built in device list.
- *
- *  The format of the string is a comma separated list of USB VID/PID pairs
- *  in hexadecimal form, e.g.
- *
- *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
- *
- *  The variable can also take the form of @file, in which case the named
- *  file will be loaded and interpreted as the value of the variable.
- */
-#define SDL_HINT_ROG_GAMEPAD_MICE_EXCLUDED "SDL_ROG_GAMEPAD_MICE_EXCLUDED"
-
 /**
  *  \brief  A variable controlling if VSYNC is automatically disable if doesn't reach the enough FPS
  *
@@ -2682,22 +2442,6 @@ extern "C" {
  */
 #define SDL_HINT_TRACKPAD_IS_TOUCH_ONLY "SDL_TRACKPAD_IS_TOUCH_ONLY"
 
-/**
- * Cause SDL to call dbus_shutdown() on quit.
- *
- * This is useful as a debug tool to validate memory leaks, but shouldn't ever
- * be set in production applications, as other libraries used by the application
- * might use dbus under the hood and this cause cause crashes if they continue
- * after SDL_Quit().
- *
- * This variable can be set to the following values:
- *   "0"       - SDL will not call dbus_shutdown() on quit (default)
- *   "1"       - SDL will call dbus_shutdown() on quit
- *
- * This hint is available since SDL 2.30.0.
- */
-#define SDL_HINT_SHUTDOWN_DBUS_ON_QUIT "SDL_SHUTDOWN_DBUS_ON_QUIT"
-
 
 /**
  *  \brief  An enumeration of hint priorities
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h
index 561e01099cede911e349969024f9b84bad658c2d..b9b4f622800d7a59285523c1407578ee130c0e32 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h
index 03c7b5a3705af4eb25d296049af1fe23ffd0b7d3..86a37ad1a241688e3ee3e658a824e5a78cba2918 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -298,10 +298,8 @@ extern DECLSPEC void SDLCALL SDL_ClearComposition(void);
 extern DECLSPEC SDL_bool SDLCALL SDL_IsTextInputShown(void);
 
 /**
- * Set the rectangle used to type Unicode text inputs. Native input methods
- * will place a window with word suggestions near it, without covering the
- * text being inputted.
- * 
+ * Set the rectangle used to type Unicode text inputs.
+ *
  * To start text input in a given location, this function is intended to be
  * called before SDL_StartTextInput, although some platforms support moving
  * the rectangle even while text input (and a composition) is active.
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h
index 57a71bd79694d749d3702af58f3813540fb678d8..7106223027e75886652f3a2efd179d82561e350c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h
index 4edc22e9e756c9f69fde1aced4679b63dc228e37..ca59b681cb45d9684223aaa6ab7287e809ced5f2 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_locale.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_locale.h
index 0b6118f0ef8669930b2ce0aa5d4e9628381ae2df..482dbefe765fce9fe2e4248cc5e57e56e71b39b1 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_locale.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_locale.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h
index bd030c6d2d5f27ece4b3a74bd80d8f9b5708d05b..da733c4023d9c9f8ed62668e22ddb00c9f5c1fd4 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@ extern "C" {
  *  By default the application category is enabled at the INFO level,
  *  the assert category is enabled at the WARN level, test is enabled
  *  at the VERBOSE level and all other categories are enabled at the
- *  ERROR level.
+ *  CRITICAL level.
  */
 typedef enum
 {
@@ -352,7 +352,7 @@ extern DECLSPEC void SDLCALL SDL_LogMessage(int category,
  */
 extern DECLSPEC void SDLCALL SDL_LogMessageV(int category,
                                              SDL_LogPriority priority,
-                                             SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(3);
+                                             const char *fmt, va_list ap);
 
 /**
  * The prototype for the log output callback function.
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h
index a66c84b4e5fbc2b45a5deca02e42b08e00ef1c66..5cc8e5913a4e705548739f0718d4878392c8a90e 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h
index 5ace6f2ddee1f8172416650c6fbdcd77e0a11ba9..7896fd1291f9211584447abcb4ab3edf320bc389 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_metal.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_metal.h
index 50f7b2aeb45211ce457bf9c6dc268eb86caa6be6..f36e34878cef20b686f7800fe112a5bd99f6a3b3 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_metal.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_metal.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_misc.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_misc.h
index 113ba7a15693dea7e8fd65d4000fd0fb5ca75c18..13ed9c771835f15abdd16c53b5cf39d999159c65 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_misc.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_misc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h
index 687ff122d2c4fc2ba8616dc9fe30fb9764690100..aa07575738a5640c65e5f5dbc4a55661fe0a093e 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h
index eaa21f293f51721c44eb07d1623fb291f3fb7ada..e679d380890ea02d7a05021152aa183646fa178c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h
index 71e9354550f913f1b76dccb0386a19d51dcd164a..5c3e07ab7d3e4a04fa436767527aa3e570a25d25 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h
index 2bb38c5c0e994443e99ce7b2ac3888d4beed435a..0ba89127ace681fa97744e94bad4728c59be9b53 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h
index 7e9a1ab8d4d037d06954b6ddd0df8684fb1a3db4..f4465eaa9da8ba3009fa4f3ee51eeecd0689283b 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h
index 96971344d1b863777ef6a567d321167ebeff4765..5e3b717def6cafa080adb200245e9528f0bf7cbc 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h
index 44757cdcf4b7fdae9c499d8c773c2c5fe28e60d7..9abd57b42014a89b2761608bea2ae802ef9e8515 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -61,10 +61,7 @@ typedef enum
     SDL_PIXELTYPE_ARRAYU16,
     SDL_PIXELTYPE_ARRAYU32,
     SDL_PIXELTYPE_ARRAYF16,
-    SDL_PIXELTYPE_ARRAYF32,
-
-    /* This must be at the end of the list to avoid breaking the existing ABI */
-    SDL_PIXELTYPE_INDEX2
+    SDL_PIXELTYPE_ARRAYF32
 } SDL_PixelType;
 
 /** Bitmap pixel order, high bit -> low bit. */
@@ -137,7 +134,6 @@ typedef enum
 #define SDL_ISPIXELFORMAT_INDEXED(format)   \
     (!SDL_ISPIXELFORMAT_FOURCC(format) && \
      ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX1) || \
-      (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX2) || \
       (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX4) || \
       (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX8)))
 
@@ -181,12 +177,6 @@ typedef enum
     SDL_PIXELFORMAT_INDEX1MSB =
         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX1, SDL_BITMAPORDER_1234, 0,
                                1, 0),
-    SDL_PIXELFORMAT_INDEX2LSB =
-        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX2, SDL_BITMAPORDER_4321, 0,
-                               2, 0),
-    SDL_PIXELFORMAT_INDEX2MSB =
-        SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX2, SDL_BITMAPORDER_1234, 0,
-                               2, 0),
     SDL_PIXELFORMAT_INDEX4LSB =
         SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX4, SDL_BITMAPORDER_4321, 0,
                                4, 0),
@@ -286,19 +276,11 @@ typedef enum
     SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_ARGB8888,
     SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_BGRA8888,
     SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_ABGR8888,
-    SDL_PIXELFORMAT_RGBX32 = SDL_PIXELFORMAT_RGBX8888,
-    SDL_PIXELFORMAT_XRGB32 = SDL_PIXELFORMAT_XRGB8888,
-    SDL_PIXELFORMAT_BGRX32 = SDL_PIXELFORMAT_BGRX8888,
-    SDL_PIXELFORMAT_XBGR32 = SDL_PIXELFORMAT_XBGR8888,
 #else
     SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_ABGR8888,
     SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_BGRA8888,
     SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_ARGB8888,
     SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_RGBA8888,
-    SDL_PIXELFORMAT_RGBX32 = SDL_PIXELFORMAT_XBGR8888,
-    SDL_PIXELFORMAT_XRGB32 = SDL_PIXELFORMAT_BGRX8888,
-    SDL_PIXELFORMAT_BGRX32 = SDL_PIXELFORMAT_XRGB8888,
-    SDL_PIXELFORMAT_XBGR32 = SDL_PIXELFORMAT_RGBX8888,
 #endif
 
     SDL_PIXELFORMAT_YV12 =      /**< Planar mode: Y + V + U  (3 planes) */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h
index 6e67b4577a3d040835a83fdc5e6332a33cc0bab5..d2a7e052d7b19051d020bb240856fbe6080e1af8 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -166,12 +166,6 @@
 #define WINAPI_FAMILY_WINRT 0
 #endif /* HAVE_WINAPIFAMILY_H */
 
-#if (HAVE_WINAPIFAMILY_H) && defined(WINAPI_FAMILY_PHONE_APP)
-#define SDL_WINAPI_FAMILY_PHONE (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
-#else
-#define SDL_WINAPI_FAMILY_PHONE 0
-#endif
-
 #if WINAPI_FAMILY_WINRT
 #undef __WINRT__
 #define __WINRT__ 1
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h
index 0520065cebbb135035665cf95402a2b15b381d1a..1d75704c421c42b244f68b93edda5694f73d5c31 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h
index 3f69dc9f26011db121417874daa9ccbb1043f708..d8ceb894369194b5a0da17b8b4117ebf2edf0a88 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h
index 5ce1f0b4517fa856ad7ee07e8c14fdf2f33f7c7a..9611a311ce83bc165a1ea968a51d4f968f9557d3 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h
index b7135bb9dd46e73b4de07762cda78cc6b292bf3e..2d3f07366209ba01531b878102b28599b256725f 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -42,7 +42,7 @@
  *  of the many good 3D engines.
  *
  *  These functions must be called from the main thread.
- *  See this bug for details: https://github.com/libsdl-org/SDL/issues/986
+ *  See this bug for details: http://bugzilla.libsdl.org/show_bug.cgi?id=1995
  */
 
 #ifndef SDL_render_h_
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h
index ee42f8421d75d3d1e8a00051725414503c7ff132..4455a08b6289e407412cfb0c59b8d8022ea49d98 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_revision.h
@@ -1,7 +1,7 @@
 /* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.30.0-0-g859844eae (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40 (" SDL_VENDOR_INFO ")"
 #else
-#define SDL_REVISION "SDL-release-2.30.0-0-g859844eae"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40"
 #endif
 #define SDL_REVISION_NUMBER 0
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h
index 9dd99f92b1541ba73386aeed906b16d4db415d17..8615cb542959def634d4a634cd24f24d3a5104a6 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h
index fe13d5b7aaad9378e49005640b0c7641cf0512dc..a960a7991c61accff7874c9c75d92099b350b858 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h
index 8b89ef6a526d45f11d7b3ac64234519df2164b22..9ecce44b17be8469a1572afe95b2ff8a323045bf 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_sensor.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h
index 4783cf290e95eec1a2e5b3f3a2ee5b7f94dcbf33..f66babc011339d5729fee081235f8f57815275c2 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h
index 0035a357cf8e70d0e201413e726b149db96acfd3..182ed86ee371194ec6f45229626fa395472d0f8d 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -257,7 +257,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIs64 PRIs64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIs64 "I64d"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIs64 "ld"
 #else
 #define SDL_PRIs64 "lld"
@@ -268,7 +268,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIu64 PRIu64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIu64 "I64u"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIu64 "lu"
 #else
 #define SDL_PRIu64 "llu"
@@ -279,7 +279,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIx64 PRIx64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIx64 "I64x"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIx64 "lx"
 #else
 #define SDL_PRIx64 "llx"
@@ -290,7 +290,7 @@ typedef uint64_t Uint64;
 #define SDL_PRIX64 PRIX64
 #elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIX64 "I64X"
-#elif defined(__LP64__) && !defined(__APPLE__)
+#elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIX64 "lX"
 #else
 #define SDL_PRIX64 "llX"
@@ -336,9 +336,7 @@ typedef uint64_t Uint64;
 #define SDL_PRINTF_FORMAT_STRING
 #define SDL_SCANF_FORMAT_STRING
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber )
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber )
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber )
 #else
 #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */
 #include <sal.h>
@@ -364,14 +362,10 @@ typedef uint64_t Uint64;
 #endif
 #if defined(__GNUC__)
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __printf__, fmtargnumber, fmtargnumber+1 )))
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber ) __attribute__(( format( __printf__, fmtargnumber, 0 )))
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber ) __attribute__ (( format( __scanf__, fmtargnumber, fmtargnumber+1 )))
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber ) __attribute__(( format( __scanf__, fmtargnumber, 0 )))
 #else
 #define SDL_PRINTF_VARARG_FUNC( fmtargnumber )
-#define SDL_PRINTF_VARARG_FUNCV( fmtargnumber )
 #define SDL_SCANF_VARARG_FUNC( fmtargnumber )
-#define SDL_SCANF_VARARG_FUNCV( fmtargnumber )
 #endif
 #endif /* SDL_DISABLE_ANALYZE_MACROS */
 
@@ -609,11 +603,11 @@ extern DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str2);
 extern DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t len);
 
 extern DECLSPEC int SDLCALL SDL_sscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, ...) SDL_SCANF_VARARG_FUNC(2);
-extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, SDL_SCANF_FORMAT_STRING const char *fmt, va_list ap) SDL_SCANF_VARARG_FUNCV(2);
+extern DECLSPEC int SDLCALL SDL_vsscanf(const char *text, const char *fmt, va_list ap);
 extern DECLSPEC int SDLCALL SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ... ) SDL_PRINTF_VARARG_FUNC(3);
-extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(3);
+extern DECLSPEC int SDLCALL SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap);
 extern DECLSPEC int SDLCALL SDL_asprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
-extern DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(2);
+extern DECLSPEC int SDLCALL SDL_vasprintf(char **strp, const char *fmt, va_list ap);
 
 #ifndef HAVE_M_PI
 #ifndef M_PI
@@ -694,8 +688,8 @@ extern DECLSPEC size_t SDLCALL SDL_iconv(SDL_iconv_t cd, const char **inbuf,
                                          size_t * outbytesleft);
 
 /**
- * This function converts a buffer or string between encodings in one pass,
- * returning a string that must be freed with SDL_free() or NULL on error.
+ * This function converts a buffer or string between encodings in one pass, returning a
+ * string that must be freed with SDL_free() or NULL on error.
  *
  * \since This function is available since SDL 2.0.0.
  */
@@ -704,8 +698,8 @@ extern DECLSPEC char *SDLCALL SDL_iconv_string(const char *tocode,
                                                const char *inbuf,
                                                size_t inbytesleft);
 #define SDL_iconv_utf8_locale(S)    SDL_iconv_string("", "UTF-8", S, SDL_strlen(S)+1)
-#define SDL_iconv_utf8_ucs2(S)      (Uint16 *)SDL_iconv_string("UCS-2", "UTF-8", S, SDL_strlen(S)+1)
-#define SDL_iconv_utf8_ucs4(S)      (Uint32 *)SDL_iconv_string("UCS-4", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs2(S)      (Uint16 *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
+#define SDL_iconv_utf8_ucs4(S)      (Uint32 *)SDL_iconv_string("UCS-4-INTERNAL", "UTF-8", S, SDL_strlen(S)+1)
 #define SDL_iconv_wchar_utf8(S)     SDL_iconv_string("UTF-8", "WCHAR_T", (char *)S, (SDL_wcslen(S)+1)*sizeof(wchar_t))
 
 /* force builds using Clang's static analysis tools to use literal C runtime
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h
index ceeb86bd867e8a657626b20ed45f89cd5637f798..d6ee615c59f0a48bc284fde0b75b0dbb3ee9bee2 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h
index ddae4f8cc1f9ca980837f403101aca74fd7ddd5d..4b7eaddcc0ed9b2033de7ccf7cc00de8a5f58a9d 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -593,8 +593,7 @@ extern DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void
 
 /* Functions used only by GDK */
 #if defined(__GDK__)
-typedef struct XTaskQueueObject *XTaskQueueHandle;
-typedef struct XUser *XUserHandle;
+typedef struct XTaskQueueObject * XTaskQueueHandle;
 
 /**
  * Gets a reference to the global async task queue handle for GDK,
@@ -611,20 +610,6 @@ typedef struct XUser *XUserHandle;
  */
 extern DECLSPEC int SDLCALL SDL_GDKGetTaskQueue(XTaskQueueHandle * outTaskQueue);
 
-/**
- * Gets a reference to the default user handle for GDK.
- *
- * This is effectively a synchronous version of XUserAddAsync, which always
- * prefers the default user and allows a sign-in UI.
- *
- * \param outUserHandle a pointer to be filled in with the default user
- *                      handle.
- * \returns 0 if success, -1 if any error occurs.
- *
- * \since This function is available since SDL 2.28.0.
- */
-extern DECLSPEC int SDLCALL SDL_GDKGetDefaultUser(XUserHandle * outUserHandle);
-
 #endif
 
 /* Ends C function definitions when using C++ */
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h
index 7b8bd6ef996571bbba2e5f1e139a0c9292c88146..b35734deb334508c6fbfcc0b635417a9d2841052 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h
index e5acbee4e31782003083624c56f9d40eac5743bc..80daaafbd9b5dc1e4dfa8f48f5fa97e19caab062 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h
index 4f983350a3944145e8c42be3453d894bba8a1270..341e490facee39061766d2fa4b85c154870611dd 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h
index d977e463f117149f7d27cf3ec35fe65a735557a2..6de63cad6f8b08a5f4f28b9b2e5de0dc65da6b71 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h
index 61a38d09051145431d107793aadffba516e08d92..5fce25ca1856cef2790a13d1895dbdd95cb8a4ad 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h
index e3478318dc069a6087e6dffd23b424764bf96f04..bf34782103a218ef811e65a356ab6f900201aa54 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h
index 620c82116b3f3418cde5195a27e7e2247f19c88e..18a82ffc80f16a989cf37da79ed06a3e5279ff37 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
index a847ccb01ca25d80ffa7b4e36f9a2a8f12f7fa6f..cfe6a14f2a0288bd57cd00d642b4dd9c609a8c21 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h
index bd9e4f8de070ae4ac730e1414b8f4ca951252008..26231dcd6bce9e72d54ddbef532a278762634948 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h
index b5bcb0a0000c49ff42d35284df2c859c9a577ca9..1211371755fdfd7bed0953fe1322fdcb639637a3 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h
index ea9ae5e1ca1d9b5170d336b5f770f9c530fdb893..a27ffc209a95ca3dd105b08dbe8ca4509245fe4c 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h
index 3764b042569eb63323ef6a589a5f3252147d4476..538c7ae3e09caa78990f738337bfbf2db9a86459 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h
index 9bd143252cefbdff77396b68ea54132b1859f16f..f959177d2336b5cf649d4d12a41cf76bf7a52578 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h
index 344646aa8b24a589b63482528441afbd296f88f8..0035a8030ad2cc4751a87d5aea3c032cd3c4944f 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h
index dc7f5363aadce39089dd1399963e541d416028b8..b829bbad5dc08bc47f02c64efc24ac97556ac603 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h
index 8123e432f1e5065b67bf51277110fbd7caf886fd..98f9ad16c647e8ecca4829b0629ae15e767f895e 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h
index f6a5db413df92d8b253614ef723f546b581354b9..c12d4a1c8174997225ba25fe087bfb794e094f48 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h
index e8d33c651371bd2fd29b155f135461f66f6681bb..b5d7192ff2e95a994229a90e668ab003e16e5cab 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h
index 02143ff7a114e9cbe2a6113aa9d7726e2532808d..7585eece563127330f3e236174f55615d9f03ddf 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -58,8 +58,8 @@ typedef struct SDL_version
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_MAJOR_VERSION   2
-#define SDL_MINOR_VERSION   30
-#define SDL_PATCHLEVEL      0
+#define SDL_MINOR_VERSION   28
+#define SDL_PATCHLEVEL      5
 
 /**
  * Macro to determine SDL version program was compiled against.
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h
index fa47d30991df03867c400da2fe80bb32d93457a8..c8b2d7a0d871e1f84cf4bf52f3583f8f5aaaf727 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -1278,8 +1278,7 @@ extern DECLSPEC int SDLCALL SDL_SetWindowFullscreen(SDL_Window * window,
 /**
  * Return whether the window has a surface associated with it.
  *
- * \returns SDL_TRUE if there is a surface associated with the window, or
- *          SDL_FALSE otherwise.
+ * \returns SDL_TRUE if there is a surface associated with the window, or SDL_FALSE otherwise.
  *
  * \since This function is available since SDL 2.28.0.
  *
@@ -1341,11 +1340,6 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurface(SDL_Window * window);
  *
  * This function is equivalent to the SDL 1.2 API SDL_UpdateRects().
  *
- * Note that this function will update _at least_ the rectangles specified,
- * but this is only intended as an optimization; in practice, this might
- * update more of the screen (or all of the screen!), depending on what
- * method SDL uses to send pixels to the system.
- *
  * \param window the window to update
  * \param rects an array of SDL_Rect structures representing areas of the
  *              surface to copy, in pixels
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h
index a47a7d2b6413cbb4f5dcd7534123477697ef71a3..4142ffeba928866354f51bedf3d1b1a9b8a4c3d9 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -36,8 +36,6 @@
 #ifndef SDL_DEPRECATED
 #  if defined(__GNUC__) && (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
 #    define SDL_DEPRECATED __attribute__((deprecated))
-#  elif defined(_MSC_VER)
-#    define SDL_DEPRECATED __declspec(deprecated)
 #  else
 #    define SDL_DEPRECATED
 #  endif
diff --git a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h
index 50a0e6f3b4462c5197bd15d7d22e6a8f36204b46..b5ff3e2049b666eeeb923d234b7179722fd8d6c3 100644
--- a/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h
+++ b/libs/SDL2/x86_64-w64-mingw32/include/SDL2/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake b/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake
index 82dfeab129e3a872175ac18a1cbc351c980616de..0e63829954166a1b637f058307f6202b00ceabfd 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake
@@ -1,6 +1,6 @@
 # sdl2 cmake project-config-version input for ./configure scripts
 
-set(PACKAGE_VERSION "2.30.0")
+set(PACKAGE_VERSION "2.28.5")
 
 if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
   set(PACKAGE_VERSION_COMPATIBLE FALSE)
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a
index fff83b8b3db5a7be3ce74c842f901582e8a29598..0fe5391a1457715205263c169f6199cfd7a26ec2 100644
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a
index 1f54d8f34958501767792bc277a6c2f7f3a828b0..25300e1d3568ca89696333347fd0c1eb601b3302 100755
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.dll.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la
index df09985eecb4c61047fea2011b410ad516ffd9dc..3c735a348a8379c56e2f8b53b4905b29266dda31 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2.la
@@ -23,9 +23,9 @@ dependency_libs=' -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -
 weak_library_names=''
 
 # Version information for libSDL2.
-current=3000
-age=3000
-revision=0
+current=2800
+age=2800
+revision=5
 
 # Is this an already installed library?
 installed=yes
@@ -38,4 +38,4 @@ dlopen=''
 dlpreopen=''
 
 # Directory that this library needs to be installed in:
-libdir='/Users/valve/release/SDL2/SDL2-2.30.0/x86_64-w64-mingw32/lib'
+libdir='/Users/valve/release/SDL2/SDL2-2.28.5/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a
index 3b5999fa2aae9fe8d71d98fcf51eae363805304e..9bb1d7d3c074500270d16864353095287a72ee4c 100644
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la
index d9f34a788284fda81547bb405c2803b203d59518..0a5cd1126d4ee14755bb6f5ec9ed24d5a0b2d564 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2_test.la
@@ -38,4 +38,4 @@ dlopen=''
 dlpreopen=''
 
 # Directory that this library needs to be installed in:
-libdir='/Users/valve/release/SDL2/SDL2-2.30.0/x86_64-w64-mingw32/lib'
+libdir='/Users/valve/release/SDL2/SDL2-2.28.5/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a
index ded236c5b08c906f09b8fb2f33ce36f8b8c2c887..0845ae4c7decda341463762ac5c1538ff81bf6ec 100644
Binary files a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a and b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.a differ
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la
index 3adf979fed9fad1451a5bc86340a4584e9a048b9..13216dfb375f77d09919ccb939b710e6c5b21dcb 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/libSDL2main.la
@@ -38,4 +38,4 @@ dlopen=''
 dlpreopen=''
 
 # Directory that this library needs to be installed in:
-libdir='/Users/valve/release/SDL2/SDL2-2.30.0/x86_64-w64-mingw32/lib'
+libdir='/Users/valve/release/SDL2/SDL2-2.28.5/x86_64-w64-mingw32/lib'
diff --git a/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc b/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc
index a23ea3051df62f15caaf2a636329ad8625620928..56b88c4ef1dc3b7eae2a7cc3f5cd4232bc793c52 100644
--- a/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc
+++ b/libs/SDL2/x86_64-w64-mingw32/lib/pkgconfig/sdl2.pc
@@ -1,13 +1,13 @@
 # sdl pkg-config source file
 
-prefix=/usr/local/x86_64-w64-mingw32
+prefix=/x86_64-w64-mingw32
 exec_prefix=${prefix}
 libdir=${exec_prefix}/lib
 includedir=${prefix}/include
 
 Name: sdl2
 Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
-Version: 2.30.0
+Version: 2.28.5
 Requires.private: 
 Conflicts:
 Libs: -L${libdir}  -lmingw32 -lSDL2main -lSDL2 -mwindows 
diff --git a/libs/SDL2/x86_64-w64-mingw32/share/aclocal/sdl2.m4 b/libs/SDL2/x86_64-w64-mingw32/share/aclocal/sdl2.m4
index 274753b118aaf3184843800cc2297b9de568891b..75b60f6ea9338d050b32fd19b5214ef9c1024afa 100644
--- a/libs/SDL2/x86_64-w64-mingw32/share/aclocal/sdl2.m4
+++ b/libs/SDL2/x86_64-w64-mingw32/share/aclocal/sdl2.m4
@@ -9,9 +9,8 @@
 # * also look for SDL2.framework under Mac OS X
 # * removed HP/UX 9 support.
 # * updated for newer autoconf.
-# * (v3) use $PKG_CONFIG for pkg-config cross-compiling support
 
-# serial 3
+# serial 2
 
 dnl AM_PATH_SDL2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
 dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
@@ -55,7 +54,7 @@ AC_ARG_VAR(SDL2_FRAMEWORK, [Path to SDL2.framework])
 
   if test "x$sdl_pc" = xyes ; then
     no_sdl=""
-    SDL2_CONFIG="$PKG_CONFIG sdl2"
+    SDL2_CONFIG="pkg-config sdl2"
   else
     as_save_PATH="$PATH"
     if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then
diff --git a/libs/miniupnpc/include/igd_desc_parse.h b/libs/miniupnpc/include/miniupnpc/igd_desc_parse.h
similarity index 100%
rename from libs/miniupnpc/include/igd_desc_parse.h
rename to libs/miniupnpc/include/miniupnpc/igd_desc_parse.h
diff --git a/libs/miniupnpc/include/miniupnpc.h b/libs/miniupnpc/include/miniupnpc/miniupnpc.h
similarity index 100%
rename from libs/miniupnpc/include/miniupnpc.h
rename to libs/miniupnpc/include/miniupnpc/miniupnpc.h
diff --git a/libs/miniupnpc/include/miniupnpc_declspec.h b/libs/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
similarity index 100%
rename from libs/miniupnpc/include/miniupnpc_declspec.h
rename to libs/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
diff --git a/libs/miniupnpc/include/miniupnpctypes.h b/libs/miniupnpc/include/miniupnpc/miniupnpctypes.h
similarity index 100%
rename from libs/miniupnpc/include/miniupnpctypes.h
rename to libs/miniupnpc/include/miniupnpc/miniupnpctypes.h
diff --git a/libs/miniupnpc/include/miniwget.h b/libs/miniupnpc/include/miniupnpc/miniwget.h
similarity index 100%
rename from libs/miniupnpc/include/miniwget.h
rename to libs/miniupnpc/include/miniupnpc/miniwget.h
diff --git a/libs/miniupnpc/include/portlistingparse.h b/libs/miniupnpc/include/miniupnpc/portlistingparse.h
similarity index 100%
rename from libs/miniupnpc/include/portlistingparse.h
rename to libs/miniupnpc/include/miniupnpc/portlistingparse.h
diff --git a/libs/miniupnpc/include/upnpcommands.h b/libs/miniupnpc/include/miniupnpc/upnpcommands.h
similarity index 100%
rename from libs/miniupnpc/include/upnpcommands.h
rename to libs/miniupnpc/include/miniupnpc/upnpcommands.h
diff --git a/libs/miniupnpc/include/upnpdev.h b/libs/miniupnpc/include/miniupnpc/upnpdev.h
similarity index 100%
rename from libs/miniupnpc/include/upnpdev.h
rename to libs/miniupnpc/include/miniupnpc/upnpdev.h
diff --git a/libs/miniupnpc/include/upnperrors.h b/libs/miniupnpc/include/miniupnpc/upnperrors.h
similarity index 100%
rename from libs/miniupnpc/include/upnperrors.h
rename to libs/miniupnpc/include/miniupnpc/upnperrors.h
diff --git a/libs/miniupnpc/include/upnpreplyparse.h b/libs/miniupnpc/include/miniupnpc/upnpreplyparse.h
similarity index 100%
rename from libs/miniupnpc/include/upnpreplyparse.h
rename to libs/miniupnpc/include/miniupnpc/upnpreplyparse.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 160174080c44996c49d8fafa91e2ff6a297acee5..20caecf7bd6a65a20631318799016da319d3f13d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -134,10 +134,13 @@ add_dependencies(SRB2SDL2 _SRB2_reconf)
 
 if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
 	target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase")
-	if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}")
+	if("${SRB2_CONFIG_STATIC_STDLIB}")
 		# On MinGW with internal libraries, link the standard library statically
 		target_link_options(SRB2SDL2 PRIVATE "-static")
 	endif()
+	if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+		target_link_options(SRB2SDL2 PRIVATE "-Wl,--large-address-aware")
+	endif()
 endif()
 
 target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
@@ -173,19 +176,16 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
 	target_compile_definitions(SRB2SDL2 PRIVATE -DMACOSX)
 endif()
 
-target_link_libraries(SRB2SDL2 PRIVATE gme)
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_GME)
-if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
-	# this sucks but gme doesn't use modern cmake to delineate public headers
-	target_include_directories(SRB2SDL2 PRIVATE "${libgme_SOURCE_DIR}")
+if("${SRB2_CONFIG_USE_GME}")
+	target_link_libraries(SRB2SDL2 PRIVATE gme)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_GME)
+	if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
+		# this sucks but gme doesn't use modern cmake to delineate public headers
+		target_include_directories(SRB2SDL2 PRIVATE "${libgme_SOURCE_DIR}")
+	endif()
 endif()
 
-target_link_libraries(SRB2SDL2 PRIVATE openmpt)
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_OPENMPT)
-
-target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB PNG::PNG CURL::libcurl)
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_ZLIB -DHAVE_PNG -DHAVE_CURL -D_LARGEFILE64_SOURCE)
-target_sources(SRB2SDL2 PRIVATE apng.c)
+target_compile_definitions(SRB2SDL2 PRIVATE -D_LARGEFILE64_SOURCE)
 
 set(SRB2_HAVE_THREADS ON)
 target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_THREADS)
@@ -243,6 +243,7 @@ target_compile_options(SRB2SDL2 PRIVATE
 	# This is a direct translation from versions.mk
 	$<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>:
 		-Wall
+		-Wextra
 		-Wno-trigraphs
 		-W # Was controlled by RELAXWARNINGS
 		-Wfloat-equal
@@ -310,11 +311,7 @@ target_compile_options(SRB2SDL2 PRIVATE
 
 		$<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,8.1.0>:
 			-Wno-error=format-overflow
-			-Wno-error=stringop-truncation
-			-Wno-error=stringop-overflow
 			-Wno-format-overflow
-			-Wno-stringop-truncation
-			-Wno-stringop-overflow
 			-Wno-error=multistatement-macros
 		>
 
@@ -327,7 +324,9 @@ target_compile_options(SRB2SDL2 PRIVATE
 	$<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
 		-Wall
 		-Wno-absolute-value
+		-Wextra
 		-Wno-trigraphs
+		-Wconditional-uninitialized
 		-Wno-error=non-literal-null-conversion
 		-Wno-error=constant-conversion
 		-Wno-error=unused-but-set-variable
@@ -344,6 +343,9 @@ target_compile_options(SRB2SDL2 PRIVATE
 	# C++, GNU, Clang and Apple Clang
 	$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<C_COMPILER_ID:GNU>,$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
 		-Wall
+		-Wextra
+		-Wno-trigraphs
+		-Wconditional-uninitialized
 	>
 
 	# C++, MSVC
@@ -399,8 +401,66 @@ if(SRB2_CONFIG_PROFILEMODE AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
 endif()
 
 add_subdirectory(sdl)
-if(SRB2_CONFIG_ENABLE_TESTS)
-	add_subdirectory(tests)
+
+if(TARGET ZLIB::ZLIB)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_ZLIB)
+	message(STATUS "Zlib Found")
+else()
+	message(STATUS "No Zlib Found")
+endif()
+
+if(TARGET PNG::PNG)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_PNG)
+	target_sources(SRB2SDL2 PRIVATE apng.c ${libapng_HEADER})
+	target_include_directories(SRB2SDL2 PRIVATE ${libapng_INCLUDE_DIRS} ${libpng_BINARY_DIR})
+	#message(STATUS "libpng inc DIRS at ${libapng_INCLUDE_DIRS}")
+	#message(STATUS "libpng bin DIRS at ${libpng_BINARY_DIR}")
+	#message(STATUS "png.h at ${libapng_HEADER}")
+	message(STATUS "libpng Found")
+else()
+	message(STATUS "No libpng Found")
+endif()
+
+if(TARGET PNG::PNG AND TARGET ZLIB::ZLIB)
+#libpng links zlib too?
+target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG)
+endif()
+
+if(NOT TARGET PNG::PNG AND TARGET ZLIB::ZLIB)
+#got no libpng? we need zlib
+target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB)
+endif()
+
+if(TARGET gme::gme)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_GME)
+	target_link_libraries(SRB2SDL2 PRIVATE gme::gme)
+	message(STATUS "libgme Found")
+else()
+	message(STATUS "No libgme Found")
+endif()
+
+if(TARGET libopenmpt::libopenmpt)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_OPENMPT)
+	target_link_libraries(SRB2SDL2 PRIVATE libopenmpt::libopenmpt)
+	message(STATUS "libopenmpt Found")
+else()
+	message(STATUS "No libopenmpt Found")
+endif()
+
+if(TARGET CURL::libcurl)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_CURL)
+	target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl)
+	message(STATUS "libcurl Found")
+else()
+	message(STATUS "No libcurl Found")
+endif()
+
+if(TARGET miniupnpc::miniupnpc)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MINIUPNPC)
+	target_link_libraries(SRB2SDL2 PRIVATE miniupnpc::miniupnpc)
+	message(STATUS "miniupnpc Found")
+else()
+	message(STATUS "No miniupnpc Found")
 endif()
 
 # strip debug symbols into separate file when using gcc.
diff --git a/src/Makefile b/src/Makefile
index 6dba19c2418d9ee465b435b40332245762ecd21f..40037834d3b2831f92a9897ea51336060addfc24 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -47,8 +47,6 @@
 # HAVE_MINIUPNPC=1 - Enable automated port forwarding.
 #                    Already enabled by default for 32-bit
 #                    Windows.
-# NOPNG=1 - Disable PNG graphics support. (TODO: double
-#           check netplay compatible.)
 # NOCURL=1 - Disable libcurl--HTTP capability.
 # NOGME=1 - Disable game music emu, retro VGM support.
 # NOOPENMPT=1 - Disable module (tracker) music support.
@@ -69,8 +67,6 @@
 # NOEXECINFO=1 - Disable stack trace dump support
 # DEBUGMODE=1 - Enable various debugging capabilities.
 #               Also disables optimizations.
-# NOZLIB=1 - Disable some compression capability. Implies
-#            NOPNG=1.
 #
 # Development flags:
 #
diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk
index d132ecc9e69517a3536eccad071fd5841ebb2a91..59806862d50d884329ab5183d1061b15987c9d01 100644
--- a/src/Makefile.d/features.mk
+++ b/src/Makefile.d/features.mk
@@ -22,8 +22,6 @@ ifndef NOMD5
 sources+=md5.c
 endif
 
-ifndef NOZLIB
-ifndef NOPNG
 ifdef PNG_PKGCONFIG
 $(eval $(call Use_pkg_config,PNG_PKGCONFIG))
 else
@@ -36,8 +34,6 @@ opts+=-D_LARGEFILE64_SOURCE
 endif
 opts+=-DHAVE_PNG
 sources+=apng.c
-endif
-endif
 
 ifndef NOCURL
 CURLCONFIG?=curl-config
diff --git a/src/Makefile.d/versions.mk b/src/Makefile.d/versions.mk
index b639ad9a13cb45a898d5c3d5b9d773b3203c2daf..7c130d90846ab6f4199eb618ee918fdb6999e5cc 100644
--- a/src/Makefile.d/versions.mk
+++ b/src/Makefile.d/versions.mk
@@ -135,11 +135,7 @@ ifdef GCC71
 endif
 ifdef GCC81
  WFLAGS+=-Wno-error=format-overflow
- WFLAGS+=-Wno-error=stringop-truncation
- WFLAGS+=-Wno-error=stringop-overflow
  WFLAGS+=-Wno-format-overflow
- WFLAGS+=-Wno-stringop-truncation
- WFLAGS+=-Wno-stringop-overflow
  WFLAGS+=-Wno-error=multistatement-macros
 endif
 
diff --git a/src/android/i_video.c b/src/android/i_video.c
index bf0decb74118385ff2b776d8d470e5ea3a03a2ba..896a5b899c008197df570376d2e0c406a1a8351e 100644
--- a/src/android/i_video.c
+++ b/src/android/i_video.c
@@ -11,8 +11,6 @@
 rendermode_t rendermode = render_soft;
 rendermode_t chosenrendermode = render_none;
 
-boolean highcolor = false;
-
 boolean allow_fullscreen = false;
 
 
diff --git a/src/b_bot.c b/src/b_bot.c
index c8228e840f751b676a00e920cde61dcb8f06311c..af57d65ecf6e3c24e725ed38b9533b9ab6509763 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -589,8 +589,9 @@ void B_RespawnBot(INT32 playernum)
 	}
 	else
 		P_SetMobjState(tails, S_PLAY_FALL);
-	P_SetScale(tails, sonic->scale);
+	P_SetScale(tails, sonic->scale, false);
 	tails->destscale = sonic->destscale;
+	tails->old_scale = sonic->old_scale;
 }
 
 void B_HandleFlightIndicator(player_t *player)
diff --git a/src/blua/lvm.c b/src/blua/lvm.c
index b74fef4ee3d72d3081fdb11776ab759c337020f3..627685b389dcdea401dffc72ed02ef061394a1b6 100644
--- a/src/blua/lvm.c
+++ b/src/blua/lvm.c
@@ -134,7 +134,7 @@ void luaV_gettable (lua_State *L, TValue *t, TValue *key, StkId val) {
 void luaV_settable (lua_State *L, TValue *t, TValue *key, StkId val) {
   int loop;
   for (loop = 0; loop < MAXTAGLOOP; loop++) {
-    TValue *tm;
+    TValue *tm = NULL;
     if (ttistable(t)) {  /* `t' is a table? */
       Table *h = hvalue(t);
       TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
diff --git a/src/command.c b/src/command.c
index 87d4f893fe6683cd21e93a8663dd71b30dce57af..a46cc98bcde4ad01557a31e439994135341a5c06 100644
--- a/src/command.c
+++ b/src/command.c
@@ -2060,16 +2060,16 @@ void CV_StealthSet(consvar_t *var, const char *value)
   */
 static void CV_SetValueMaybeStealth(consvar_t *var, INT32 value, boolean stealth)
 {
-	char val[SKINNAMESIZE+1];
+	char val[SKINNAMESIZE+1] = "None";
 
 	if (var == &cv_forceskin) // Special handling.
 	{
 		const char *tmpskin = NULL;
 		if ((value < 0) || (value >= numskins))
-			tmpskin = "None";
+			;
 		else
 			tmpskin = skins[value]->name;
-		strncpy(val, tmpskin, SKINNAMESIZE);
+		memcpy(val, tmpskin, SKINNAMESIZE);
 	}
 	else
 		sprintf(val, "%d", value);
diff --git a/src/console.c b/src/console.c
index 0d296ca74138c46564878e911b7892eb64fec145..69160c24004ca45f1c561d6b205f3ffc1a5a71e5 100644
--- a/src/console.c
+++ b/src/console.c
@@ -70,14 +70,9 @@ static boolean consoleready;  // console prompt is ready
        INT32 con_destlines; // vid lines used by console at final position
 static INT32 con_curlines;  // vid lines currently used by console
 
-       INT32 con_clipviewtop; // (useless)
-
 static UINT8  con_hudlines;             // number of console heads up message lines
 static UINT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines
 
-       INT32 con_clearlines;      // top screen lines to refresh when view reduced
-       boolean con_hudupdate;   // when messages scroll, we need a backgrnd refresh
-
 // console text output
 static char *con_line;          // console text output current line
 static size_t con_cx;           // cursor position in current line
@@ -473,9 +468,6 @@ void CON_Init(void)
 
 	Lock_state();
 
-	//note: CON_Ticker should always execute at least once before D_Display()
-	con_clipviewtop = -1; // -1 does not clip
-
 	con_hudlines = atoi(cons_hudlines.defaultvalue);
 
 	Unlock_state();
@@ -751,7 +743,6 @@ void CON_ToggleOff(void)
 	con_curlines = 0;
 	CON_ClearHUD();
 	con_forcepic = 0;
-	con_clipviewtop = -1; // remove console clipping of view
 
 	I_UpdateMouseGrab();
 
@@ -800,18 +791,6 @@ void CON_Ticker(void)
 			CON_ChangeHeight();
 	}
 
-	// clip the view, so that the part under the console is not drawn
-	con_clipviewtop = -1;
-	if (cons_backpic.value) // clip only when using an opaque background
-	{
-		if (con_curlines > 0)
-			con_clipviewtop = con_curlines - viewwindowy - 1 - 10;
-		// NOTE: BIG HACK::SUBTRACT 10, SO THAT WATER DON'T COPY LINES OF THE CONSOLE
-		//       WINDOW!!! (draw some more lines behind the bottom of the console)
-		if (con_clipviewtop < 0)
-			con_clipviewtop = -1; // maybe not necessary, provided it's < 0
-	}
-
 	// check if console ready for prompt
 	if (con_destlines >= minheight)
 		consoleready = true;
@@ -882,12 +861,6 @@ static void CON_InputDelSelection(void)
 
 	Lock_state();
 
-	if (!input_cur)
-	{
-		Unlock_state();
-		return;
-	}
-
 	if (input_cur > input_sel)
 	{
 		start = input_sel;
@@ -949,8 +922,6 @@ static void CON_InputDelChar(void)
 //
 boolean CON_Responder(event_t *ev)
 {
-	static UINT8 consdown = false; // console is treated differently due to rare usage
-
 	// sequential completions a la 4dos
 	static char completioncmd[80 + sizeof("find ")] = "find ";
 	static char *completion = &completioncmd[sizeof("find ")-1];
@@ -970,32 +941,28 @@ boolean CON_Responder(event_t *ev)
 	// let go keyup events, don't eat them
 	if (ev->type != ev_keydown && ev->type != ev_text && ev->type != ev_console)
 	{
-		if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1])
-			consdown = false;
 		return false;
 	}
 
 	key = ev->key;
 
 	// check for console toggle key
-	if (ev->type != ev_console)
+	if (ev->type == ev_keydown)
 	{
 		if (modeattacking || metalrecording || marathonmode)
 			return false;
 
-		if (ev->type == ev_keydown && ((key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) && !shiftdown))
+		if ((key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) && !shiftdown)
 		{
-			if (consdown) // ignore repeat
-				return true;
+			I_SetTextInputMode(con_destlines == 0); // inverse, since this is changed next tic.
 			consoletoggle = true;
-			consdown = true;
 			return true;
 		}
 
 		// check other keys only if console prompt is active
 		if (!consoleready && key < NUMINPUTS) // metzgermeister: boundary check!!
 		{
-			if (ev->type == ev_keydown && !menuactive && bindtable[key])
+			if (!menuactive && bindtable[key])
 			{
 				COM_BufAddText(bindtable[key]);
 				COM_BufAddText("\n");
@@ -1007,14 +974,14 @@ boolean CON_Responder(event_t *ev)
 		// escape key toggle off console
 		if (key == KEY_ESCAPE)
 		{
+			I_SetTextInputMode(false);
 			consoletoggle = true;
 			return true;
 		}
 	}
-
-	if (ev->type == ev_text)
+	else if (ev->type == ev_text)
 	{
-		if (!consoletoggle)
+		if (!consoletoggle && consoleready)
 			CON_InputAddChar(key);
 		return true;
 	}
@@ -1063,7 +1030,7 @@ boolean CON_Responder(event_t *ev)
 	}
 	else if (key == KEY_BACKSPACE)
 	{
-		if (ctrldown)
+		if (ctrldown && input_cur != 0)
 		{
 			input_sel = M_JumpWordReverse(inputlines[inputline], input_cur);
 			CON_InputDelSelection();
@@ -1121,7 +1088,9 @@ boolean CON_Responder(event_t *ev)
 
 		if (key == 'x' || key == 'X')
 		{
-			if (input_sel > input_cur)
+			if (input_sel == input_cur) // Don't replace the clipboard without a text selection
+				return true;
+			else if (input_sel > input_cur)
 				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
 			else
 				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
@@ -1131,7 +1100,9 @@ boolean CON_Responder(event_t *ev)
 		}
 		else if (key == 'c' || key == 'C')
 		{
-			if (input_sel > input_cur)
+			if (input_sel == input_cur) // Don't replace the clipboard without a text selection
+				return true;
+			else if (input_sel > input_cur)
 				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
 			else
 				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
@@ -1358,9 +1329,6 @@ static void CON_Linefeed(void)
 
 	con_line = &con_buffer[(con_cy%con_totallines)*con_width];
 	memset(con_line, ' ', con_width);
-
-	// make sure the view borders are refreshed if hud messages scroll
-	con_hudupdate = true; // see HU_Erase()
 }
 
 // Outputs text into the console text buffer
@@ -1737,11 +1705,11 @@ static void CON_DrawHudlines(void)
 			}
 			if (c >= con_width)
 				break;
-			if (*p < HU_FONTSTART)
+			if (*p < FONTSTART)
 				;//charwidth = 4 * con_scalefactor;
 			else
 			{
-				//charwidth = (hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
+				//charwidth = (hu_font.chars['A'-FONTSTART]->width) * con_scalefactor;
 				V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
 			}
 		}
@@ -1749,9 +1717,6 @@ static void CON_DrawHudlines(void)
 		//V_DrawCharacter(x, y, (p[c]&0xff) | cv_constextsize.value | V_NOSCALESTART, true);
 		y += charheight;
 	}
-
-	// top screen lines that might need clearing when view is reduced
-	con_clearlines = y; // this is handled by HU_Erase();
 }
 
 // Lactozilla: Draws the console's background picture.
@@ -1817,10 +1782,6 @@ static void CON_DrawConsole(void)
 	if (con_curlines <= 0)
 		return;
 
-	//FIXME: refresh borders only when console bg is translucent
-	con_clearlines = con_curlines; // clear console draw from view borders
-	con_hudupdate = true; // always refresh while console is on
-
 	// draw console background
 	if (cons_backpic.value || con_forcepic)
 		CON_DrawBackpic();
diff --git a/src/console.h b/src/console.h
index f22f8dcbc18e595b6fb57b942bca8c0eb3cf15e2..6ad1dba1e458c19d47bb2599f9d3a87ce0fb17c1 100644
--- a/src/console.h
+++ b/src/console.h
@@ -34,14 +34,9 @@ extern boolean con_startup;
 // needs explicit screen refresh until we are in the main game loop
 extern boolean con_refresh;
 
-// top clip value for view render: do not draw part of view hidden by console
-extern INT32 con_clipviewtop;
-
 // 0 means console if off, or moving out
 extern INT32 con_destlines;
 
-extern INT32 con_clearlines; // lines of top of screen to refresh
-extern boolean con_hudupdate; // hud messages have changed, need refresh
 extern UINT32 con_scalefactor; // console text scale factor
 
 extern consvar_t cons_backcolor;
diff --git a/src/d_main.c b/src/d_main.c
index 83cb425c98bd76b8b931c91db2e1699682c20a0e..c139650d1eb039a057da10d063f392f33c94fac2 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -408,13 +408,11 @@ static void D_Display(void)
 		case GS_LEVEL:
 			if (!gametic)
 				break;
-			HU_Erase();
 			AM_Drawer();
 			break;
 
 		case GS_INTERMISSION:
 			Y_IntermissionDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -429,13 +427,11 @@ static void D_Display(void)
 
 		case GS_ENDING:
 			F_EndingDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
 		case GS_CUTSCENE:
 			F_CutsceneDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -445,7 +441,6 @@ static void D_Display(void)
 
 		case GS_EVALUATION:
 			F_GameEvaluationDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -455,7 +450,6 @@ static void D_Display(void)
 
 		case GS_CREDITS:
 			F_CreditDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -465,7 +459,6 @@ static void D_Display(void)
 			{
 				// I don't think HOM from nothing drawing is independent...
 				F_WaitingPlayersDrawer();
-				HU_Erase();
 				HU_Drawer();
 			}
 		case GS_DEDICATEDSERVER:
@@ -480,11 +473,21 @@ static void D_Display(void)
 	{
 		wipegamestate = gamestate;
 
-		// clean up border stuff
-		// see if the border needs to be initially drawn
 		if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap)))
 		{
 			// draw the view directly
+			if (cv_debug)
+			{
+				r_renderwalls = cv_renderwalls.value;
+				r_renderfloors = cv_renderfloors.value;
+				r_renderthings = cv_renderthings.value;
+			}
+			else
+			{
+				r_renderwalls = true;
+				r_renderfloors = true;
+				r_renderthings = true;
+			}
 
 			if (!automapactive && !dedicated && cv_renderview.value)
 			{
@@ -506,23 +509,21 @@ static void D_Display(void)
 				// render the second screen
 				if (splitscreen && players[secondarydisplayplayer].mo)
 				{
-	#ifdef HWRENDER
-					if (rendermode != render_soft)
+					viewwindowy = vid.height / 2;
+
+#ifdef HWRENDER
+					if (rendermode == render_opengl)
 						HWR_RenderPlayerView(1, &players[secondarydisplayplayer]);
 					else
-	#endif
+#endif
 					if (rendermode != render_none)
 					{
-						viewwindowy = vid.height / 2;
-						M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0]));
-
 						topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
 
 						R_RenderPlayerView(&players[secondarydisplayplayer]);
-
-						viewwindowy = 0;
-						M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0]));
 					}
+
+					viewwindowy = 0;
 				}
 
 				// Image postprocessing effect
@@ -1512,9 +1513,7 @@ void D_SRB2Main(void)
 	G_LoadGameData(clientGamedata);
 	M_CopyGameData(serverGamedata, clientGamedata);
 
-#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)
 	VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen
-#endif
 
 	// set user default mode or mode set at cmdline
 	SCR_CheckDefaultMode();
diff --git a/src/d_player.h b/src/d_player.h
index 26f17a1a09e114a1d73887acd19338c1245b14a0..95d2f609dab322189fcb3892d7beace6d0fd45dc 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -373,6 +373,16 @@ typedef enum
 	AI_SPINFOLLOW
 } aistatetype_t;
 
+// NiGHTS text
+typedef enum
+{
+	NTV_NONE = 0,
+	NTV_GETSPHERES,
+	NTV_GETMORESPHERES,
+	NTV_BONUSTIMESTART,
+	NTV_BONUSTIMEEND,
+} nightstextvar_t;
+
 
 // ========================================================================
 //                          PLAYER STRUCTURE
@@ -572,7 +582,8 @@ typedef struct player_s
 	// Statistical purposes.
 	tic_t marebegunat; // Leveltime when mare begun
 	tic_t startedtime; // Time which you started this mare with.
-	tic_t finishedtime; // Time it took you to finish the mare (used for display)
+	tic_t finishedtime; // The time it took to destroy the capsule on this mare (used for bonus time display)
+	tic_t lastmaretime; // The time it took to complete the last mare (used for rank display)
 	tic_t lapbegunat; // Leveltime when lap begun
 	tic_t lapstartedtime; // Time which you started this lap with.
 	INT16 finishedspheres; // The spheres you had left upon finishing the mare
@@ -587,7 +598,7 @@ typedef struct player_s
 	UINT8 totalmarebonuslap; // total mare bonus lap
 	INT32 maxlink; // maximum link obtained
 	UINT8 texttimer; // nights_texttime should not be local
-	UINT8 textvar; // which line of NiGHTS text to show -- let's not use cheap hacks
+	UINT8 textvar; // which line of NiGHTS text to show -- see nightstextvar_t
 
 	INT16 lastsidehit, lastlinehit;
 
@@ -603,6 +614,7 @@ typedef struct player_s
 	boolean spectator;
 	boolean outofcoop;
 	boolean removing;
+	boolean muted;
 	UINT8 bot;
 	struct player_s *botleader;
 	UINT16 lastbuttons;
diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c
index 4dbaec8df9f73a5c7d04727942b7f224f4716139..413b366b865c035a08ece29008c30004ea58666e 100644
--- a/src/dedicated/i_system.c
+++ b/src/dedicated/i_system.c
@@ -39,12 +39,6 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #include <ntsecapi.h>
 #undef SystemFunction036
 
-// A little more than the minimum sleep duration on Windows.
-// May be incorrect for other platforms, but we don't currently have a way to
-// query the scheduler granularity. SDL will do what's needed to make this as
-// low as possible though.
-#define MIN_SLEEP_DURATION_MS 2.1
-
 #endif
 #include <stdio.h>
 #include <stdlib.h>
@@ -95,6 +89,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #endif
 #endif
 
+#if defined(UNIXCOMMON)
+#include <poll.h>
+#endif
+
 #if defined (__unix__) || (defined (UNIXCOMMON) && !defined (__APPLE__))
 #include <errno.h>
 #include <sys/wait.h>
@@ -208,6 +206,12 @@ static char returnWadPath[256];
 
 #define MAX_EXIT_FUNCS 32
 
+// A little more than the minimum sleep duration on Windows.
+// May be incorrect for other platforms, but we don't currently have a way to
+// query the scheduler granularity. SDL will do what's needed to make this as
+// low as possible though.
+#define MIN_SLEEP_DURATION_MS 2.1
+
 UINT8 graphics_started = 0;
 
 UINT8 keyboard_started = 0;
@@ -855,50 +859,60 @@ static void I_GetConsoleEvents(void)
 	// we use this when sending back commands
 	event_t ev = {0};
 	char key = 0;
-	ssize_t d;
+	struct pollfd pfd =
+	{
+		.fd = STDIN_FILENO,
+		.events = POLLIN,
+		.revents = 0,
+	};
 
 	if (!consolevent)
 		return;
 
-	ev.type = ev_console;
-	ev.key = 0;
-	if (read(STDIN_FILENO, &key, 1) == -1 || !key)
-		return;
-
-	// we have something
-	// backspace?
-	// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
-	if ((key == tty_erase) || (key == 127) || (key == 8))
+	for (;;)
 	{
-		if (tty_con.cursor > 0)
+		if (poll(&pfd, 1, 0) < 1 || !(pfd.revents & POLLIN))
+			return;
+
+		ev.type = ev_console;
+		ev.key = 0;
+		if (read(STDIN_FILENO, &key, 1) == -1 || !key)
+			return;
+
+		// we have something
+		// backspace?
+		// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
+		if ((key == tty_erase) || (key == 127) || (key == 8))
 		{
-			tty_con.cursor--;
-			tty_con.buffer[tty_con.cursor] = '\0';
-			tty_Back();
+			if (tty_con.cursor > 0)
+			{
+				tty_con.cursor--;
+				tty_con.buffer[tty_con.cursor] = '\0';
+				tty_Back();
+			}
+			ev.key = KEY_BACKSPACE;
 		}
-		ev.key = KEY_BACKSPACE;
-	}
-	else if (key < ' ') // check if this is a control char
-	{
-		if (key == '\n')
+		else if (key < ' ') // check if this is a control char
 		{
-			tty_Clear();
-			tty_con.cursor = 0;
-			ev.key = KEY_ENTER;
+			if (key == '\n')
+			{
+				tty_Clear();
+				tty_con.cursor = 0;
+				ev.key = KEY_ENTER;
+			}
+			else continue;
 		}
-		else return;
-	}
-	else if (tty_con.cursor < sizeof(tty_con.buffer))
-	{
-		// push regular character
-		ev.key = tty_con.buffer[tty_con.cursor] = key;
-		tty_con.cursor++;
-		// print the current line (this is differential)
-		d = write(STDOUT_FILENO, &key, 1);
+		else if (tty_con.cursor < sizeof(tty_con.buffer))
+		{
+			// push regular character
+			ev.key = tty_con.buffer[tty_con.cursor] = key;
+			tty_con.cursor++;
+			// print the current line (this is differential)
+			write(STDOUT_FILENO, &key, 1);
+		}
+		if (ev.key) D_PostEvent(&ev);
+		//tty_FlushIn();
 	}
-	if (ev.key) D_PostEvent(&ev);
-	//tty_FlushIn();
-	(void)d;
 }
 
 #elif defined (_WIN32)
@@ -1571,5 +1585,15 @@ void I_GetCursorPosition(INT32 *x, INT32 *y)
 	(void)y;
 }
 
+void I_SetTextInputMode(boolean active)
+{
+	(void)active;
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return false;
+}
+
 #include "../sdl/dosstr.c"
 
diff --git a/src/dedicated/i_video.c b/src/dedicated/i_video.c
index bb796b6767a1d55990209ba46cd8245377b013d9..2c998117accb71be25850438bdac2ee6c4db0509 100644
--- a/src/dedicated/i_video.c
+++ b/src/dedicated/i_video.c
@@ -5,8 +5,6 @@
 rendermode_t rendermode = render_none;
 rendermode_t chosenrendermode = render_none;
 
-boolean highcolor = false;
-
 boolean allow_fullscreen = false;
 
 consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
diff --git a/src/deh_lua.c b/src/deh_lua.c
index 3600c3554da059091e513c559f7a9e80cff72de2..64fb52fc7423a7486c9d6736762fedd0fcde64ba 100644
--- a/src/deh_lua.c
+++ b/src/deh_lua.c
@@ -11,6 +11,7 @@
 /// \brief Lua SOC library
 
 #include "deh_lua.h"
+#include "g_input.h"
 
 // freeslot takes a name (string only!)
 // and allocates it to the appropriate free slot.
@@ -58,24 +59,19 @@ static inline int lib_freeslot(lua_State *L)
 		}
 		else if (fastcmp(type, "SPR"))
 		{
-			char wad;
 			spritenum_t j;
-			lua_getfield(L, LUA_REGISTRYINDEX, "WAD");
-			wad = (char)lua_tointeger(L, -1);
-			lua_pop(L, 1);
+
+			if (strlen(word) > MAXSPRITENAME)
+				return luaL_error(L, "Sprite name is longer than %d characters\n", MAXSPRITENAME);
+
 			for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++)
 			{
-				if (used_spr[(j-SPR_FIRSTFREESLOT)/8] & (1<<(j%8)))
-				{
-					if (!sprnames[j][4] && memcmp(sprnames[j],word,4)==0)
-						sprnames[j][4] = wad;
+				if (in_bit_array(used_spr, j - SPR_FIRSTFREESLOT))
 					continue; // Already allocated, next.
-				}
 				// Found a free slot!
 				CONS_Printf("Sprite SPR_%s allocated.\n",word);
-				strncpy(sprnames[j],word,4);
-				//sprnames[j][4] = 0;
-				used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
+				strcpy(sprnames[j], word);
+				set_bit_array(used_spr, j - SPR_FIRSTFREESLOT); // Okay, this sprite slot has been named now.
 				// Lua needs to update the value in _G if it exists
 				LUA_UpdateSprName(word, j);
 				lua_pushinteger(L, j);
@@ -454,17 +450,19 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
 	}
 	else if (fastncmp("SPR_",word,4)) {
 		p = word+4;
-		for (i = 0; i < NUMSPRITES; i++)
-			if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
-				// updating overridden sprnames is not implemented for soc parser,
-				// so don't use cache
-				if (mathlib)
-					lua_pushinteger(L, i);
-				else
-					CacheAndPushConstant(L, word, i);
-				return 1;
-			}
-		if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word);
+		i = R_GetSpriteNumByName(p);
+		if (i != NUMSPRITES)
+		{
+			// updating overridden sprnames is not implemented for soc parser,
+			// so don't use cache
+			if (mathlib)
+				lua_pushinteger(L, i);
+			else
+				CacheAndPushConstant(L, word, i);
+			return 1;
+		}
+		else if (mathlib)
+			return luaL_error(L, "sprite '%s' could not be found.\n", word);
 		return 0;
 	}
 	else if (fastncmp("SPR2_",word,5)) {
@@ -596,12 +594,20 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
 		return luaL_error(L, "translation '%s' could not be found.\n", word);
 	}
 
-	// TODO: 2.3: Delete this alias
-	if (fastcmp(word, "BT_USE"))
+	// TODO: 2.3: Delete these aliases
+	else if (fastcmp(word, "BT_USE"))
 	{
 		CacheAndPushConstant(L, word, (lua_Integer)BT_SPIN);
 		return 1;
-	} 
+	}
+	else if (fastcmp(word, "GC_WEPSLOT8") || fastcmp(word, "GC_WEPSLOT9") || fastcmp(word, "GC_WEPSLOT10"))
+	{
+		// Using GC_WEPSLOT7 isn't accurate, but ensures that "if x >= GC_WEPSLOT1 and x <= GC_WEPSLOT10" keeps the intended effect
+		CacheAndPushConstant(L, word, (lua_Integer)GC_WEPSLOT7);
+		if (!mathlib)
+			LUA_Deprecated(L, "GC_WEPSLOT8\"-\"GC_WEPSLOT10", "GC_WEPSLOT1\"-\"GC_WEPSLOT7");
+		return 1;
+	}
 
 	for (i = 0; INT_CONST[i].n; i++)
 		if (fastcmp(word,INT_CONST[i].n)) {
@@ -729,18 +735,18 @@ static inline int lib_getenum(lua_State *L)
 // If a sprname has been "cached" to _G, update it to a new value.
 void LUA_UpdateSprName(const char *name, lua_Integer value)
 {
-	char fullname[9] = "SPR_XXXX";
+	char fullname[4 + MAXSPRITENAME + 1] = "SPR_";
 
 	if (!gL)
 		return;
 
-	strncpy(&fullname[4], name, 4);
+	strcpy(&fullname[4], name);
 	lua_pushstring(gL, fullname);
 	lua_rawget(gL, LUA_GLOBALSINDEX);
 
 	if (!lua_isnil(gL, -1))
 	{
-		lua_pushstring(gL, name);
+		lua_pushstring(gL, fullname);
 		lua_pushinteger(gL, value);
 		lua_rawset(gL, LUA_GLOBALSINDEX);
 	}
diff --git a/src/deh_soc.c b/src/deh_soc.c
index 41eb28a90f91f77c3672b7b35ea919f9a0edf6ef..dda3b2ef4b31352b1579623421cdc2733da56585 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -324,7 +324,7 @@ void readPlayer(MYFILE *f, INT32 num)
 			if (fastcmp(word, "PICNAME"))
 			{
 				SLOTFOUND
-				strncpy(description[num].picname, word2, 8);
+				strncpy(description[num].picname, word2, sizeof(description[num].picname)-1);
 			}
 			else if (fastcmp(word, "DISPLAYNAME"))
 			{
@@ -355,7 +355,7 @@ void readPlayer(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME"))
 			{
 				SLOTFOUND
-				strncpy(description[num].nametag, word2, 8);
+				strncpy(description[num].nametag, word2, sizeof(description[num].nametag)-1);
 			}
 			else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR"))
 			{
@@ -405,7 +405,6 @@ void readfreeslots(MYFILE *f)
 {
 	char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
 	char *word,*type;
-	char *tmp;
 	int i;
 
 	do
@@ -415,10 +414,13 @@ void readfreeslots(MYFILE *f)
 			if (s[0] == '\n')
 				break;
 
-			tmp = strchr(s, '#');
-			if (tmp)
-				*tmp = '\0';
-			if (s == tmp)
+			char *hashtag = strchr(s, '#');
+			char *space = strchr(s, ' ');
+			if (hashtag)
+				*hashtag = '\0';
+			if (space)
+				*space = '\0';
+			if (s == hashtag || s == space)
 				continue; // Skip comment lines, but don't break.
 
 			type = strtok(s, "_");
@@ -440,18 +442,16 @@ void readfreeslots(MYFILE *f)
 				S_AddSoundFx(word, false, 0, false);
 			else if (fastcmp(type, "SPR"))
 			{
+				if (strlen(word) > MAXSPRITENAME)
+					I_Error("Sprite name is longer than %d characters\n", MAXSPRITENAME);
+
 				for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++)
 				{
-					if (used_spr[(i-SPR_FIRSTFREESLOT)/8] & (1<<(i%8)))
-					{
-						if (!sprnames[i][4] && memcmp(sprnames[i],word,4)==0)
-							sprnames[i][4] = (char)f->wad;
+					if (in_bit_array(used_spr, i - SPR_FIRSTFREESLOT))
 						continue; // Already allocated, next.
-					}
 					// Found a free slot!
-					strncpy(sprnames[i],word,4);
-					//sprnames[i][4] = 0;
-					used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now.
+					strcpy(sprnames[i], word);
+					set_bit_array(used_spr, i - SPR_FIRSTFREESLOT); // Okay, this sprite slot has been named now.
 					// Lua needs to update the value in _G if it exists
 					LUA_UpdateSprName(word, i);
 					break;
@@ -1163,7 +1163,7 @@ void readgametype(MYFILE *f, char *gtname)
 	INT16 newgtrankingstype = -1;
 	int newgtinttype = 0;
 	char gtdescription[441];
-	char gtconst[MAXLINELEN];
+	char gtconst[MAXLINELEN+1];
 
 	// Empty strings.
 	gtdescription[0] = '\0';
@@ -1543,6 +1543,12 @@ void readlevelheader(MYFILE *f, INT32 num)
 				P_AddGradesForMare((INT16)(num-1), mare-1, word2);
 			}
 
+			// NiGHTS time limits (per mare)
+			else if (fastncmp(word, "NIGHTSTIME", 10))
+			{
+				P_AddNiGHTSTimes((INT16)(num-1), word2);
+			}
+
 			// Strings that can be truncated
 			else if (fastcmp(word, "SELECTHEADING"))
 			{
@@ -1677,7 +1683,7 @@ void readlevelheader(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "SKYNUM"))
 				mapheaderinfo[num-1]->skynum = (INT16)i;
 			else if (fastcmp(word, "INTERSCREEN"))
-				strncpy(mapheaderinfo[num-1]->interscreen, word2, 8);
+				strncpy(mapheaderinfo[num-1]->interscreen, word2, sizeof(mapheaderinfo[num-1]->interscreen)-1);
 			else if (fastcmp(word, "PRECUTSCENENUM"))
 				mapheaderinfo[num-1]->precutscenenum = (UINT8)i;
 			else if (fastcmp(word, "CUTSCENENUM"))
@@ -2294,7 +2300,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 					char name[34];
 					name[0] = '\x82'; // color yellow
 					name[1] = 0;
-					strncat(name, word2, 33);
+					strncat(name, word2, 32);
 					name[33] = 0;
 
 					// Replace _ with ' '
@@ -2304,7 +2310,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 							name[j] = ' ';
 					}
 
-					strncpy(textprompts[num]->page[pagenum].name, name, 32);
+					strncpy(textprompts[num]->page[pagenum].name, name, sizeof(textprompts[num]->page[pagenum].name));
 				}
 				else
 					*textprompts[num]->page[pagenum].name = '\0';
@@ -3794,7 +3800,7 @@ void readmaincfg(MYFILE *f)
 			}
 			else if (fastcmp(word, "TITLEPICSNAME"))
 			{
-				strncpy(ttname, word2, 9);
+				strncpy(ttname, word2, sizeof(ttname)-1);
 				titlechanged = true;
 			}
 			else if (fastcmp(word, "TITLEPICSX"))
@@ -3878,8 +3884,12 @@ void readmaincfg(MYFILE *f)
 				savemoddata = true;
 
 				// Also save a time attack folder
-				filenamelen = strlen(gamedatafilename)-4;  // Strip off the extension
-				strncpy(timeattackfolder, gamedatafilename, min(filenamelen, sizeof (timeattackfolder)));
+				filenamelen = strlen(gamedatafilename);  // Strip off the extension
+				if (filenamelen >= 4)
+					filenamelen -= 4;
+				if (filenamelen >= sizeof(timeattackfolder))
+					filenamelen = sizeof(timeattackfolder)-1;
+				strncpy(timeattackfolder, gamedatafilename, filenamelen);
 				timeattackfolder[min(filenamelen, sizeof (timeattackfolder) - 1)] = '\0';
 
 				strcpy(savegamename, timeattackfolder);
@@ -4172,9 +4182,9 @@ spritenum_t get_sprite(const char *word)
 		return atoi(word);
 	if (fastncmp("SPR_",word,4))
 		word += 4; // take off the SPR_
-	for (i = 0; i < NUMSPRITES; i++)
-		if (!sprnames[i][4] && memcmp(word,sprnames[i],4)==0)
-			return i;
+	i = R_GetSpriteNumByName(word);
+	if (i != NUMSPRITES)
+		return i;
 	deh_warning("Couldn't find sprite named 'SPR_%s'",word);
 	return SPR_NULL;
 }
diff --git a/src/deh_tables.c b/src/deh_tables.c
index fa86518e2e0eaf51555d6ee334a97cad22b3afa3..c7c7c604068cd4761ea3944a92cd4efecd9a0ddb 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -31,7 +31,7 @@
 char *FREE_STATES[NUMSTATEFREESLOTS];
 char *FREE_MOBJS[NUMMOBJFREESLOTS];
 char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
-UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
+bitarray_t used_spr[BIT_ARRAY_SIZE(NUMSPRITEFREESLOTS)]; // Sprite freeslots in use
 
 const char NIGHTSGRADE_LIST[] = {
 	'F', // GRADE_F
@@ -4834,6 +4834,7 @@ const char *const POWERS_LIST[] = {
 
 const char *const HUDITEMS_LIST[] = {
 	"LIVES",
+	"INPUT",
 
 	"RINGS",
 	"RINGSNUM",
@@ -5095,6 +5096,10 @@ struct int_const_s const INT_CONST[] = {
 	{"RF_SHADOWEFFECTS",RF_SHADOWEFFECTS},
 	{"RF_DROPSHADOW",RF_DROPSHADOW},
 
+	// Animation flags
+	{"SPR2F_MASK",SPR2F_MASK},
+	{"SPR2F_SUPER",SPR2F_SUPER},
+
 	// Level flags
 	{"LF_SCRIPTISFILE",LF_SCRIPTISFILE},
 	{"LF_SPEEDMUSIC",LF_SPEEDMUSIC},
@@ -5737,6 +5742,7 @@ struct int_const_s const INT_CONST[] = {
 	{"JA_DIGITAL",JA_DIGITAL},
 	{"JA_JUMP",JA_JUMP},
 	{"JA_SPIN",JA_SPIN},
+	{"JA_SHIELD",JA_SHIELD},
 	{"JA_FIRE",JA_FIRE},
 	{"JA_FIRENORMAL",JA_FIRENORMAL},
 	{"JOYAXISRANGE",JOYAXISRANGE},
diff --git a/src/deh_tables.h b/src/deh_tables.h
index 42716f9b4bd271c98aca83737f419670d862d7e5..b6986adff0166c3132be5f70ca78c7835030998f 100644
--- a/src/deh_tables.h
+++ b/src/deh_tables.h
@@ -23,13 +23,13 @@
 extern char *FREE_STATES[NUMSTATEFREESLOTS];
 extern char *FREE_MOBJS[NUMMOBJFREESLOTS];
 extern char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
-extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
+extern bitarray_t used_spr[BIT_ARRAY_SIZE(NUMSPRITEFREESLOTS)]; // Sprite freeslots in use
 
 #define initfreeslots() {\
-	memset(FREE_STATES,0,sizeof(char *) * NUMSTATEFREESLOTS);\
-	memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\
-	memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\
-	memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\
+	memset(FREE_STATES, 0, sizeof(FREE_STATES));\
+	memset(FREE_MOBJS, 0, sizeof(FREE_MOBJS));\
+	memset(FREE_SKINCOLORS, 0, sizeof(FREE_SKINCOLORS));\
+	memset(used_spr, 0, sizeof(used_spr));\
 	memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\
 }
 
diff --git a/src/doomdef.h b/src/doomdef.h
index 50f6f8a8b8c92ad42cf014711e5852454f7a0b81..1b0e76314b13d080fc18c8f3463c066616c4b8c8 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -82,6 +82,7 @@
 #include "version.h"
 #include "doomtype.h"
 
+#include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -244,12 +245,12 @@ extern char logfilename[1024];
 #define MAXPLAYERNAME 21
 #define PLAYERSMASK (MAXPLAYERS-1)
 
-// Don't make MAXSKINS higher than 256, since skin numbers are used with an
-// UINT8 in various parts of the codebase. If you do anyway, the data type
-// of those variables will have to be changed into at least an UINT16.
+// Don't make MAXSKINS higher than 255, since skin numbers are used with an UINT8 in
+// various parts of the codebase, and one number is reserved. If you do anyway,
+// the data type of those variables will have to be changed into at least an UINT16.
 // This change must affect code such as demo recording and playback,
 // and the structure of some networking packets and commands.
-#define MAXSKINS 256
+#define MAXSKINS 255
 #define MAXCHARACTERSLOTS (MAXSKINS * 3) // Should be higher than MAXSKINS.
 
 #define COLORRAMPSIZE 16
@@ -648,6 +649,7 @@ UINT32 quickncasehash (const char *p, size_t n)
 #else
 #define I_Assert(e) ((void)0)
 #endif
+#define I_StaticAssert(e) static_assert(e, "Static assertion failed: " #e)
 
 // The character that separates pathnames. Forward slash on
 // most systems, but reverse solidus (\) on Windows.
@@ -709,13 +711,6 @@ extern int
 /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls.
 //#define PAPER_COLLISIONCORRECTION
 
-/// FINALLY some real clipping that doesn't make walls dissappear AND speeds the game up
-/// (that was the original comment from SRB2CB, sadly it is a lie and actually slows game down)
-/// on the bright side it fixes some weird issues with translucent walls
-/// \note	SRB2CB port.
-///      	SRB2CB itself ported this from PrBoom+
-#define NEWCLIP
-
 /// OpenGL shaders
 #define GL_SHADERS
 
diff --git a/src/doomstat.h b/src/doomstat.h
index 6a2d6acf00f816804c1ec8830b69c9848deadcbe..bde2bacc72890d47b61a6085a26c5cda33dcfad0 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -165,7 +165,7 @@ extern boolean exitfadestarted;
 typedef struct
 {
 	UINT8 numpics;
-	char picname[8][8];
+	char picname[8][8+1];
 	UINT8 pichires[8];
 	char *text;
 	UINT16 xcoord[8];
@@ -296,69 +296,70 @@ typedef struct
 typedef struct
 {
 	// The original eight, plus one.
-	char lvlttl[22];       ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
-	char subttl[33];       ///< Subtitle for level
-	UINT8 actnum;          ///< Act number or 0 for none.
-	UINT32 typeoflevel;    ///< Combination of typeoflevel flags.
-	INT16 nextlevel;       ///< Map number of next level, or 1100-1102 to end.
-	INT16 marathonnext;    ///< See nextlevel, but for Marathon mode. Necessary to support hub worlds ala SUGOI.
-	char keywords[33];     ///< Keywords separated by space to search for. 32 characters.
-	char musname[7];       ///< Music track to play. "" for no music.
-	UINT16 mustrack;       ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
-	UINT32 muspos;    ///< Music position to jump to.
-	char forcecharacter[17];  ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
-	UINT8 weather;         ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
-	INT16 skynum;          ///< Sky number to use.
-	INT16 skybox_scalex;   ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.)
-	INT16 skybox_scaley;   ///< Skybox Y axis scale.
-	INT16 skybox_scalez;   ///< Skybox Z axis scale.
+	char lvlttl[21+1];          ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
+	char subttl[32+1];          ///< Subtitle for level
+	UINT8 actnum;               ///< Act number or 0 for none.
+	UINT32 typeoflevel;         ///< Combination of typeoflevel flags.
+	INT16 nextlevel;            ///< Map number of next level, or 1100-1102 to end.
+	INT16 marathonnext;         ///< See nextlevel, but for Marathon mode. Necessary to support hub worlds ala SUGOI.
+	char keywords[32+1];        ///< Keywords separated by space to search for. 32 characters.
+	char musname[7];            ///< Music track to play. "" for no music.
+	UINT16 mustrack;            ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
+	UINT32 muspos;              ///< Music position to jump to.
+	char forcecharacter[16+1];  ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
+	UINT8 weather;              ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
+	INT16 skynum;               ///< Sky number to use.
+	INT16 skybox_scalex;        ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.)
+	INT16 skybox_scaley;        ///< Skybox Y axis scale.
+	INT16 skybox_scalez;        ///< Skybox Z axis scale.
 
 	// Extra information.
-	char interscreen[8];  ///< 320x200 patch to display at intermission.
-	char runsoc[33];      ///< SOC to execute at start of level (32 character limit instead of 63)
-	char scriptname[33];  ///< Script to use when the map is switched to. (32 character limit instead of 191)
-	UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts.
-	UINT8 cutscenenum;    ///< Cutscene number to use, 0 for none.
-	INT16 countdown;      ///< Countdown until level end?
-	UINT16 palette;       ///< PAL lump to use on this map
-	UINT8 numlaps;        ///< Number of laps in circuit mode, unless overridden.
-	SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no.
-	UINT8 levelselect;    ///< Is this map available in the level select? If so, which map list is it available in?
-	SINT8 bonustype;      ///< What type of bonus does this level have? (-1 for null.)
-	SINT8 maxbonuslives;  ///< How many bonus lives to award at Intermission? (-1 for unlimited.)
-
-	UINT16 levelflags;     ///< LF_flags:  merged booleans into one UINT16 for space, see below
-	UINT8 menuflags;      ///< LF2_flags: options that affect record attack / nights mode menus
-
-	char selectheading[22]; ///< Level select heading. Allows for controllable grouping.
-	UINT16 startrings;      ///< Number of rings players start with.
-	INT32 sstimer;          ///< Timer for special stages.
-	UINT32 ssspheres;       ///< Sphere requirement in special stages.
-	fixed_t gravity;        ///< Map-wide gravity.
+	char interscreen[8+1];      ///< 320x200 patch to display at intermission.
+	char runsoc[32+1];          ///< SOC to execute at start of level (32 character limit instead of 63)
+	char scriptname[32+1];      ///< Script to use when the map is switched to. (32 character limit instead of 191)
+	UINT8 precutscenenum;       ///< Cutscene number to play BEFORE a level starts.
+	UINT8 cutscenenum;          ///< Cutscene number to use, 0 for none.
+	INT16 countdown;            ///< Countdown until level end?
+	UINT16 palette;             ///< PAL lump to use on this map
+	UINT8 numlaps;              ///< Number of laps in circuit mode, unless overridden.
+	SINT8 unlockrequired;       ///< Is an unlockable required to play this level? -1 if no.
+	UINT8 levelselect;          ///< Is this map available in the level select? If so, which map list is it available in?
+	SINT8 bonustype;            ///< What type of bonus does this level have? (-1 for null.)
+	SINT8 maxbonuslives;        ///< How many bonus lives to award at Intermission? (-1 for unlimited.)
+
+	UINT16 levelflags;          ///< LF_flags:  merged booleans into one UINT16 for space, see below
+	UINT8 menuflags;            ///< LF2_flags: options that affect record attack / nights mode menus
+
+	char selectheading[22];     ///< Level select heading. Allows for controllable grouping.
+	UINT16 startrings;          ///< Number of rings players start with.
+	INT32 sstimer;              ///< Timer for special stages.
+	UINT32 ssspheres;           ///< Sphere requirement in special stages.
+	fixed_t gravity;            ///< Map-wide gravity.
+	UINT16 nightstimer[8];      ///< Per-mare time limits for NiGHTS stages.
 
 	// Title card.
-	char ltzzpatch[9];      ///< Zig zag patch.
-	char ltzztext[9];       ///< Zig zag text.
-	char ltactdiamond[9];   ///< Act diamond.
+	char ltzzpatch[8+1];        ///< Zig zag patch.
+	char ltzztext[8+1];         ///< Zig zag text.
+	char ltactdiamond[8+1];     ///< Act diamond.
 
 	// Freed animals stuff.
-	UINT8 numFlickies;     ///< Internal. For freed flicky support.
-	mobjtype_t *flickies;  ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
+	UINT8 numFlickies;          ///< Internal. For freed flicky support.
+	mobjtype_t *flickies;       ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
 
 	// NiGHTS stuff.
-	UINT8 numGradedMares;   ///< Internal. For grade support.
-	nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful.
+	UINT8 numGradedMares;       ///< Internal. For grade support.
+	nightsgrades_t *grades;     ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful.
 
 	// Music stuff.
-	UINT32 musinterfadeout;  ///< Fade out level music on intermission screen in milliseconds
-	char musintername[7];    ///< Intermission screen music.
+	UINT32 musinterfadeout;     ///< Fade out level music on intermission screen in milliseconds
+	char musintername[7];       ///< Intermission screen music.
 
 	char muspostbossname[7];    ///< Post-bossdeath music.
 	UINT16 muspostbosstrack;    ///< Post-bossdeath track.
 	UINT32 muspostbosspos;      ///< Post-bossdeath position
 	UINT32 muspostbossfadein;   ///< Post-bossdeath fade-in milliseconds.
 
-	SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on)
+	SINT8 musforcereset;        ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on)
 
 	// Lua stuff.
 	// (This is not ifdeffed so the map header structure can stay identical, just in case.)
@@ -638,6 +639,7 @@ extern boolean singletics;
 
 extern consvar_t cv_timetic; // display high resolution timer
 extern consvar_t cv_powerupdisplay; // display powerups
+extern consvar_t cv_showinput; // display input viewer outside of time attack
 extern consvar_t cv_showinputjoy; // display joystick in time attack
 extern consvar_t cv_forceskin; // force clients to use the server's skin
 extern consvar_t cv_downloading; // allow clients to downloading WADs.
diff --git a/src/doomtype.h b/src/doomtype.h
index 4070e346a1b13dd516a91504f056cebc4defb20d..fa8616793e0aeab7bea18c77ef78a4520770b802 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -108,6 +108,7 @@ char *nongnu_strcasestr(const char *in, const char *what);
 
 int startswith (const char *base, const char *tag);
 int endswith (const char *base, const char *tag);
+char *xstrtok(char *line, const char *delims);
 
 #if defined (_WIN32) || defined (__HAIKU__)
 #define HAVE_DOSSTR_FUNCS
diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c
index ecabe3576d3f15b06513315a945562076587aff5..99bfa9f363ca04c9281b17b0cffeda5cc4314586 100644
--- a/src/dummy/i_system.c
+++ b/src/dummy/i_system.c
@@ -211,5 +211,15 @@ const char *I_GetSysName(void)
 	return NULL;
 }
 
+void I_SetTextInputMode(boolean active)
+{
+	(void)active;
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return false;
+}
+
 #include "../sdl/dosstr.c"
 
diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c
index bb796b6767a1d55990209ba46cd8245377b013d9..2c998117accb71be25850438bdac2ee6c4db0509 100644
--- a/src/dummy/i_video.c
+++ b/src/dummy/i_video.c
@@ -5,8 +5,6 @@
 rendermode_t rendermode = render_none;
 rendermode_t chosenrendermode = render_none;
 
-boolean highcolor = false;
-
 boolean allow_fullscreen = false;
 
 consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
diff --git a/src/f_finale.c b/src/f_finale.c
index edeb08820c54f53adff9dcfb4b1bfb929c536cc7..9ff50147e0bb36ae17d3c23672b82d6528f54871 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -229,6 +229,7 @@ static UINT8 cutscene_boostspeed = 0;
 char stjrintro[9] = "STJRI000";
 
 static huddrawlist_h luahuddrawlist_title;
+static huddrawlist_h luahuddrawlist_continue[2];
 
 //
 // This alters the text string cutscene_disptext.
@@ -1281,6 +1282,9 @@ void F_CreditDrawer(void)
 	UINT8 colornum;
 	const UINT8 *colormap;
 
+	// compensation for y on non-green resolutions, used to prevent text from disappearing before reaching the top
+	UINT16 compy = (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2;
+
 	if (players[consoleplayer].skincolor)
 		colornum = players[consoleplayer].skincolor;
 	else
@@ -1312,17 +1316,17 @@ void F_CreditDrawer(void)
 			y += 80<<FRACBITS;
 			break;
 		case 1:
-			if (y>>FRACBITS > -20)
+			if (y>>FRACBITS > -20-compy)
 				V_DrawCreditString((160 - (V_CreditStringWidth(&credits[i][1])>>1))<<FRACBITS, y, 0, &credits[i][1]);
 			y += 30<<FRACBITS;
 			break;
 		case 2:
-			if (y>>FRACBITS > -10)
+			if (y>>FRACBITS > -10-compy)
 				V_DrawStringAtFixed((BASEVIDWIDTH-V_StringWidth(&credits[i][1], V_ALLOWLOWERCASE|V_YELLOWMAP))<<FRACBITS>>1, y, V_ALLOWLOWERCASE|V_YELLOWMAP, &credits[i][1]);
 			y += 12<<FRACBITS;
 			break;
 		default:
-			if (y>>FRACBITS > -10)
+			if (y>>FRACBITS > -10-compy)
 				V_DrawStringAtFixed(32<<FRACBITS, y, V_ALLOWLOWERCASE, credits[i]);
 			y += 12<<FRACBITS;
 			break;
@@ -3527,11 +3531,16 @@ void F_TitleDemoTicker(void)
 // ==========
 
 static skin_t *contskins[2];
-static UINT8 cont_spr2[2][6];
+static UINT16 cont_spr2[2][6];
 static UINT8 *contcolormaps[2];
+static player_t *contPlayers[2];
+static skincolornum_t contColors[2]; // it's possible to change your skincolor in the continue screen, so this is for Lua to identify the skincolor that was used to cache the colormap
+static boolean contOverrides[2];
 
 void F_StartContinue(void)
 {
+	UINT8 i;
+
 	I_Assert(!netgame && !multiplayer);
 
 	if (continuesInSession && players[consoleplayer].continues <= 0)
@@ -3554,9 +3563,12 @@ void F_StartContinue(void)
 	S_ChangeMusicInternal("_conti", false);
 	S_StopSounds();
 
+	contPlayers[0] = &players[consoleplayer];
 	contskins[0] = skins[players[consoleplayer].skin];
+
 	cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL);
 	cont_spr2[0][2] = contskins[0]->contangle & 7;
+	contColors[0] = players[consoleplayer].skincolor;
 	contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE);
 	cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes;
 	cont_spr2[0][5] = max(1, contskins[0]->contspeed);
@@ -3570,9 +3582,12 @@ void F_StartContinue(void)
 		else // HACK
 			secondplaya = 1;
 
+		contPlayers[1] = &players[secondplaya];
 		contskins[1] = skins[players[secondplaya].skin];
+
 		cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL);
 		cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7;
+		contColors[1] = players[secondplaya].skincolor;
 		contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE);
 		cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes;
 		if (cont_spr2[1][0] == SPR2_CNT4)
@@ -3592,6 +3607,58 @@ void F_StartContinue(void)
 
 	timetonext = (11*TICRATE)+11;
 	continuetime = 0;
+
+	// allocate and/or clear Lua continue screen draw lists
+	for (i = 0; i < 2; i++)
+	{
+		if (!LUA_HUD_IsDrawListValid(luahuddrawlist_continue[i]))
+		{
+			LUA_HUD_DestroyDrawList(luahuddrawlist_continue[i]);
+			luahuddrawlist_continue[i] = LUA_HUD_CreateDrawList();
+		}
+		LUA_HUD_ClearDrawList(luahuddrawlist_continue[i]);
+		contOverrides[i] = false;
+	}
+}
+
+static void F_DestroyContinueDrawLists(void)
+{
+	UINT8 i;
+	for (i = 0; i < 2; i++)
+	{
+		LUA_HUD_DestroyDrawList(luahuddrawlist_continue[i]);
+		luahuddrawlist_continue[i] = NULL;
+		contOverrides[i] = false;
+	}
+}
+
+static void F_DrawContinueCharacter(INT32 dx, INT32 dy, UINT8 n)
+{
+	spritedef_t *sprdef;
+	spriteframe_t *sprframe;
+	patch_t *patch;
+
+	if (renderisnewtic)
+	{
+		LUA_HUD_ClearDrawList(luahuddrawlist_continue[n]);
+		contOverrides[n] = LUA_HookCharacterHUD
+		(
+			HUD_HOOK(continue), luahuddrawlist_continue[n], contPlayers[n],
+			dx, dy, contskins[n]->highresscale,
+			(INT32)(&contskins[n] - skins), cont_spr2[n][0], cont_spr2[n][1], cont_spr2[n][2] + 1, contColors[n], // add 1 to rotation to convert internal angle numbers (0-7) to WAD editor angle numbers (1-8)
+			imcontinuing ? continuetime : timetonext, imcontinuing
+		);
+	}
+
+	LUA_HUD_DrawList(luahuddrawlist_continue[n]);
+
+	if (contOverrides[n] == true)
+		return;
+
+	sprdef = &contskins[n]->sprites[cont_spr2[n][0]];
+	sprframe = &sprdef->spriteframes[cont_spr2[n][1]];
+	patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);
+	V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);
 }
 
 //
@@ -3600,8 +3667,6 @@ void F_StartContinue(void)
 //
 void F_ContinueDrawer(void)
 {
-	spritedef_t *sprdef;
-	spriteframe_t *sprframe;
 	patch_t *patch;
 	INT32 i, x = (BASEVIDWIDTH>>1), ncontinues = players[consoleplayer].continues;
 	char numbuf[9] = "CONTNUM*";
@@ -3646,7 +3711,7 @@ void F_ContinueDrawer(void)
 	else if (ncontinues > 10)
 	{
 		if (!(continuetime & 1) || continuetime > 17)
-			V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
+			V_DrawContinueIcon(x, 68, 0, (INT32)(&contskins[0] - skins), contColors[0]);
 		V_DrawScaledPatch(x+12, 66, 0, stlivex);
 		V_DrawRightAlignedString(x+38, 64, 0,
 			va("%d",(imcontinuing ? ncontinues-1 : ncontinues)));
@@ -3660,7 +3725,7 @@ void F_ContinueDrawer(void)
 		{
 			if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17))
 				continue;
-			V_DrawContinueIcon(x - (i*30), 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
+			V_DrawContinueIcon(x - (i*30), 68, 0, (INT32)(&contskins[0] - skins), contColors[0]);
 		}
 		x = BASEVIDWIDTH>>1;
 	}
@@ -3700,21 +3765,12 @@ void F_ContinueDrawer(void)
 	else if (lift[0] > TICRATE+5)
 		lift[0] = TICRATE+5;
 
-#define drawchar(dx, dy, n)	{\
-								sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\
-								sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\
-								patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);\
-								V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\
-							}
-
 	if (offsy < 0)
-		drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
+		F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
 	if (contskins[1])
-		drawchar((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
+		F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
 	if (offsy >= 0)
-		drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
-
-#undef drawchar
+		F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
 
 	if (timetonext > (11*TICRATE))
 		V_DrawFadeScreen(31, timetonext-(11*TICRATE));
@@ -3730,6 +3786,7 @@ void F_ContinueTicker(void)
 		{
 			if (!(--timetonext))
 			{
+				F_DestroyContinueDrawLists();
 				Command_ExitGame_f();
 				return;
 			}
@@ -3739,6 +3796,7 @@ void F_ContinueTicker(void)
 	{
 		if (++continuetime == 3*TICRATE)
 		{
+			F_DestroyContinueDrawLists();
 			G_Continue();
 			return;
 		}
@@ -4384,11 +4442,10 @@ void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum
 	if (!tag || !tag[0])
 		return;
 
-	strncpy(suffixedtag, tag, 33);
-	suffixedtag[32] = 0;
+	strncpy(suffixedtag, tag, sizeof(suffixedtag)-1);
 
 	if (tutorialmode)
-		suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33);
+		suffixed = F_GetTextPromptTutorialTag(suffixedtag, sizeof(suffixedtag)-1);
 
 	for (*promptnum = 0 + tutorialpromptnum; *promptnum < MAX_PROMPTS; (*promptnum)++)
 	{
diff --git a/src/f_finale.h b/src/f_finale.h
index cb71775d05fc109aa4c3468c19cfe381eff72635..4b777eb11fe45e65b6df4a81a24d47955763551b 100644
--- a/src/f_finale.h
+++ b/src/f_finale.h
@@ -96,7 +96,7 @@ typedef enum
 extern ttmode_enum ttmode;
 extern UINT8 ttscale;
 // ttmode user vars
-extern char ttname[9];
+extern char ttname[8+1];
 extern INT16 ttx;
 extern INT16 tty;
 extern INT16 ttloop;
diff --git a/src/filesrch.c b/src/filesrch.c
index 6429b6fa2f13b49979c7e5efa1614bf47cac02be..944e8447f4d462c5ee7cac302a7481422e184613 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -1185,7 +1185,7 @@ boolean preparefilemenu(boolean samedepth)
 					{
 						if (!filenamebuf[i][0])
 						{
-							strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH);
+							strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH-1);
 							filenamebuf[i][MAX_WADPATH - 1] = '\0';
 							nameonly(filenamebuf[i]);
 						}
diff --git a/src/g_demo.c b/src/g_demo.c
index f64f34168efd8286ba21199841be95bc60fceb3d..0efba5a59724f3b64f3a9ed9dbcf1d137a472e47 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -98,7 +98,7 @@ demoghost *ghosts = NULL;
 // DEMO RECORDING
 //
 
-#define DEMOVERSION 0x0011
+#define DEMOVERSION 0x0012
 #define DEMOHEADER  "\xF0" "SRB2Replay" "\x0F"
 
 #define DF_GHOST        0x01 // This demo contains ghost data too!
@@ -183,7 +183,11 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
 	if (ziptic & ZT_ANGLE)
 		oldcmd.angleturn = READINT16(demo_p);
 	if (ziptic & ZT_BUTTONS)
+	{
 		oldcmd.buttons = (oldcmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) | (READUINT16(demo_p) & ~(BT_CAMLEFT|BT_CAMRIGHT));
+		if (demoversion < 0x0012 && oldcmd.buttons & BT_SPIN)
+			oldcmd.buttons |= BT_SHIELD; // Copy BT_SPIN to BT_SHIELD for pre-Shield-button demos
+	}
 	if (ziptic & ZT_AIMING)
 		oldcmd.aiming = READINT16(demo_p);
 	if (ziptic & ZT_LATENCY)
@@ -409,7 +413,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 	{
 		oldghost.sprite2 = ghost->sprite2;
 		ziptic |= GZT_SPR2;
-		WRITEUINT8(demo_p,oldghost.sprite2);
+		WRITEUINT16(demo_p,oldghost.sprite2);
 	}
 
 	// Check for sprite set changes
@@ -509,7 +513,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 		temp = ghost->player->followmobj->z-ghost->z;
 		WRITEFIXED(demo_p,temp);
 		if (followtic & FZT_SKIN)
-			WRITEUINT8(demo_p,ghost->player->followmobj->sprite2);
+			WRITEUINT16(demo_p,ghost->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
 		WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK));
 		WRITEUINT16(demo_p,ghost->player->followmobj->color);
@@ -571,7 +575,7 @@ void G_ConsGhostTic(void)
 	if (ziptic & GZT_FRAME)
 		demo_p++;
 	if (ziptic & GZT_SPR2)
-		demo_p++;
+		demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
 
 	if (ziptic & GZT_EXTRA)
 	{ // But wait, there's more!
@@ -640,7 +644,7 @@ void G_ConsGhostTic(void)
 		// momx, momy and momz
 		demo_p += (demoversion < 0x000e) ? sizeof(INT16) * 3 : sizeof(fixed_t) * 3;
 		if (followtic & FZT_SKIN)
-			demo_p++;
+			demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
 		demo_p += sizeof(UINT16);
 		demo_p++;
 		demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16);
@@ -722,7 +726,7 @@ void G_GhostTicker(void)
 		if (ziptic & GZT_FRAME)
 			g->oldmo.frame = READUINT8(g->p);
 		if (ziptic & GZT_SPR2)
-			g->oldmo.sprite2 = READUINT8(g->p);
+			g->oldmo.sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
 
 		// Update ghost
 		P_UnsetThingPosition(g->mo);
@@ -771,7 +775,7 @@ void G_GhostTicker(void)
 			{
 				g->mo->destscale = READFIXED(g->p);
 				if (g->mo->destscale != g->mo->scale)
-					P_SetScale(g->mo, g->mo->destscale);
+					P_SetScale(g->mo, g->mo->destscale, false);
 			}
 			if (xziptic & EZT_THOKMASK)
 			{ // Let's only spawn ONE of these per frame, thanks.
@@ -810,7 +814,7 @@ void G_GhostTicker(void)
 							mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<<FF_TRANSSHIFT;
 							mobj->color = g->mo->color;
 							mobj->skin = g->mo->skin;
-							P_SetScale(mobj, (mobj->destscale = g->mo->scale));
+							P_SetScale(mobj, g->mo->scale, true);
 
 							if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 							{
@@ -926,7 +930,7 @@ void G_GhostTicker(void)
 				else
 					follow->destscale = g->mo->destscale;
 				if (follow->destscale != follow->scale)
-					P_SetScale(follow, follow->destscale);
+					P_SetScale(follow, follow->destscale, false);
 
 				P_UnsetThingPosition(follow);
 				temp = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
@@ -937,7 +941,7 @@ void G_GhostTicker(void)
 				follow->z = g->mo->z + temp;
 				P_SetThingPosition(follow);
 				if (followtic & FZT_SKIN)
-					follow->sprite2 = READUINT8(g->p);
+					follow->sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
 				else
 					follow->sprite2 = 0;
 				follow->sprite = READUINT16(g->p);
@@ -1052,7 +1056,7 @@ void G_ReadMetalTic(mobj_t *metal)
 			oldmetal.frame = G_ConvertOldFrameFlags(oldmetal.frame);
 	}
 	if (ziptic & GZT_SPR2)
-		oldmetal.sprite2 = READUINT8(metal_p);
+		oldmetal.sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
 
 	// Set movement, position, and angle
 	// oldmetal contains where you're supposed to be.
@@ -1079,7 +1083,7 @@ void G_ReadMetalTic(mobj_t *metal)
 		{
 			metal->destscale = READFIXED(metal_p);
 			if (metal->destscale != metal->scale)
-				P_SetScale(metal, metal->destscale);
+				P_SetScale(metal, metal->destscale, false);
 		}
 		if (xziptic & EZT_THOKMASK)
 		{ // Let's only spawn ONE of these per frame, thanks.
@@ -1117,7 +1121,7 @@ void G_ReadMetalTic(mobj_t *metal)
 						mobj->angle = metal->angle;
 						mobj->color = metal->color;
 						mobj->skin = metal->skin;
-						P_SetScale(mobj, (mobj->destscale = metal->scale));
+						P_SetScale(mobj, metal->scale, true);
 
 						if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 						{
@@ -1184,7 +1188,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				else
 					follow->destscale = metal->destscale;
 				if (follow->destscale != follow->scale)
-					P_SetScale(follow, follow->destscale);
+					P_SetScale(follow, follow->destscale, false);
 
 				P_UnsetThingPosition(follow);
 				temp = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
@@ -1195,7 +1199,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				follow->z = metal->z + temp;
 				P_SetThingPosition(follow);
 				if (followtic & FZT_SKIN)
-					follow->sprite2 = READUINT8(metal_p);
+					follow->sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
 				else
 					follow->sprite2 = 0;
 				follow->sprite = READUINT16(metal_p);
@@ -1203,7 +1207,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				if (metalversion < 0x000f)
 					follow->frame = G_ConvertOldFrameFlags(follow->frame);
 				follow->angle = metal->angle;
-				follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
+				follow->color = (metalversion == 0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
 
 				if (!(followtic & FZT_SPAWNED))
 				{
@@ -1304,7 +1308,7 @@ void G_WriteMetalTic(mobj_t *metal)
 	{
 		oldmetal.sprite2 = metal->sprite2;
 		ziptic |= GZT_SPR2;
-		WRITEUINT8(demo_p,oldmetal.sprite2);
+		WRITEUINT16(demo_p,oldmetal.sprite2);
 	}
 
 	// Check for sprite set changes
@@ -1379,7 +1383,7 @@ void G_WriteMetalTic(mobj_t *metal)
 		temp = metal->player->followmobj->z-metal->z;
 		WRITEFIXED(demo_p,temp);
 		if (followtic & FZT_SKIN)
-			WRITEUINT8(demo_p,metal->player->followmobj->sprite2);
+			WRITEUINT16(demo_p,metal->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,metal->player->followmobj->sprite);
 		WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits
 		WRITEUINT16(demo_p,metal->player->followmobj->color);
@@ -1650,7 +1654,7 @@ static void G_LoadDemoExtraFiles(UINT8 **pp, UINT16 this_demo_version)
 	UINT16 totalfiles;
 	char filename[MAX_WADPATH];
 	UINT8 md5sum[16];
-	filestatus_t ncs;
+	filestatus_t ncs = FS_NOTFOUND;
 	boolean toomany = false;
 	boolean alreadyloaded;
 	UINT16 i, j;
@@ -2603,10 +2607,10 @@ void G_AddGhost(char *defdemoname)
 		}
 	gh->oldmo.color = gh->mo->color;
 
-	gh->mo->state = states+S_PLAY_STND;
+	gh->mo->state = &states[S_PLAY_STND];
 	gh->mo->sprite = gh->mo->state->sprite;
-	gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK);
-	//gh->mo->frame = tr_trans30<<FF_TRANSSHIFT;
+	gh->mo->sprite2 = P_GetStateSprite2(gh->mo->state);
+	gh->mo->frame = (gh->mo->state->frame & ~FF_FRAMEMASK) | P_GetSprite2StateFrame(gh->mo->state);
 	gh->mo->flags2 |= MF2_DONTDRAW;
 	gh->fadein = (9-3)*6; // fade from invisible to trans30 over as close to 35 tics as possible
 	gh->mo->tics = -1;
diff --git a/src/g_game.c b/src/g_game.c
index 6a99381e741544030ad9208f93860ffbc0f249d6..8d19c9e7cb68df142e68e7d0277b2425153f9206 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -403,27 +403,29 @@ consvar_t cv_cam_lockonboss[2] = {
 	CVAR_INIT ("cam2_lockaimassist", "Full", CV_SAVE|CV_ALLOWLUA, lockedassist_cons_t, NULL),
 };
 
-consvar_t cv_moveaxis = CVAR_INIT ("joyaxis_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_sideaxis = CVAR_INIT ("joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_lookaxis = CVAR_INIT ("joyaxis_look", "X-Rudder-", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_turnaxis = CVAR_INIT ("joyaxis_turn", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_jumpaxis = CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_spinaxis = CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_fireaxis = CVAR_INIT ("joyaxis_fire", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_firenaxis = CVAR_INIT ("joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_deadzone = CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
-consvar_t cv_digitaldeadzone = CVAR_INIT ("joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
-
-consvar_t cv_moveaxis2 = CVAR_INIT ("joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_sideaxis2 = CVAR_INIT ("joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_lookaxis2 = CVAR_INIT ("joyaxis2_look", "X-Rudder-", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_turnaxis2 = CVAR_INIT ("joyaxis2_turn", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_jumpaxis2 = CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_spinaxis2 = CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_fireaxis2 = CVAR_INIT ("joyaxis2_fire", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_firenaxis2 = CVAR_INIT ("joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL);
-consvar_t cv_deadzone2 = CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
-consvar_t cv_digitaldeadzone2 = CVAR_INIT ("joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+consvar_t cv_moveaxis   = CVAR_INIT ("joyaxis_move",       "Y-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_sideaxis   = CVAR_INIT ("joyaxis_side",       "X-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_lookaxis   = CVAR_INIT ("joyaxis_look",       "X-Rudder-", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_turnaxis   = CVAR_INIT ("joyaxis_turn",       "Z-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_jumpaxis   = CVAR_INIT ("joyaxis_jump",       "None",      CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_spinaxis   = CVAR_INIT ("joyaxis_spin",       "None",      CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_shieldaxis = CVAR_INIT ("joyaxis_shield",     "None",      CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_fireaxis   = CVAR_INIT ("joyaxis_fire",       "Z-Rudder",  CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_firenaxis  = CVAR_INIT ("joyaxis_firenormal", "Z-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_deadzone        = CVAR_INIT ("joy_deadzone",    "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+consvar_t cv_digitaldeadzone = CVAR_INIT ("joy_digdeadzone", "0.25",  CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+
+consvar_t cv_moveaxis2   = CVAR_INIT ("joyaxis2_move",       "Y-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_sideaxis2   = CVAR_INIT ("joyaxis2_side",       "X-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_lookaxis2   = CVAR_INIT ("joyaxis2_look",       "X-Rudder-", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_turnaxis2   = CVAR_INIT ("joyaxis2_turn",       "Z-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_jumpaxis2   = CVAR_INIT ("joyaxis2_jump",       "None",      CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_spinaxis2   = CVAR_INIT ("joyaxis2_spin",       "None",      CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_shieldaxis2 = CVAR_INIT ("joyaxis2_shield",     "None",      CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_fireaxis2   = CVAR_INIT ("joyaxis2_fire",       "Z-Rudder",  CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_firenaxis2  = CVAR_INIT ("joyaxis2_firenormal", "Z-Axis",    CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_deadzone2        = CVAR_INIT ("joy_deadzone2",    "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+consvar_t cv_digitaldeadzone2 = CVAR_INIT ("joy_digdeadzone2", "0.25",  CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
 
 player_t *seenplayer; // player we're aiming at right now
 
@@ -894,6 +896,9 @@ INT32 JoyAxis(joyaxis_e axissel)
 		case JA_SPIN:
 			axisval = cv_spinaxis.value;
 			break;
+		case JA_SHIELD:
+			axisval = cv_shieldaxis.value;
+			break;
 		case JA_FIRE:
 			axisval = cv_fireaxis.value;
 			break;
@@ -967,6 +972,9 @@ INT32 Joy2Axis(joyaxis_e axissel)
 		case JA_SPIN:
 			axisval = cv_spinaxis2.value;
 			break;
+		case JA_SHIELD:
+			axisval = cv_shieldaxis2.value;
+			break;
 		case JA_FIRE:
 			axisval = cv_fireaxis2.value;
 			break;
@@ -1334,8 +1342,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONPREV))
 		cmd->buttons |= BT_WEAPONPREV; // Previous Weapon
 
-#if NUM_WEAPONS > 10
-"Add extra inputs to g_input.h/gamecontrols_e"
+#if NUM_WEAPONS > 7
+"Add extra inputs to g_input.h/gamecontrols_e, and fix conflicts in d_ticcmd.h/ticcmd_t/buttons"
 #endif
 	//use the three avaliable bits to determine the weapon.
 	cmd->buttons &= ~BT_WEAPONMASK;
@@ -1361,7 +1369,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 		cmd->buttons |= BT_TOSSFLAG;
 	
 	// Shield button
-	if (PLAYERINPUTDOWN(ssplayer, GC_SHIELD))
+	axis = PlayerJoyAxis(ssplayer, JA_SHIELD);
+	if (PLAYERINPUTDOWN(ssplayer, GC_SHIELD) || (usejoystick && axis > 0))
 		cmd->buttons |= BT_SHIELD;
 
 	// Lua scriptable buttons
@@ -5403,7 +5412,7 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc)
 INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep)
 {
 	boolean usemapcode = false;
-	INT32 newmapnum;
+	INT32 newmapnum = -1;
 	size_t mapnamelen = strlen(mapname);
 	char *p;
 
diff --git a/src/g_game.h b/src/g_game.h
index 80a815f02d00a572972412901c72877e8f80de49..0d5fc7e373179f9b9905ab9361bb2dafb146afb7 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -71,8 +71,8 @@ typedef enum {
 #define P_ControlStyle(player) ((((player)->pflags & PF_ANALOGMODE) ? CS_LMAOGALOG : 0) | (((player)->pflags & PF_DIRECTIONCHAR) ? CS_STANDARD : 0))
 
 extern consvar_t cv_autobrake, cv_autobrake2;
-extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis,cv_deadzone,cv_digitaldeadzone;
-extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2,cv_deadzone2,cv_digitaldeadzone2;
+extern consvar_t cv_sideaxis, cv_turnaxis, cv_moveaxis, cv_lookaxis, cv_jumpaxis, cv_spinaxis, cv_shieldaxis, cv_fireaxis, cv_firenaxis, cv_deadzone, cv_digitaldeadzone;
+extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_shieldaxis2,cv_fireaxis2,cv_firenaxis2,cv_deadzone2,cv_digitaldeadzone2;
 extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest;
 
 // hi here's some new controls
@@ -100,6 +100,7 @@ typedef enum
 
 	JA_JUMP = JA_DIGITAL,
 	JA_SPIN,
+	JA_SHIELD,
 	JA_FIRE,
 	JA_FIRENORMAL,
 } joyaxis_e;
diff --git a/src/g_input.c b/src/g_input.c
index 3f1be37ba3f588fb2f3b2f6012ae7bf29c397b98..4a9692e8812ad89b20a85fb5f727acf9f8e52e86 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -743,34 +743,34 @@ void G_DefineDefaultControls(void)
 		// Gamepad controls -- same for both schemes
 		gamecontroldefault[i][GC_JUMP         ][1] = KEY_JOY1+0; // A
 		gamecontroldefault[i][GC_SPIN         ][1] = KEY_JOY1+2; // X
-		gamecontroldefault[i][GC_CUSTOM1      ][1] = KEY_JOY1+1; // B
-		gamecontroldefault[i][GC_CUSTOM2      ][1] = KEY_JOY1+3; // Y
-		gamecontroldefault[i][GC_CUSTOM3      ][1] = KEY_JOY1+8; // Left Stick
-		gamecontroldefault[i][GC_SHIELD       ][1] = KEY_JOY1+4; // LB
+		gamecontroldefault[i][GC_SHIELD       ][1] = KEY_JOY1+1; // B
+		gamecontroldefault[i][GC_CUSTOM1      ][1] = KEY_JOY1+3; // Y
+		gamecontroldefault[i][GC_CUSTOM2      ][1] = KEY_JOY1+4; // LB
 		gamecontroldefault[i][GC_CENTERVIEW   ][1] = KEY_JOY1+5; // RB
+		gamecontroldefault[i][GC_CUSTOM3      ][1] = KEY_JOY1+8; // Left Stick
+		gamecontroldefault[i][GC_CAMTOGGLE    ][1] = KEY_JOY1+9; // Right Stick
 		gamecontroldefault[i][GC_SCORES       ][1] = KEY_JOY1+6; // Back
 		gamecontroldefault[i][GC_SYSTEMMENU   ][0] = KEY_JOY1+7; // Start
+		gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = KEY_HAT1+0; // D-Pad Up
+		gamecontroldefault[i][GC_TOSSFLAG     ][1] = KEY_HAT1+1; // D-Pad Down
 		gamecontroldefault[i][GC_WEAPONPREV   ][1] = KEY_HAT1+2; // D-Pad Left
 		gamecontroldefault[i][GC_WEAPONNEXT   ][1] = KEY_HAT1+3; // D-Pad Right
-		gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = KEY_JOY1+9; // Right Stick
-		gamecontroldefault[i][GC_TOSSFLAG     ][1] = KEY_HAT1+0; // D-Pad Up
-		gamecontroldefault[i][GC_CAMTOGGLE    ][1] = KEY_HAT1+1; // D-Pad Down
 
 		// Second player controls only have joypad defaults
 		gamecontrolbisdefault[i][GC_JUMP         ][1] = KEY_2JOY1+0; // A
 		gamecontrolbisdefault[i][GC_SPIN         ][1] = KEY_2JOY1+2; // X
-		gamecontrolbisdefault[i][GC_CUSTOM1      ][1] = KEY_2JOY1+1; // B
-		gamecontrolbisdefault[i][GC_CUSTOM2      ][1] = KEY_2JOY1+3; // Y
-		gamecontrolbisdefault[i][GC_CUSTOM3      ][1] = KEY_2JOY1+8; // Left Stick
-		gamecontrolbisdefault[i][GC_SHIELD       ][1] = KEY_2JOY1+4; // LB
+		gamecontrolbisdefault[i][GC_SHIELD       ][1] = KEY_2JOY1+1; // B
+		gamecontrolbisdefault[i][GC_CUSTOM1      ][1] = KEY_2JOY1+3; // Y
+		gamecontrolbisdefault[i][GC_CUSTOM2      ][1] = KEY_2JOY1+4; // LB
 		gamecontrolbisdefault[i][GC_CENTERVIEW   ][1] = KEY_2JOY1+5; // RB
+		gamecontrolbisdefault[i][GC_CUSTOM3      ][1] = KEY_2JOY1+8; // Left Stick
+		gamecontrolbisdefault[i][GC_CAMTOGGLE    ][1] = KEY_2JOY1+9; // Right Stick
 		//gamecontrolbisdefault[i][GC_SCORES       ][1] = KEY_2JOY1+6; // Back
 		//gamecontrolbisdefault[i][GC_SYSTEMMENU   ][0] = KEY_2JOY1+7; // Start
+		gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = KEY_2HAT1+0; // D-Pad Up
+		gamecontrolbisdefault[i][GC_TOSSFLAG     ][1] = KEY_2HAT1+1; // D-Pad Down
 		gamecontrolbisdefault[i][GC_WEAPONPREV   ][1] = KEY_2HAT1+2; // D-Pad Left
 		gamecontrolbisdefault[i][GC_WEAPONNEXT   ][1] = KEY_2HAT1+3; // D-Pad Right
-		gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = KEY_2JOY1+9; // Right Stick
-		gamecontrolbisdefault[i][GC_TOSSFLAG     ][1] = KEY_2HAT1+0; // D-Pad Up
-		gamecontrolbisdefault[i][GC_CAMTOGGLE    ][1] = KEY_2HAT1+1; // D-Pad Down
 	}
 }
 
@@ -1001,7 +1001,6 @@ static void setcontrol(INT32 (*gc)[2])
 
 	// TODO: 2.3: Delete the "use" alias
 	namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin";
-		
 
 	for (numctrl = 0; numctrl < NUM_GAMECONTROLS && stricmp(namectrl, gamecontrolname[numctrl]);
 		numctrl++)
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index f1f0668be51d99dd3e5e07bcb4760083afb76c33..56f5416cf13f8d4c3176d93b122094d4bfd0bacb 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -98,13 +98,11 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
 		if (position + count >= pblockheight)
 			count = pblockheight - position;
 
-		dest = block + (position*blockmodulo);
-		while (count > 0)
+		for (dest = block + (position*blockmodulo); count > 0; count--, dest += blockmodulo, yfrac += yfracstep)
 		{
-			count--;
-
 			texel = source[yfrac>>FRACBITS];
 			alpha = 0xFF;
+
 			// Make pixel transparent if chroma keyed
 			if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
 				alpha = 0x00;
@@ -115,11 +113,20 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
 			switch (bpp)
 			{
 				case 2:
+				{
+					texelu16 = *((UINT16*)dest);
 					if ((originPatch != NULL) && (originPatch->style != AST_COPY))
-						texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
+					{
+						if (originPatch->style == AST_TRANSLUCENT && originPatch->alpha < ASTTextureBlendingThreshold[0])
+							continue;
+						if (!(texelu16 & 0xFF00) && originPatch->alpha <= ASTTextureBlendingThreshold[1])
+							continue;
+						texel = ASTBlendPaletteIndexes(texelu16 & 0xFF, texel, originPatch->style, originPatch->alpha);
+					}
 					texelu16 = (UINT16)((alpha<<8) | texel);
 					memcpy(dest, &texelu16, sizeof(UINT16));
 					break;
+				}
 				case 3:
 					colortemp = palette[texel];
 					if ((originPatch != NULL) && (originPatch->style != AST_COPY))
@@ -149,9 +156,6 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
 						*dest = texel;
 					break;
 			}
-
-			dest += blockmodulo;
-			yfrac += yfracstep;
 		}
 	}
 }
@@ -202,13 +206,11 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
 		if (position + count >= pblockheight)
 			count = pblockheight - position;
 
-		dest = block + (position*blockmodulo);
-		while (count > 0)
+		for (dest = block + (position*blockmodulo); count > 0; count--, dest += blockmodulo, yfrac -= yfracstep)
 		{
-			count--;
-
 			texel = source[yfrac>>FRACBITS];
 			alpha = 0xFF;
+
 			// Make pixel transparent if chroma keyed
 			if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
 				alpha = 0x00;
@@ -219,8 +221,15 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
 			switch (bpp)
 			{
 				case 2:
+					texelu16 = *((UINT16*)dest);
 					if ((originPatch != NULL) && (originPatch->style != AST_COPY))
-						texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
+					{
+						if (originPatch->style == AST_TRANSLUCENT && originPatch->alpha < ASTTextureBlendingThreshold[0])
+							continue;
+						if (!(texelu16 & 0xFF00) && originPatch->alpha <= ASTTextureBlendingThreshold[1])
+							continue;
+						texel = ASTBlendPaletteIndexes(texelu16 & 0xFF, texel, originPatch->style, originPatch->alpha);
+					}
 					texelu16 = (UINT16)((alpha<<8) | texel);
 					memcpy(dest, &texelu16, sizeof(UINT16));
 					break;
@@ -253,9 +262,6 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
 						*dest = texel;
 					break;
 			}
-
-			dest += blockmodulo;
-			yfrac -= yfracstep;
 		}
 	}
 }
@@ -433,7 +439,7 @@ static UINT8 *MakeBlock(GLMipmap_t *grMipmap)
 // Create a composite texture from patches, adapt the texture size to a power of 2
 // height and width for the hardware texture cache.
 //
-static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
+static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, GLMipmap_t *mipmap)
 {
 	UINT8 *block;
 	texture_t *texture;
@@ -441,57 +447,19 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
 	INT32 blockwidth, blockheight, blocksize;
 
 	INT32 i;
-	boolean skyspecial = false; //poor hack for Legacy large skies..
-
-	RGBA_t *palette;
-	palette = HWR_GetTexturePalette();
 
 	texture = textures[texnum];
 
-	// hack the Legacy skies..
-	if (texture->name[0] == 'S' &&
-	    texture->name[1] == 'K' &&
-	    texture->name[2] == 'Y' &&
-	    (texture->name[4] == 0 ||
-	     texture->name[5] == 0)
-	   )
-	{
-		skyspecial = true;
-		grtex->mipmap.flags = TF_WRAPXY; // don't use the chromakey for sky
-	}
-	else
-		grtex->mipmap.flags = TF_CHROMAKEYED | TF_WRAPXY;
-
-	grtex->mipmap.width = (UINT16)texture->width;
-	grtex->mipmap.height = (UINT16)texture->height;
-	if (skyspecial)
-		grtex->mipmap.format = GL_TEXFMT_RGBA; // that skyspecial code below assumes this format ...
-	else
-		grtex->mipmap.format = textureformat;
+	mipmap->flags = TF_WRAPXY;
+	mipmap->width = (UINT16)texture->width;
+	mipmap->height = (UINT16)texture->height;
+	mipmap->format = textureformat;
 
 	blockwidth = texture->width;
 	blockheight = texture->height;
 	blocksize = (blockwidth * blockheight);
 	block = MakeBlock(&grtex->mipmap);
 
-	if (skyspecial) //Hurdler: not efficient, but better than holes in the sky (and it's done only at level loading)
-	{
-		INT32 j;
-		RGBA_t col;
-
-		col = palette[HWR_PATCHES_CHROMAKEY_COLORINDEX];
-		for (j = 0; j < blockheight; j++)
-		{
-			for (i = 0; i < blockwidth; i++)
-			{
-				block[4*(j*blockwidth+i)+0] = col.s.red;
-				block[4*(j*blockwidth+i)+1] = col.s.green;
-				block[4*(j*blockwidth+i)+2] = col.s.blue;
-				block[4*(j*blockwidth+i)+3] = 0xff;
-			}
-		}
-	}
-
 	// Composite the columns together.
 	for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
 	{
@@ -526,13 +494,13 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
 			Patch_Free(realpatch);
 	}
 	//Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
-	if (format2bpp(grtex->mipmap.format)==4)
+	if (format2bpp(mipmap->format)==4)
 	{
 		for (i = 3; i < blocksize*4; i += 4) // blocksize*4 because blocksize doesn't include the bpp
 		{
 			if (block[i] == 0)
 			{
-				grtex->mipmap.flags |= TF_TRANSPARENT;
+				mipmap->flags |= TF_TRANSPARENT;
 				break;
 			}
 		}
@@ -661,8 +629,6 @@ void HWR_FreeTextureColormaps(patch_t *patch)
 			Z_Free(next->data);
 		if (next->colormap)
 			Z_Free(next->colormap);
-		next->data = NULL;
-		next->colormap = NULL;
 		HWD.pfnDeleteTexture(next);
 
 		// Free the old colormap mipmap from memory.
@@ -714,12 +680,25 @@ void HWR_InitMapTextures(void)
 	gl_maptexturesloaded = false;
 }
 
+static void DeleteTextureMipmap(GLMipmap_t *grMipmap)
+{
+	HWD.pfnDeleteTexture(grMipmap);
+
+	// Chroma-keyed textures do not own their texture data, so do not free it
+	if (!(grMipmap->flags & TF_CHROMAKEYED))
+		Z_Free(grMipmap->data);
+}
+
 static void FreeMapTexture(GLMapTexture_t *tex)
 {
-	HWD.pfnDeleteTexture(&tex->mipmap);
-	if (tex->mipmap.data)
-		Z_Free(tex->mipmap.data);
-	tex->mipmap.data = NULL;
+	if (tex->mipmap.nextcolormap)
+	{
+		DeleteTextureMipmap(tex->mipmap.nextcolormap);
+		free(tex->mipmap.nextcolormap);
+		tex->mipmap.nextcolormap = NULL;
+	}
+
+	DeleteTextureMipmap(&tex->mipmap);
 }
 
 void HWR_FreeMapTextures(void)
@@ -762,41 +741,47 @@ void HWR_LoadMapTextures(size_t pnumtextures)
 // --------------------------------------------------------------------------
 // Make sure texture is downloaded and set it as the source
 // --------------------------------------------------------------------------
-GLMapTexture_t *HWR_GetTexture(INT32 tex)
+static void GetMapTexture(INT32 tex, GLMapTexture_t *grtex, GLMipmap_t *mipmap)
 {
-	GLMapTexture_t *grtex;
-#ifdef PARANOIA
-	if ((unsigned)tex >= gl_numtextures)
-		I_Error("HWR_GetTexture: tex >= numtextures\n");
-#endif
-
-	// Every texture in memory, stored in the
-	// hardware renderer's bit depth format. Wow!
-	grtex = &gl_textures[tex];
-
 	// Generate texture if missing from the cache
-	if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
-		HWR_GenerateTexture(tex, grtex);
+	if (!mipmap->data && !mipmap->downloaded)
+		HWR_GenerateTexture(tex, grtex, mipmap);
 
 	// If hardware does not have the texture, then call pfnSetTexture to upload it
-	if (!grtex->mipmap.downloaded)
-		HWD.pfnSetTexture(&grtex->mipmap);
-	HWR_SetCurrentTexture(&grtex->mipmap);
+	if (!mipmap->downloaded)
+		HWD.pfnSetTexture(mipmap);
+	HWR_SetCurrentTexture(mipmap);
 
 	// The system-memory data can be purged now.
-	Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
+	Z_ChangeTag(mipmap->data, PU_HWRCACHE_UNLOCKED);
+}
+
+GLMapTexture_t *HWR_GetTexture(INT32 tex)
+{
+	if (tex < 0 || tex >= (signed)gl_numtextures)
+	{
+#ifdef PARANOIA
+		I_Error("HWR_GetTexture: Invalid texture ID %d", tex);
+#else
+		tex = 0;
+#endif
+	}
+
+	GLMapTexture_t *grtex = &gl_textures[tex];
+
+	GetMapTexture(tex, grtex, &grtex->mipmap);
 
 	return grtex;
 }
 
-static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
+static void HWR_CacheRawFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
 {
 	size_t size = W_LumpLength(flatlumpnum);
 	UINT16 pflatsize = R_GetFlatSize(size);
 
 	// setup the texture info
 	grMipmap->format = GL_TEXFMT_P_8;
-	grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
+	grMipmap->flags = TF_WRAPXY;
 
 	grMipmap->width = pflatsize;
 	grMipmap->height = pflatsize;
@@ -817,7 +802,7 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum)
 	patch = HWR_GetCachedGLPatch(flatlumpnum);
 	grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
 	if (!grmip->downloaded && !grmip->data)
-		HWR_CacheFlat(grmip, flatlumpnum);
+		HWR_CacheRawFlat(grmip, flatlumpnum);
 
 	// If hardware does not have the texture, then call pfnSetTexture to upload it
 	if (!grmip->downloaded)
@@ -828,7 +813,16 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum)
 	Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
 }
 
-void HWR_GetLevelFlat(levelflat_t *levelflat)
+static void MakeLevelFlatMipmap(GLMipmap_t *grMipmap, INT32 texturenum, UINT16 flags)
+{
+	grMipmap->format = GL_TEXFMT_P_8;
+	grMipmap->flags = flags;
+
+	grMipmap->width  = (UINT16)textures[texturenum]->width;
+	grMipmap->height = (UINT16)textures[texturenum]->height;
+}
+
+void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed)
 {
 	if (levelflat->type == LEVELFLAT_NONE || levelflat->texture_id < 0)
 	{
@@ -839,24 +833,50 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 	INT32 texturenum = texturetranslation[levelflat->texture_id];
 
 	GLMapTexture_t *grtex = &gl_flats[texturenum];
+
 	GLMipmap_t *grMipmap = &grtex->mipmap;
+	GLMipmap_t *originalMipmap = grMipmap;
+
+	if (!originalMipmap->downloaded)
+		MakeLevelFlatMipmap(originalMipmap, texturenum, TF_WRAPXY);
+
+	if (!originalMipmap->data)
+	{
+		size_t size = originalMipmap->width * originalMipmap->height;
+		memcpy(Z_Malloc(size, PU_HWRCACHE, &originalMipmap->data), R_GetFlatForTexture(texturenum), size);
+	}
 
-	if (!grMipmap->data && !grMipmap->downloaded)
+	// If chroma-keyed, create or use a different mipmap for the variant
+	if (chromakeyed)
 	{
-		grMipmap->format = GL_TEXFMT_P_8;
-		grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
+		if (!originalMipmap->data)
+		{
+			HWR_SetCurrentTexture(NULL);
+			return;
+		}
+
+		// Allocate it if it wasn't already
+		if (!originalMipmap->nextcolormap)
+		{
+			GLMipmap_t *newMipmap = calloc(1, sizeof (*grMipmap));
+			if (newMipmap == NULL)
+				I_Error("%s: Out of memory", "HWR_GetLevelFlat");
+			MakeLevelFlatMipmap(newMipmap, texturenum, TF_WRAPXY | TF_CHROMAKEYED);
+			originalMipmap->nextcolormap = newMipmap;
+		}
 
-		grMipmap->width  = (UINT16)textures[texturenum]->width;
-		grMipmap->height = (UINT16)textures[texturenum]->height;
+		// Upload and bind the variant texture instead of the original one
+		grMipmap = originalMipmap->nextcolormap;
 
-		size_t size = grMipmap->width * grMipmap->height;
-		memcpy(Z_Malloc(size, PU_HWRCACHE, &grMipmap->data), R_GetFlatForTexture(texturenum), size);
+		// Use the original texture's pixel data
+		// It can just be a pointer to it, since the r_opengl backend deals with the pixels
+		// that are supposed to be transparent.
+		grMipmap->data = originalMipmap->data;
 	}
 
 	if (!grMipmap->downloaded)
-		HWD.pfnSetTexture(&grtex->mipmap);
-
-	HWR_SetCurrentTexture(&grtex->mipmap);
+		HWD.pfnSetTexture(grMipmap);
+	HWR_SetCurrentTexture(grMipmap);
 
 	Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
 }
@@ -972,139 +992,6 @@ void HWR_UnlockCachedPatch(GLPatch_t *gpatch)
 	Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
 }
 
-static const INT32 picmode2GR[] =
-{
-	GL_TEXFMT_P_8,                // PALETTE
-	0,                            // INTENSITY          (unsupported yet)
-	GL_TEXFMT_ALPHA_INTENSITY_88, // INTENSITY_ALPHA    (corona use this)
-	0,                            // RGB24              (unsupported yet)
-	GL_TEXFMT_RGBA,               // RGBA32             (opengl only)
-};
-
-static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheight,
-	INT32 blockmodulo, pic_t *pic, INT32 bpp)
-{
-	INT32 i,j;
-	fixed_t posx, posy, stepx, stepy;
-	UINT8 *dest, *src, texel;
-	UINT16 texelu16;
-	INT32 picbpp;
-	RGBA_t col;
-	RGBA_t *palette = HWR_GetTexturePalette();
-
-	stepy = ((INT32)SHORT(pic->height)<<FRACBITS)/pblockheight;
-	stepx = ((INT32)SHORT(pic->width)<<FRACBITS)/pblockwidth;
-	picbpp = format2bpp(picmode2GR[pic->mode]);
-	posy = 0;
-	for (j = 0; j < pblockheight; j++)
-	{
-		posx = 0;
-		dest = &block[j*blockmodulo];
-		src = &pic->data[(posy>>FRACBITS)*SHORT(pic->width)*picbpp];
-		for (i = 0; i < pblockwidth;i++)
-		{
-			switch (pic->mode)
-			{ // source bpp
-				case PALETTE :
-					texel = src[(posx+FRACUNIT/2)>>FRACBITS];
-					switch (bpp)
-					{ // destination bpp
-						case 1 :
-							*dest++ = texel; break;
-						case 2 :
-							texelu16 = (UINT16)(texel | 0xff00);
-							memcpy(dest, &texelu16, sizeof(UINT16));
-							dest += sizeof(UINT16);
-							break;
-						case 3 :
-							col = palette[texel];
-							memcpy(dest, &col, sizeof(RGBA_t)-sizeof(UINT8));
-							dest += sizeof(RGBA_t)-sizeof(UINT8);
-							break;
-						case 4 :
-							memcpy(dest, &palette[texel], sizeof(RGBA_t));
-							dest += sizeof(RGBA_t);
-							break;
-					}
-					break;
-				case INTENSITY :
-					*dest++ = src[(posx+FRACUNIT/2)>>FRACBITS];
-					break;
-				case INTENSITY_ALPHA : // assume dest bpp = 2
-					memcpy(dest, src + ((posx+FRACUNIT/2)>>FRACBITS)*sizeof(UINT16), sizeof(UINT16));
-					dest += sizeof(UINT16);
-					break;
-				case RGB24 :
-					break;  // not supported yet
-				case RGBA32 : // assume dest bpp = 4
-					dest += sizeof(UINT32);
-					memcpy(dest, src + ((posx+FRACUNIT/2)>>FRACBITS)*sizeof(UINT32), sizeof(UINT32));
-					break;
-			}
-			posx += stepx;
-		}
-		posy += stepy;
-	}
-}
-
-// -----------------+
-// HWR_GetPic       : Download a Doom pic (raw row encoded with no 'holes')
-// Returns          :
-// -----------------+
-patch_t *HWR_GetPic(lumpnum_t lumpnum)
-{
-	patch_t *patch = HWR_GetCachedGLPatch(lumpnum);
-	GLPatch_t *grPatch = (GLPatch_t *)(patch->hardware);
-
-	if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data)
-	{
-		pic_t *pic;
-		UINT8 *block;
-		size_t len;
-
-		pic = W_CacheLumpNum(lumpnum, PU_CACHE);
-		patch->width = SHORT(pic->width);
-		patch->height = SHORT(pic->height);
-		len = W_LumpLength(lumpnum) - sizeof (pic_t);
-
-		grPatch->mipmap->width = (UINT16)patch->width;
-		grPatch->mipmap->height = (UINT16)patch->height;
-
-		if (pic->mode == PALETTE)
-			grPatch->mipmap->format = textureformat; // can be set by driver
-		else
-			grPatch->mipmap->format = picmode2GR[pic->mode];
-
-		Z_Free(grPatch->mipmap->data);
-
-		// allocate block
-		block = MakeBlock(grPatch->mipmap);
-
-		if (patch->width  == SHORT(pic->width) &&
-			patch->height == SHORT(pic->height) &&
-			format2bpp(grPatch->mipmap->format) == format2bpp(picmode2GR[pic->mode]))
-		{
-			// no conversion needed
-			M_Memcpy(grPatch->mipmap->data, pic->data,len);
-		}
-		else
-			HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height),
-			                   SHORT(pic->width)*format2bpp(grPatch->mipmap->format),
-			                   pic,
-			                   format2bpp(grPatch->mipmap->format));
-
-		Z_Unlock(pic);
-		Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED);
-
-		grPatch->mipmap->flags = 0;
-		grPatch->max_s = grPatch->max_t = 1.0f;
-	}
-	HWD.pfnSetTexture(grPatch->mipmap);
-	//CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grPatch->mipmap->data, grPatch->mipmap->downloaded);
-
-	return patch;
-}
-
 patch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum)
 {
 	lumpcache_t *lumpcache = wadfiles[wadnum]->patchcache;
diff --git a/src/hardware/hw_clip.c b/src/hardware/hw_clip.c
index 86e0c58d25a72956dd9b10d6950baf10fd731ae1..74268423f5526c8d2c8733775b9f2ca60fb6141e 100644
--- a/src/hardware/hw_clip.c
+++ b/src/hardware/hw_clip.c
@@ -320,16 +320,13 @@ void gld_clipper_Clear(void)
 
 #define RMUL (1.6f/1.333333f)
 
-angle_t gld_FrustumAngle(angle_t tiltangle)
+angle_t gld_FrustumAngle(float render_fov, angle_t tiltangle)
 {
 	double floatangle;
 	angle_t a1;
 
 	float tilt = (float)fabs(((double)(int)tiltangle) / ANG1);
 
-	// NEWCLIP TODO: SRB2CBTODO: make a global render_fov for this function
-
-	float render_fov = FIXED_TO_FLOAT(cv_fov.value);
 	float render_fovratio = (float)BASEVIDWIDTH / (float)BASEVIDHEIGHT; // SRB2CBTODO: NEWCLIPTODO: Is this right?
 	float render_multiplier = 64.0f / render_fovratio / RMUL;
 
diff --git a/src/hardware/hw_clip.h b/src/hardware/hw_clip.h
index 27a2ed1efa2de4b9f6d54278a5052fb03c4a1d46..e3bb4c3193ca0094871f15d89e892a8c769d14d0 100644
--- a/src/hardware/hw_clip.h
+++ b/src/hardware/hw_clip.h
@@ -17,7 +17,7 @@
 boolean gld_clipper_SafeCheckRange(angle_t startAngle, angle_t endAngle);
 void gld_clipper_SafeAddClipRange(angle_t startangle, angle_t endangle);
 void gld_clipper_Clear(void);
-angle_t gld_FrustumAngle(angle_t tiltangle);
+angle_t gld_FrustumAngle(float render_fov, angle_t tiltangle);
 #ifdef HAVE_SPHEREFRUSTRUM
 void gld_FrustrumSetup(void);
 boolean gld_SphereInFrustum(float x, float y, float z, float radius);
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 2d55eef2d8fd72271fef9c529d4be862318f93da..7d06ceb60b86d8ef3fff3d30a21ce29213d6c600 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -246,7 +246,7 @@ enum ETextureFlags
 	TF_WRAPX       = 0x00000001,        // wrap around X
 	TF_WRAPY       = 0x00000002,        // wrap around Y
 	TF_WRAPXY      = TF_WRAPY|TF_WRAPX, // very common so use alias is more easy
-	TF_CHROMAKEYED = 0x00000010,
+	TF_CHROMAKEYED = 0x00000010,        // Used only for flats with pixels that have palette index 255
 	TF_TRANSPARENT = 0x00000040,        // texture with some alpha == 0
 };
 
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index e07484137c83433edc89207a3b85ae5f921d348d..ddce7d9885d7607e1cabf9bfc5c74ecf6258612b 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -22,7 +22,6 @@
 #include "hw_drv.h"
 
 #include "../m_misc.h" //FIL_WriteFile()
-#include "../r_draw.h" //viewborderlump
 #include "../r_main.h"
 #include "../w_wad.h"
 #include "../z_zone.h"
@@ -33,11 +32,7 @@
 #include "../f_finale.h" // fade color factors
 
 #include <fcntl.h>
-#include "../i_video.h"  // for rendermode != render_glide
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
+#include "../i_video.h"
 
 #if defined(_MSC_VER)
 #pragma pack(1)
@@ -63,63 +58,6 @@ static UINT8 softwaretranstogl[11]    = {  0, 25, 51, 76,102,127,153,178,204,229
 static UINT8 softwaretranstogl_hi[11] = {  0, 51,102,153,204,255,255,255,255,255,255};
 static UINT8 softwaretranstogl_lo[11] = {  0, 12, 24, 36, 48, 60, 71, 83, 95,111,127};
 
-//
-// -----------------+
-// HWR_DrawPatch    : Draw a 'tile' graphic
-// Notes            : x,y : positions relative to the original Doom resolution
-//                  : textes(console+score) + menus + status bar
-// -----------------+
-void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option)
-{
-	FOutVector v[4];
-	FBITFIELD flags;
-	GLPatch_t *hwrPatch;
-
-//  3--2
-//  | /|
-//  |/ |
-//  0--1
-	float sdup = FIXED_TO_FLOAT(vid.fdup)*2.0f;
-	float pdup = FIXED_TO_FLOAT(vid.fdup)*2.0f;
-
-	// make patch ready in hardware cache
-	HWR_GetPatch(gpatch);
-	hwrPatch = ((GLPatch_t *)gpatch->hardware);
-
-	switch (option & V_SCALEPATCHMASK)
-	{
-	case V_NOSCALEPATCH:
-		pdup = 2.0f;
-		break;
-	case V_SMALLSCALEPATCH:
-		pdup = 2.0f * FIXED_TO_FLOAT(vid.fsmalldup);
-		break;
-	case V_MEDSCALEPATCH:
-		pdup = 2.0f * FIXED_TO_FLOAT(vid.fmeddup);
-		break;
-	}
-
-	if (option & V_NOSCALESTART)
-		sdup = 2.0f;
-
-	v[0].x = v[3].x = (x*sdup-(gpatch->leftoffset)*pdup)/vid.width - 1;
-	v[2].x = v[1].x = (x*sdup+(gpatch->width-gpatch->leftoffset)*pdup)/vid.width - 1;
-	v[0].y = v[1].y = 1-(y*sdup-(gpatch->topoffset)*pdup)/vid.height;
-	v[2].y = v[3].y = 1-(y*sdup+(gpatch->height-gpatch->topoffset)*pdup)/vid.height;
-
-	v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
-
-	v[0].s = v[3].s = 0.0f;
-	v[2].s = v[1].s = hwrPatch->max_s;
-	v[0].t = v[1].t = 0.0f;
-	v[2].t = v[3].t = hwrPatch->max_t;
-
-	flags = PF_Translucent|PF_NoDepthTest;
-
-	// clip it since it is used for bunny scroll in doom I
-	HWD.pfnDrawPolygon(NULL, v, 4, flags);
-}
-
 void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap)
 {
 	FOutVector v[4];
@@ -1005,136 +943,6 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight)
 	HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
 }
 
-
-// ==========================================================================
-//                                                             R_DRAW.C STUFF
-// ==========================================================================
-
-// ------------------
-// HWR_DrawViewBorder
-// Fill the space around the view window with a Doom flat texture, draw the
-// beveled edges.
-// 'clearlines' is useful to clear the heads up messages, when the view
-// window is reduced, it doesn't refresh all the view borders.
-// ------------------
-void HWR_DrawViewBorder(INT32 clearlines)
-{
-	INT32 x, y;
-	INT32 top, side;
-	INT32 baseviewwidth, baseviewheight;
-	INT32 basewindowx, basewindowy;
-	patch_t *patch;
-
-//    if (gl_viewwidth == vid.width)
-//        return;
-
-	if (!clearlines)
-		clearlines = BASEVIDHEIGHT; // refresh all
-
-	// calc view size based on original game resolution
-	baseviewwidth =  FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwidth), vid.fdup)); //(cv_viewsize.value * BASEVIDWIDTH/10)&~7;
-	baseviewheight = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewheight), vid.fdup));
-	top = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_baseviewwindowy), vid.fdup));
-	side = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwindowx), vid.fdup));
-
-	// top
-	HWR_DrawFlatFill(0, 0,
-		BASEVIDWIDTH, (top < clearlines ? top : clearlines),
-		st_borderpatchnum);
-
-	// left
-	if (top < clearlines)
-		HWR_DrawFlatFill(0, top, side,
-			(clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
-			st_borderpatchnum);
-
-	// right
-	if (top < clearlines)
-		HWR_DrawFlatFill(side + baseviewwidth, top, side,
-			(clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
-			st_borderpatchnum);
-
-	// bottom
-	if (top + baseviewheight < clearlines)
-		HWR_DrawFlatFill(0, top + baseviewheight,
-			BASEVIDWIDTH, BASEVIDHEIGHT, st_borderpatchnum);
-
-	//
-	// draw the view borders
-	//
-
-	basewindowx = (BASEVIDWIDTH - baseviewwidth)>>1;
-	if (baseviewwidth == BASEVIDWIDTH)
-		basewindowy = 0;
-	else
-		basewindowy = top;
-
-	// top edge
-	if (clearlines > basewindowy - 8)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH);
-		for (x = 0; x < baseviewwidth; x += 8)
-			HWR_DrawPatch(patch, basewindowx + x, basewindowy - 8,
-				0);
-	}
-
-	// bottom edge
-	if (clearlines > basewindowy + baseviewheight)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH);
-		for (x = 0; x < baseviewwidth; x += 8)
-			HWR_DrawPatch(patch, basewindowx + x,
-				basewindowy + baseviewheight, 0);
-	}
-
-	// left edge
-	if (clearlines > basewindowy)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH);
-		for (y = 0; y < baseviewheight && basewindowy + y < clearlines;
-			y += 8)
-		{
-			HWR_DrawPatch(patch, basewindowx - 8, basewindowy + y,
-				0);
-		}
-	}
-
-	// right edge
-	if (clearlines > basewindowy)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH);
-		for (y = 0; y < baseviewheight && basewindowy+y < clearlines;
-			y += 8)
-		{
-			HWR_DrawPatch(patch, basewindowx + baseviewwidth,
-				basewindowy + y, 0);
-		}
-	}
-
-	// Draw beveled corners.
-	if (clearlines > basewindowy - 8)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TL],
-				PU_PATCH),
-			basewindowx - 8, basewindowy - 8, 0);
-
-	if (clearlines > basewindowy - 8)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TR],
-				PU_PATCH),
-			basewindowx + baseviewwidth, basewindowy - 8, 0);
-
-	if (clearlines > basewindowy+baseviewheight)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BL],
-				PU_PATCH),
-			basewindowx - 8, basewindowy + baseviewheight, 0);
-
-	if (clearlines > basewindowy + baseviewheight)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BR],
-				PU_PATCH),
-			basewindowx + baseviewwidth,
-			basewindowy + baseviewheight, 0);
-}
-
-
 // ==========================================================================
 //                                                     AM_MAP.C DRAWING STUFF
 // ==========================================================================
@@ -1546,7 +1354,7 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
 	INT32 i;
 	UINT8 *buf8 = buffer;
 
-	fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+	fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
 	if (fd < 0)
 		return false;
 
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index ba0258c120de3bd388513c827d03ecaa8689424e..45ee2933a69bca328be875ec2e449ca7f74cab39 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -29,9 +29,6 @@ EXPORT boolean HWRAPI(Init) (void);
 #ifndef HAVE_SDL
 EXPORT void HWRAPI(Shutdown) (void);
 #endif
-#ifdef _WINDOWS
-EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes);
-#endif
 EXPORT void HWRAPI(SetTexturePalette) (RGBA_t *ppal);
 EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
 EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 094d356d530a24f010896141a8f6b8bc6b0777ae..807c7098946b5589ce7d3394f864d6dccb484194 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -119,10 +119,9 @@ patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum);
 void HWR_GetPatch(patch_t *patch);
 void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap);
 void HWR_GetFadeMask(lumpnum_t fademasklumpnum);
-patch_t *HWR_GetPic(lumpnum_t lumpnum);
 
 GLMapTexture_t *HWR_GetTexture(INT32 tex);
-void HWR_GetLevelFlat(levelflat_t *levelflat);
+void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed);
 void HWR_GetRawFlat(lumpnum_t flatlumpnum);
 
 void HWR_FreeTexture(patch_t *patch);
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index bcfdfa960d7b723ecb0be2437667bcf09b1030e9..e7769edbd8da2dbaa38debfabae9a34f25d121ee 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -1055,7 +1055,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr)
 		light[3].y = cy+size*1.33f+p_lspr->light_yoffset;
 		light[3].s = 0.0f;   light[3].t = 1.0f;
 
-		HWR_GetPic(coronalumpnum);  /// \todo use different coronas
+		// HWR_GetPic(coronalumpnum);  /// \todo use different coronas
 
 		HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Corona | PF_NoDepthTest);
 	}
@@ -1071,7 +1071,7 @@ void HWR_DrawCoronas(void)
 	if (!cv_glcoronas.value || dynlights->nb <= 0 || coronalumpnum == LUMPERROR)
 		return;
 
-	HWR_GetPic(coronalumpnum);  /// \todo use different coronas
+	// HWR_GetPic(coronalumpnum);  /// \todo use different coronas
 	for (j = 0;j < dynlights->nb;j++)
 	{
 		FOutVector      light[4];
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 1cfffca541d048fece90d1b1970b5b2f62ab69bc..f533082f76e6db8af21e90c6dcf4f98949f7f532 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -19,8 +19,10 @@
 #include "hw_light.h"
 #include "hw_drv.h"
 #include "hw_batching.h"
+#include "hw_md2.h"
+#include "hw_clip.h"
 
-#include "../i_video.h" // for rendermode == render_glide
+#include "../i_video.h"
 #include "../v_video.h"
 #include "../p_local.h"
 #include "../p_setup.h"
@@ -42,15 +44,6 @@
 #include "../r_translation.h"
 #include "../d_main.h"
 #include "../p_slopes.h"
-#include "hw_md2.h"
-
-#ifdef NEWCLIP
-#include "hw_clip.h"
-#endif
-
-#define R_FAKEFLOORS
-#define HWPRECIP
-//#define POLYSKY
 
 // ==========================================================================
 // the hardware driver object
@@ -61,69 +54,21 @@ struct hwdriver_s hwdriver;
 //                                                                     PROTOS
 // ==========================================================================
 
-
 static void HWR_AddSprites(sector_t *sec);
 static void HWR_ProjectSprite(mobj_t *thing);
-#ifdef HWPRECIP
 static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
-#endif
 static void HWR_ProjectBoundingBox(mobj_t *thing);
 
-void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
+void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, boolean chromakeyed, extracolormap_t *planecolormap);
 void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
                              INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
 
-boolean drawsky = true;
-
-// ==========================================================================
-//                                                               VIEW GLOBALS
-// ==========================================================================
-// Fineangles in the SCREENWIDTH wide window.
-#define FIELDOFVIEW ANGLE_90
-#define ABS(x) ((x) < 0 ? -(x) : (x))
-
-static angle_t gl_clipangle;
-
-// The viewangletox[viewangle + FINEANGLES/4] lookup
-// maps the visible view angles to screen X coordinates,
-// flattening the arc to a flat projection plane.
-// There will be many angles mapped to the same X.
-static INT32 gl_viewangletox[FINEANGLES/2];
-
-// The xtoviewangleangle[] table maps a screen pixel
-// to the lowest viewangle that maps back to x ranges
-// from clipangle to -clipangle.
-static angle_t gl_xtoviewangle[MAXVIDWIDTH+1];
+static boolean drawsky = true;
 
 // ==========================================================================
 //                                                                    GLOBALS
 // ==========================================================================
 
-// uncomment to remove the plane rendering
-#define DOPLANES
-//#define DOWALLS
-
-// test of drawing sky by polygons like in software with visplane, unfortunately
-// this doesn't work since we must have z for pixel and z for texture (not like now with z = oow)
-//#define POLYSKY
-
-// test change fov when looking up/down but bsp projection messup :(
-//#define NOCRAPPYMLOOK
-
-// base values set at SetViewSize
-static float gl_basecentery;
-
-float gl_baseviewwindowy, gl_basewindowcentery;
-float gl_viewwidth, gl_viewheight; // viewport clipping boundaries (screen coords)
-float gl_viewwindowx;
-
-static float gl_centerx, gl_centery;
-static float gl_viewwindowy; // top left corner of view window
-static float gl_windowcenterx; // center of view window, for projection
-static float gl_windowcentery;
-
-static float gl_pspritexscale, gl_pspriteyscale;
-
 static seg_t *gl_curline;
 static side_t *gl_sidedef;
 static line_t *gl_linedef;
@@ -162,16 +107,12 @@ static boolean gl_palette_rendering_state = false;
 // --------------------------------------------------------------------------
 
 FTransform atransform;
-// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
-// copied here for local use
-static fixed_t dup_viewx, dup_viewy, dup_viewz;
-static angle_t dup_viewangle;
 
 static float gl_viewx, gl_viewy, gl_viewz;
 float gl_viewsin, gl_viewcos;
 
-// Maybe not necessary with the new T&L code (needs to be checked!)
-static float gl_viewludsin, gl_viewludcos; // look up down kik test
+// For HWR_RotateSpritePolyToAim
+static float gl_viewludsin, gl_viewludcos;
 static float gl_fovlud;
 
 static angle_t gl_aimingangle;
@@ -372,8 +313,6 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
 //                                   FLOOR/CEILING GENERATION FROM SUBSECTORS
 // ==========================================================================
 
-#ifdef DOPLANES
-
 // -----------------+
 // HWR_RenderPlane  : Render a floor or ceiling convex polygon
 // -----------------+
@@ -400,6 +339,9 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
 	static FOutVector *planeVerts = NULL;
 	static UINT16 numAllocedPlaneVerts = 0;
 
+	if (!r_renderfloors)
+		return;
+
 	// no convex poly were generated for this subsector
 	if (!xsub->planepoly)
 		return;
@@ -562,7 +504,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
 
 		for (i = 0; i < subsector->numlines; i++, line++)
 		{
-			if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0)
+			if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(viewx, viewy, line) == 0)
 			{
 				P_ClosestPointOnLine(viewx, viewy, line->linedef, &v);
 				dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y));
@@ -641,52 +583,6 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
 #endif
 }
 
-#ifdef POLYSKY
-// this don't draw anything it only update the z-buffer so there isn't problem with
-// wall/things upper that sky (map12)
-static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight)
-{
-	polyvertex_t *pv;
-	float height; //constant y for all points on the convex flat polygon
-	FOutVector *v3d;
-	INT32 nrPlaneVerts;   //verts original define of convex flat polygon
-	INT32 i;
-
-	// no convex poly were generated for this subsector
-	if (!xsub->planepoly)
-		return;
-
-	height = FIXED_TO_FLOAT(fixedheight);
-
-	pv  = xsub->planepoly->pts;
-	nrPlaneVerts = xsub->planepoly->numpts;
-
-	if (nrPlaneVerts < 3) // not even a triangle?
-		return;
-
-	if (nrPlaneVerts > MAXPLANEVERTICES) // FIXME: exceeds plVerts size
-	{
-		CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, MAXPLANEVERTICES);
-		return;
-	}
-
-	// transform
-	v3d = planeVerts;
-	for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++)
-	{
-		v3d->s = 0.0f;
-		v3d->t = 0.0f;
-		v3d->x = pv->x;
-		v3d->y = height;
-		v3d->z = pv->y;
-	}
-
-	HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, PF_Invisible|PF_NoTexture|PF_Occlude);
-}
-#endif //polysky
-
-#endif //doplanes
-
 FBITFIELD HWR_GetBlendModeFlag(INT32 style)
 {
 	switch (style)
@@ -772,6 +668,9 @@ static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIEL
 {
 	INT32 shader = SHADER_NONE;
 
+	if (!r_renderwalls)
+		return;
+
 	HWR_Lighting(pSurf, lightlevel, wallcolormap);
 
 	if (HWR_UseShader())
@@ -787,41 +686,6 @@ static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIEL
 //                                                          BSP, CULL, ETC..
 // ==========================================================================
 
-// return the frac from the interception of the clipping line
-// (in fact a clipping plane that has a constant, so can clip with simple 2d)
-// with the wall segment
-//
-#ifndef NEWCLIP
-static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2)
-{
-	float num, den;
-	float v1x, v1y, v1dx, v1dy, v2dx, v2dy;
-	angle_t pclipangle = gl_xtoviewangle[x];
-
-	// a segment of a polygon
-	v1x  = v1->x;
-	v1y  = v1->y;
-	v1dx = (v2->x - v1->x);
-	v1dy = (v2->y - v1->y);
-
-	// the clipping line
-	pclipangle = pclipangle + dup_viewangle; //back to normal angle (non-relative)
-	v2dx = FIXED_TO_FLOAT(FINECOSINE(pclipangle>>ANGLETOFINESHIFT));
-	v2dy = FIXED_TO_FLOAT(FINESINE(pclipangle>>ANGLETOFINESHIFT));
-
-	den = v2dy*v1dx - v2dx*v1dy;
-	if (den == 0)
-		return -1; // parallel
-
-	// calc the frac along the polygon segment,
-	//num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx;
-	//num = -v1x * v2dy + v1y * v2dx;
-	num = (gl_viewx - v1x)*v2dy + (v1y - gl_viewy)*v2dx;
-
-	return num / den;
-}
-#endif
-
 // SoM: split up and light walls according to the lightlist.
 // This may also include leaving out parts of the wall that can't be seen
 static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor, FBITFIELD polyflags)
@@ -845,6 +709,9 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
 	FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
 	extracolormap_t *colormap = NULL;
 
+	if (!r_renderwalls)
+		return;
+
 	realtop = top = wallVerts[3].y;
 	realbot = bot = wallVerts[0].y;
 	diff = top - bot;
@@ -1011,7 +878,7 @@ static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf)
 	// PF_Occlude is set in HWR_ProjectWall to draw into the depth buffer
 }
 
-// Returns true if the midtexture is visible, and false if... it isn't...
+// Returns true if the midtexture is visible, false if not
 static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf)
 {
 	FUINT blendmode = PF_Masked;
@@ -1047,14 +914,193 @@ static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf)
 	return true;
 }
 
-//
-// HWR_ProcessSeg
-// A portion or all of a wall segment will be drawn, from startfrac to endfrac,
-//  where 0 is the start of the segment, 1 the end of the segment
-// Anything between means the wall segment has been clipped with solidsegs,
-//  reducing wall overdraw to a minimum
-//
-static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
+static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliphigh, fixed_t worldtop, fixed_t worldbottom, fixed_t worldhigh, fixed_t worldlow, fixed_t worldtopslope, fixed_t worldbottomslope, fixed_t worldhighslope, fixed_t worldlowslope, UINT32 lightnum, FOutVector *inWallVerts)
+{
+	FOutVector wallVerts[4];
+
+	FSurfaceInfo Surf;
+	Surf.PolyColor.s.alpha = 255;
+
+	// Determine if it's visible
+	if (!HWR_BlendMidtextureSurface(&Surf))
+		return;
+
+	fixed_t texheight = FixedDiv(textureheight[gl_midtexture], abs(gl_sidedef->scaley_mid));
+	INT32 repeats;
+
+	if (gl_sidedef->repeatcnt)
+		repeats = 1 + gl_sidedef->repeatcnt;
+	else if (gl_linedef->flags & ML_WRAPMIDTEX)
+	{
+		fixed_t high, low;
+
+		if (gl_frontsector->ceilingheight > gl_backsector->ceilingheight)
+			high = gl_backsector->ceilingheight;
+		else
+			high = gl_frontsector->ceilingheight;
+
+		if (gl_frontsector->floorheight > gl_backsector->floorheight)
+			low = gl_frontsector->floorheight;
+		else
+			low = gl_backsector->floorheight;
+
+		repeats = (high - low) / texheight;
+		if ((high - low) % texheight)
+			repeats++; // tile an extra time to fill the gap -- Monster Iestyn
+	}
+	else
+		repeats = 1;
+
+	GLMapTexture_t *grTex = HWR_GetTexture(gl_midtexture);
+	float xscale = FixedToFloat(gl_sidedef->scalex_mid);
+	float yscale = FixedToFloat(gl_sidedef->scaley_mid);
+
+	// SoM: a little note: popentop and popenbottom
+	// record the limits the texture can be displayed in.
+	// polytop and polybottom, are the ideal (i.e. unclipped)
+	// heights of the polygon, and h & l, are the final (clipped)
+	// poly coords.
+	fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut;
+	fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope;
+
+	// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
+	// you must use the linedef's backsector to be correct
+	// From CB
+	if (gl_curline->polyseg)
+	{
+		// Change this when polyobjects support slopes
+		popentop = popentopslope = gl_curline->backsector->ceilingheight;
+		popenbottom = popenbottomslope = gl_curline->backsector->floorheight;
+	}
+	else
+	{
+		popentop = min(worldtop, worldhigh);
+		popenbottom = max(worldbottom, worldlow);
+		popentopslope = min(worldtopslope, worldhighslope);
+		popenbottomslope = max(worldbottomslope, worldlowslope);
+	}
+
+	// Find the wall's coordinates
+	fixed_t midtexheight = texheight * repeats;
+
+	fixed_t rowoffset = FixedDiv(gl_sidedef->rowoffset + gl_sidedef->offsety_mid, abs(gl_sidedef->scaley_mid));
+
+	// Texture is not skewed
+	if (gl_linedef->flags & ML_NOSKEW)
+	{
+		// Peg it to the floor
+		if (gl_linedef->flags & ML_MIDPEG)
+		{
+			polybottom = max(gl_frontsector->floorheight, gl_backsector->floorheight) + rowoffset;
+			polytop = polybottom + midtexheight;
+		}
+		// Peg it to the ceiling
+		else
+		{
+			polytop = min(gl_frontsector->ceilingheight, gl_backsector->ceilingheight) + rowoffset;
+			polybottom = polytop - midtexheight;
+		}
+
+		// The right side's coordinates are the the same as the left side
+		polytopslope = polytop;
+		polybottomslope = polybottom;
+	}
+	// Skew the texture, but peg it to the floor
+	else if (gl_linedef->flags & ML_MIDPEG)
+	{
+		polybottom = popenbottom + rowoffset;
+		polytop = polybottom + midtexheight;
+		polybottomslope = popenbottomslope + rowoffset;
+		polytopslope = polybottomslope + midtexheight;
+	}
+	// Skew it according to the ceiling's slope
+	else
+	{
+		polytop = popentop + rowoffset;
+		polybottom = polytop - midtexheight;
+		polytopslope = popentopslope + rowoffset;
+		polybottomslope = polytopslope - midtexheight;
+	}
+
+	// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
+	if (gl_curline->polyseg)
+	{
+		lowcut = polybottom;
+		highcut = polytop;
+		lowcutslope = polybottomslope;
+		highcutslope = polytopslope;
+	}
+	else
+	{
+		lowcut = popenbottom;
+		highcut = popentop;
+		lowcutslope = popenbottomslope;
+		highcutslope = popentopslope;
+	}
+
+	fixed_t h = min(highcut, polytop);
+	fixed_t l = max(polybottom, lowcut);
+	fixed_t hS = min(highcutslope, polytopslope);
+	fixed_t lS = max(polybottomslope, lowcutslope);
+
+	// PEGGING
+	fixed_t texturevpeg, texturevpegslope;
+
+	if (gl_linedef->flags & ML_MIDPEG)
+	{
+		texturevpeg = midtexheight - h + polybottom;
+		texturevpegslope = midtexheight - hS + polybottomslope;
+	}
+	else
+	{
+		texturevpeg = polytop - h;
+		texturevpegslope = polytopslope - hS;
+	}
+
+	memcpy(wallVerts, inWallVerts, sizeof(wallVerts));
+
+	// Left side
+	wallVerts[3].t = texturevpeg * yscale * grTex->scaleY;
+	wallVerts[0].t = (h - l + texturevpeg) * yscale * grTex->scaleY;
+	wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
+
+	// Right side
+	wallVerts[2].t = texturevpegslope * yscale * grTex->scaleY;
+	wallVerts[1].t = (hS - lS + texturevpegslope) * yscale * grTex->scaleY;
+	wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
+
+	// set top/bottom coords
+	// Take the texture peg into account, rather than changing the offsets past
+	// where the polygon might not be.
+	wallVerts[3].y = FIXED_TO_FLOAT(h);
+	wallVerts[0].y = FIXED_TO_FLOAT(l);
+	wallVerts[2].y = FIXED_TO_FLOAT(hS);
+	wallVerts[1].y = FIXED_TO_FLOAT(lS);
+
+	// TODO: Actually use the surface's flags so that I don't have to do this
+	FUINT blendmode = Surf.PolyFlags;
+
+	// Render midtextures on two-sided lines with a z-buffer offset.
+	// This will cause the midtexture appear on top, if a FOF overlaps with it.
+	blendmode |= PF_Decal;
+
+	extracolormap_t *colormap = gl_frontsector->extra_colormap;
+
+	if (gl_frontsector->numlights)
+	{
+		if (!(blendmode & PF_Masked))
+			HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_TRANSLUCENT, NULL, blendmode);
+		else
+			HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_CUTLEVEL, NULL, blendmode);
+	}
+	else if (!(blendmode & PF_Masked))
+		HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, blendmode, false, lightnum, colormap);
+	else
+		HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
+}
+
+// Sort of like GLWall::Process in GZDoom
+static void HWR_ProcessSeg(void)
 {
 	FOutVector wallVerts[4];
 	v2d_t vs, ve; // start, end vertices of 2d line (view from above)
@@ -1118,9 +1164,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 	wallVerts[2].z = wallVerts[1].z = ve.y;
 
 	// x offset the texture
-	fixed_t texturehpeg = gl_sidedef->textureoffset + gl_curline->offset;
-	float cliplow = (float)texturehpeg;
-	float cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT));
+	float cliplow = (float)gl_curline->offset;
+	float cliphigh = cliplow + (gl_curline->flength * FRACUNIT);
 
 	FUINT lightnum = gl_frontsector->lightlevel;
 	extracolormap_t *colormap = gl_frontsector->extra_colormap;
@@ -1136,6 +1181,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 	if (gl_backsector)
 	{
 		INT32 gl_toptexture = 0, gl_bottomtexture = 0;
+
 		fixed_t texturevpeg;
 
 		SLOPEPARAMS(gl_backsector->c_slope, worldhigh, worldhighslope, gl_backsector->ceilingheight)
@@ -1165,30 +1211,46 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 		if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gl_toptexture)
 		{
 			grTex = HWR_GetTexture(gl_toptexture);
-			xscale = FixedToFloat(gl_sidedef->scalex_top);
-			yscale = FixedToFloat(gl_sidedef->scaley_top);
+			xscale = FixedToFloat(abs(gl_sidedef->scalex_top));
+			yscale = FixedToFloat(abs(gl_sidedef->scaley_top));
+
+			fixed_t offsetx_top = gl_sidedef->textureoffset + gl_sidedef->offsetx_top;
 
-			fixed_t texheight = FixedDiv(textureheight[gl_toptexture], gl_sidedef->scaley_top);
+			float left = cliplow * xscale;
+			float right = cliphigh * xscale;
+			if (gl_sidedef->scalex_top < 0)
+			{
+				left = -left;
+				right = -right;
+				offsetx_top = -offsetx_top;
+			}
+
+			fixed_t texheight = textureheight[gl_toptexture];
+			fixed_t texheightscaled = FixedDiv(texheight, abs(gl_sidedef->scaley_top));
 
 			// PEGGING
+			// FIXME: This is probably not correct?
 			if (gl_linedef->flags & ML_DONTPEGTOP)
 				texturevpeg = 0;
 			else if (gl_linedef->flags & ML_SKEWTD)
 				texturevpeg = worldhigh + texheight - worldtop;
 			else
-				texturevpeg = gl_backsector->ceilingheight + texheight - gl_frontsector->ceilingheight;
+				texturevpeg = gl_backsector->ceilingheight + texheightscaled - gl_frontsector->ceilingheight;
 
 			texturevpeg *= yscale;
 
-			texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top;
+			if (gl_sidedef->scaley_top < 0)
+				texturevpeg -= gl_sidedef->rowoffset + gl_sidedef->offsety_top;
+			else
+				texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top;
 
 			// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
-			texturevpeg %= texheight;
+			texturevpeg %= texheightscaled;
 
 			wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
 			wallVerts[0].t = wallVerts[1].t = (texturevpeg + (gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * yscale) * grTex->scaleY;
-			wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_top) * grTex->scaleX;
-			wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_top) * grTex->scaleX;
+			wallVerts[0].s = wallVerts[3].s = (left + offsetx_top) * grTex->scaleX;
+			wallVerts[2].s = wallVerts[1].s = (right + offsetx_top) * grTex->scaleX;
 
 			// Adjust t value for sloped walls
 			if (!(gl_linedef->flags & ML_SKEWTD))
@@ -1213,6 +1275,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				wallVerts[2].t = wallVerts[1].t - (worldtopslope - worldhighslope) * yscale * grTex->scaleY;
 			}
 
+			if (gl_sidedef->scaley_top < 0)
+			{
+				wallVerts[0].t = -wallVerts[0].t;
+				wallVerts[1].t = -wallVerts[1].t;
+				wallVerts[2].t = -wallVerts[2].t;
+				wallVerts[3].t = -wallVerts[3].t;
+			}
+
 			// set top/bottom coords
 			wallVerts[3].y = FIXED_TO_FLOAT(worldtop);
 			wallVerts[0].y = FIXED_TO_FLOAT(worldhigh);
@@ -1231,8 +1301,19 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 		if ((worldlowslope > worldbottomslope || worldlow > worldbottom) && gl_bottomtexture)
 		{
 			grTex = HWR_GetTexture(gl_bottomtexture);
-			xscale = FixedToFloat(gl_sidedef->scalex_bottom);
-			yscale = FixedToFloat(gl_sidedef->scaley_bottom);
+			xscale = FixedToFloat(abs(gl_sidedef->scalex_bottom));
+			yscale = FixedToFloat(abs(gl_sidedef->scaley_bottom));
+
+			fixed_t offsetx_bottom = gl_sidedef->textureoffset + gl_sidedef->offsetx_bottom;
+
+			float left = cliplow * xscale;
+			float right = cliphigh * xscale;
+			if (gl_sidedef->scalex_bottom < 0)
+			{
+				left = -left;
+				right = -right;
+				offsetx_bottom = -offsetx_bottom;
+			}
 
 			// PEGGING
 			if (!(gl_linedef->flags & ML_DONTPEGBOTTOM))
@@ -1244,15 +1325,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 
 			texturevpeg *= yscale;
 
-			texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bottom;
+			if (gl_sidedef->scaley_bottom < 0)
+				texturevpeg -= gl_sidedef->rowoffset + gl_sidedef->offsety_bottom;
+			else
+				texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bottom;
 
 			// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
-			texturevpeg %= FixedDiv(textureheight[gl_bottomtexture], gl_sidedef->scaley_bottom);
+			texturevpeg %= FixedDiv(textureheight[gl_bottomtexture], abs(gl_sidedef->scaley_bottom));
 
 			wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
 			wallVerts[0].t = wallVerts[1].t = (texturevpeg + (gl_backsector->floorheight - gl_frontsector->floorheight) * yscale) * grTex->scaleY;
-			wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_bottom) * grTex->scaleX;
-			wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_bottom) * grTex->scaleX;
+			wallVerts[0].s = wallVerts[3].s = (left + offsetx_bottom) * grTex->scaleX;
+			wallVerts[2].s = wallVerts[1].s = (right + offsetx_bottom) * grTex->scaleX;
 
 			// Adjust t value for sloped walls
 			if (!(gl_linedef->flags & ML_SKEWTD))
@@ -1276,6 +1360,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				wallVerts[1].t = (texturevpeg + (worldlowslope - worldbottomslope) * yscale) * grTex->scaleY;
 			}
 
+			if (gl_sidedef->scaley_bottom < 0)
+			{
+				wallVerts[0].t = -wallVerts[0].t;
+				wallVerts[1].t = -wallVerts[1].t;
+				wallVerts[2].t = -wallVerts[2].t;
+				wallVerts[3].t = -wallVerts[3].t;
+			}
+
 			// set top/bottom coords
 			wallVerts[3].y = FIXED_TO_FLOAT(worldlow);
 			wallVerts[0].y = FIXED_TO_FLOAT(worldbottom);
@@ -1290,196 +1382,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
 		}
 
-		// Render midtexture if there's one. Determine if it's visible first, though
-		if (gl_midtexture && HWR_BlendMidtextureSurface(&Surf))
-		{
-			sector_t *front, *back;
-			fixed_t texheight = FixedDiv(textureheight[gl_midtexture], gl_sidedef->scaley_mid);
-			INT32 repeats;
-
-			if (gl_linedef->frontsector->heightsec != -1)
-				front = &sectors[gl_linedef->frontsector->heightsec];
-			else
-				front = gl_linedef->frontsector;
-
-			if (gl_linedef->backsector->heightsec != -1)
-				back = &sectors[gl_linedef->backsector->heightsec];
-			else
-				back = gl_linedef->backsector;
-
-			if (gl_sidedef->repeatcnt)
-				repeats = 1 + gl_sidedef->repeatcnt;
-			else if (gl_linedef->flags & ML_WRAPMIDTEX)
-			{
-				fixed_t high, low;
-
-				if (front->ceilingheight > back->ceilingheight)
-					high = back->ceilingheight;
-				else
-					high = front->ceilingheight;
-
-				if (front->floorheight > back->floorheight)
-					low = front->floorheight;
-				else
-					low = back->floorheight;
-
-				repeats = (high - low) / texheight;
-				if ((high - low) % texheight)
-					repeats++; // tile an extra time to fill the gap -- Monster Iestyn
-			}
-			else
-				repeats = 1;
-
-			grTex = HWR_GetTexture(gl_midtexture);
-			xscale = FixedToFloat(gl_sidedef->scalex_mid);
-			yscale = FixedToFloat(gl_sidedef->scaley_mid);
-
-			// SoM: a little note: popentop and popenbottom
-			// record the limits the texture can be displayed in.
-			// polytop and polybottom, are the ideal (i.e. unclipped)
-			// heights of the polygon, and h & l, are the final (clipped)
-			// poly coords.
-			fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut;
-			fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope;
-
-			// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
-			// you must use the linedef's backsector to be correct
-			// From CB
-			if (gl_curline->polyseg)
-			{
-				popentop = popentopslope = back->ceilingheight;
-				popenbottom = popenbottomslope = back->floorheight;
-			}
-			else
-			{
-				popentop = min(worldtop, worldhigh);
-				popenbottom = max(worldbottom, worldlow);
-				popentopslope = min(worldtopslope, worldhighslope);
-				popenbottomslope = max(worldbottomslope, worldlowslope);
-			}
-
-			// Find the wall's coordinates
-			fixed_t midtexheight = texheight * repeats;
-
-			fixed_t rowoffset = FixedDiv(gl_sidedef->rowoffset + gl_sidedef->offsety_mid, gl_sidedef->scaley_mid);
-
-			// Texture is not skewed
-			if (gl_linedef->flags & ML_NOSKEW)
-			{
-				// Peg it to the floor
-				if (gl_linedef->flags & ML_MIDPEG)
-				{
-					polybottom = max(front->floorheight, back->floorheight) + rowoffset;
-					polytop = polybottom + midtexheight;
-				}
-				// Peg it to the ceiling
-				else
-				{
-					polytop = min(front->ceilingheight, back->ceilingheight) + rowoffset;
-					polybottom = polytop - midtexheight;
-				}
-
-				// The right side's coordinates are the the same as the left side
-				polytopslope = polytop;
-				polybottomslope = polybottom;
-			}
-			// Skew the texture, but peg it to the floor
-			else if (gl_linedef->flags & ML_MIDPEG)
-			{
-				polybottom = popenbottom + rowoffset;
-				polytop = polybottom + midtexheight;
-				polybottomslope = popenbottomslope + rowoffset;
-				polytopslope = polybottomslope + midtexheight;
-			}
-			// Skew it according to the ceiling's slope
-			else
-			{
-				polytop = popentop + rowoffset;
-				polybottom = polytop - midtexheight;
-				polytopslope = popentopslope + rowoffset;
-				polybottomslope = polytopslope - midtexheight;
-			}
-
-			// CB
-			// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
-			// you must use the linedef's backsector to be correct
-			if (gl_curline->polyseg)
-			{
-				lowcut = polybottom;
-				highcut = polytop;
-				lowcutslope = polybottomslope;
-				highcutslope = polytopslope;
-			}
-			else
-			{
-				// The cut-off values of a linedef can always be constant, since every line has an absoulute front and or back sector
-				lowcut = popenbottom;
-				highcut = popentop;
-				lowcutslope = popenbottomslope;
-				highcutslope = popentopslope;
-			}
-
-			h = min(highcut, polytop);
-			l = max(polybottom, lowcut);
-			hS = min(highcutslope, polytopslope);
-			lS = max(polybottomslope, lowcutslope);
-
-			// PEGGING
-			fixed_t texturevpegslope;
-
-			if (gl_linedef->flags & ML_MIDPEG)
-			{
-				texturevpeg = midtexheight - h + polybottom;
-				texturevpegslope = midtexheight - hS + polybottomslope;
-			}
-			else
-			{
-				texturevpeg = polytop - h;
-				texturevpegslope = polytopslope - hS;
-			}
-
-			// Left side
-			wallVerts[3].t = texturevpeg * yscale * grTex->scaleY;
-			wallVerts[0].t = (h - l + texturevpeg) * yscale * grTex->scaleY;
-			wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
-
-			// Right side
-			wallVerts[2].t = texturevpegslope * yscale * grTex->scaleY;
-			wallVerts[1].t = (hS - lS + texturevpegslope) * yscale * grTex->scaleY;
-			wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
-
-			// set top/bottom coords
-			// Take the texture peg into account, rather than changing the offsets past
-			// where the polygon might not be.
-			wallVerts[3].y = FIXED_TO_FLOAT(h);
-			wallVerts[0].y = FIXED_TO_FLOAT(l);
-			wallVerts[2].y = FIXED_TO_FLOAT(hS);
-			wallVerts[1].y = FIXED_TO_FLOAT(lS);
-
-			// TODO: Actually use the surface's flags so that I don't have to do this
-			FUINT blendmode = Surf.PolyFlags;
-
-			// Render midtextures on two-sided lines with a z-buffer offset.
-			// This will cause the midtexture appear on top, if a FOF overlaps with it.
-			blendmode |= PF_Decal;
-
-			if (gl_frontsector->numlights)
-			{
-				if (!(blendmode & PF_Masked))
-					HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_TRANSLUCENT, NULL, blendmode);
-				else
-					HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FOF_CUTLEVEL, NULL, blendmode);
-			}
-			else if (!(blendmode & PF_Masked))
-				HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, blendmode, false, lightnum, colormap);
-			else
-				HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, colormap);
-		}
+		// Render midtexture if there's one
+		if (gl_midtexture)
+			HWR_RenderMidtexture(gl_midtexture, cliplow, cliphigh, worldtop, worldbottom, worldhigh, worldlow, worldtopslope, worldbottomslope, worldhighslope, worldlowslope, lightnum, wallVerts);
 
-		// Sky culling
-		// No longer so much a mess as before!
 		if (!gl_curline->polyseg) // Don't do it for polyobjects
 		{
+			// Sky culling
+			// No longer so much a mess as before!
 			if (gl_frontsector->ceilingpic == skyflatnum
 				&& gl_backsector->ceilingpic != skyflatnum) // don't cull if back sector is also sky
 			{
@@ -1523,8 +1433,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 
 			wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
 			wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
-			wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
-			wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->offsetx_mid) * grTex->scaleX;
+			wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
+			wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + gl_sidedef->textureoffset + gl_sidedef->offsetx_mid) * grTex->scaleX;
 
 			// Texture correction for slopes
 			if (gl_linedef->flags & ML_NOSKEW) {
@@ -1587,8 +1497,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 		// Used for height comparisons and etc across FOFs and slopes
 		fixed_t high1, highslope1, low1, lowslope1;
 
+		fixed_t texturehpeg = gl_sidedef->textureoffset + gl_sidedef->offsetx_mid;
+
 		INT32 texnum;
-		line_t * newline = NULL; // Multi-Property FOF
 
 		lowcut = max(worldbottom, worldlow);
 		highcut = min(worldtop, worldhigh);
@@ -1622,16 +1533,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
 					continue;
 
-				side_t *side = &sides[rover->master->sidenum[0]];
+				side_t *side = R_GetFFloorSide(gl_curline, rover);
 
 				boolean do_texture_skew;
 				boolean dont_peg_bottom;
 
 				if (rover->master->flags & ML_TFERLINE)
 				{
-					size_t linenum = gl_curline->linedef-gl_backsector->lines[0];
-					newline = rover->master->frontsector->lines[0] + linenum;
-					side = &sides[newline->sidenum[0]];
+					line_t *newline = R_GetFFloorLine(gl_curline, rover);
 					do_texture_skew = newline->flags & ML_SKEWTD;
 					dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
 				}
@@ -1709,14 +1618,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 						}
 					}
 
-					wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + side->offsetx_mid) * grTex->scaleX;
-					wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + side->offsetx_mid) * grTex->scaleX;
+					wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
+					wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
 				}
 
+				FBITFIELD blendmode;
+
 				if (rover->fofflags & FOF_FOG)
 				{
-					FBITFIELD blendmode;
-
 					blendmode = PF_Fog|PF_NoTexture;
 
 					lightnum = rover->master->frontsector->lightlevel;
@@ -1732,7 +1641,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				}
 				else
 				{
-					FBITFIELD blendmode = PF_Masked;
+					blendmode = PF_Masked;
 
 					if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
 					{
@@ -1780,13 +1689,21 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
 					continue;
 
-				side_t *side = &sides[rover->master->sidenum[0]];
+				side_t *side = R_GetFFloorSide(gl_curline, rover);
+
+				boolean do_texture_skew;
+				boolean dont_peg_bottom;
 
 				if (rover->master->flags & ML_TFERLINE)
 				{
-					size_t linenum = gl_curline->linedef-gl_backsector->lines[0];
-					newline = rover->master->frontsector->lines[0] + linenum;
-					side = &sides[newline->sidenum[0]];
+					line_t *newline = R_GetFFloorLine(gl_curline, rover);
+					do_texture_skew = newline->flags & ML_SKEWTD;
+					dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
+				}
+				else
+				{
+					do_texture_skew = rover->master->flags & ML_SKEWTD;
+					dont_peg_bottom = gl_curline->linedef->flags & ML_DONTPEGBOTTOM;
 				}
 
 				texnum = R_GetTextureNum(side->midtexture);
@@ -1823,23 +1740,49 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				}
 				else
 				{
+					// Wow, how was this missing from OpenGL for so long?
+					// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
+					// -- Monster Iestyn 26/06/18
+					fixed_t texturevpeg = side->rowoffset + side->offsety_mid;
+
 					grTex = HWR_GetTexture(texnum);
 					xscale = FixedToFloat(side->scalex_mid);
 					yscale = FixedToFloat(side->scaley_mid);
 
-					fixed_t diff = (*rover->topheight - h) * yscale;
+					if (!do_texture_skew) // no skewing
+					{
+						if (dont_peg_bottom)
+							texturevpeg -= (*rover->topheight - *rover->bottomheight) * yscale;
 
-					wallVerts[3].t = wallVerts[2].t = (diff + side->rowoffset + side->offsety_mid) * grTex->scaleY;
-					wallVerts[0].t = wallVerts[1].t = (((h - l) * yscale) + (diff + side->rowoffset + side->offsety_mid)) * grTex->scaleY;
+						wallVerts[3].t = (((*rover->topheight - h) * yscale) + texturevpeg) * grTex->scaleY;
+						wallVerts[2].t = (((*rover->topheight - hS) * yscale) + texturevpeg) * grTex->scaleY;
+						wallVerts[0].t = (((*rover->topheight - l) * yscale) + texturevpeg) * grTex->scaleY;
+						wallVerts[1].t = (((*rover->topheight - lS) * yscale) + texturevpeg) * grTex->scaleY;
+					}
+					else
+					{
+						if (!dont_peg_bottom) // skew by top
+						{
+							wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
+							wallVerts[0].t = (((h - l) * yscale) + texturevpeg) * grTex->scaleY;
+							wallVerts[1].t = (((hS - lS) * yscale) + texturevpeg) * grTex->scaleY;
+						}
+						else // skew by bottom
+						{
+							wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
+							wallVerts[3].t = wallVerts[0].t - ((h - l) * yscale) * grTex->scaleY;
+							wallVerts[2].t = wallVerts[1].t - ((hS - lS) * yscale) * grTex->scaleY;
+						}
+					}
 
-					wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + side->offsetx_mid) * grTex->scaleX;
-					wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + side->offsetx_mid) * grTex->scaleX;
+					wallVerts[0].s = wallVerts[3].s = ((cliplow * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
+					wallVerts[2].s = wallVerts[1].s = ((cliphigh * xscale) + texturehpeg + side->offsetx_mid) * grTex->scaleX;
 				}
 
+				FBITFIELD blendmode;
+
 				if (rover->fofflags & FOF_FOG)
 				{
-					FBITFIELD blendmode;
-
 					blendmode = PF_Fog|PF_NoTexture;
 
 					lightnum = rover->master->frontsector->lightlevel;
@@ -1855,7 +1798,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 				}
 				else
 				{
-					FBITFIELD blendmode = PF_Masked;
+					blendmode = PF_Masked;
 
 					if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
 					{
@@ -1884,8 +1827,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
 //
 // e6y: Check whether the player can look beyond this line
 //
-#ifdef NEWCLIP
-boolean checkforemptylines = true;
+static boolean checkforemptylines = true;
+
 // Don't modify anything here, just check
 // Kalaron: Modified for sloped linedefs
 static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacksector)
@@ -1977,295 +1920,6 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks
 
 	return false;
 }
-#else
-//Hurdler: just like in r_bsp.c
-#if 1
-#define MAXSEGS         MAXVIDWIDTH/2+1
-#else
-//Alam_GBC: Or not (may cause overflow)
-#define MAXSEGS         128
-#endif
-
-// hw_newend is one past the last valid seg
-static cliprange_t *   hw_newend;
-static cliprange_t     gl_solidsegs[MAXSEGS];
-
-// needs fix: walls are incorrectly clipped one column less
-static consvar_t cv_glclipwalls = CVAR_INIT ("gr_clipwalls", "Off", 0, CV_OnOff, NULL);
-
-static void printsolidsegs(void)
-{
-	cliprange_t *       start;
-	if (!hw_newend)
-		return;
-	for (start = gl_solidsegs;start != hw_newend;start++)
-	{
-		CONS_Debug(DBG_RENDER, "%d-%d|",start->first,start->last);
-	}
-	CONS_Debug(DBG_RENDER, "\n\n");
-}
-
-//
-//
-//
-static void HWR_ClipSolidWallSegment(INT32 first, INT32 last)
-{
-	cliprange_t *next, *start;
-	float lowfrac, highfrac;
-	boolean poorhack = false;
-
-	// Find the first range that touches the range
-	//  (adjacent pixels are touching).
-	start = gl_solidsegs;
-	while (start->last < first-1)
-		start++;
-
-	if (first < start->first)
-	{
-		if (last < start->first-1)
-		{
-			// Post is entirely visible (above start),
-			//  so insert a new clippost.
-			HWR_StoreWallRange(first, last);
-
-			next = hw_newend;
-			hw_newend++;
-
-			while (next != start)
-			{
-				*next = *(next-1);
-				next--;
-			}
-
-			next->first = first;
-			next->last = last;
-			printsolidsegs();
-			return;
-		}
-
-		// There is a fragment above *start.
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(first, last);
-			poorhack = true;
-		}
-		else
-		{
-			highfrac = HWR_ClipViewSegment(start->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
-			HWR_StoreWallRange(0, highfrac);
-		}
-		// Now adjust the clip size.
-		start->first = first;
-	}
-
-	// Bottom contained in start?
-	if (last <= start->last)
-	{
-		printsolidsegs();
-		return;
-	}
-	next = start;
-	while (last >= (next+1)->first-1)
-	{
-		// There is a fragment between two posts.
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(first,last);
-			poorhack = true;
-		}
-		else
-		{
-			lowfrac  = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
-			highfrac = HWR_ClipViewSegment((next+1)->first+1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
-			HWR_StoreWallRange(lowfrac, highfrac);
-		}
-		next++;
-
-		if (last <= next->last)
-		{
-			// Bottom is contained in next.
-			// Adjust the clip size.
-			start->last = next->last;
-			goto crunch;
-		}
-	}
-
-	if (first == next->first+1) // 1 line texture
-	{
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(first,last);
-			poorhack = true;
-		}
-		else
-			HWR_StoreWallRange(0, 1);
-	}
-	else
-	{
-	// There is a fragment after *next.
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(first,last);
-			poorhack = true;
-		}
-		else
-		{
-			lowfrac  = HWR_ClipViewSegment(next->last-1, (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
-			HWR_StoreWallRange(lowfrac, 1);
-		}
-	}
-
-	// Adjust the clip size.
-	start->last = last;
-
-	// Remove start+1 to next from the clip list,
-	// because start now covers their area.
-crunch:
-	if (next == start)
-	{
-		printsolidsegs();
-		// Post just extended past the bottom of one post.
-		return;
-	}
-
-
-	while (next++ != hw_newend)
-	{
-		// Remove a post.
-		*++start = *next;
-	}
-
-	hw_newend = start;
-	printsolidsegs();
-}
-
-//
-//  handle LineDefs with upper and lower texture (windows)
-//
-static void HWR_ClipPassWallSegment(INT32 first, INT32 last)
-{
-	cliprange_t *start;
-	float lowfrac, highfrac;
-	//to allow noclipwalls but still solidseg reject of non-visible walls
-	boolean poorhack = false;
-
-	// Find the first range that touches the range
-	//  (adjacent pixels are touching).
-	start = gl_solidsegs;
-	while (start->last < first - 1)
-		start++;
-
-	if (first < start->first)
-	{
-		if (last < start->first-1)
-		{
-			// Post is entirely visible (above start).
-			HWR_StoreWallRange(0, 1);
-			return;
-		}
-
-		// There is a fragment above *start.
-		if (!cv_glclipwalls.value)
-		{	//20/08/99: Changed by Hurdler (taken from faB's code)
-			if (!poorhack) HWR_StoreWallRange(0, 1);
-			poorhack = true;
-		}
-		else
-		{
-			highfrac = HWR_ClipViewSegment(min(start->first + 1,
-				start->last), (polyvertex_t *)gl_curline->pv1,
-				(polyvertex_t *)gl_curline->pv2);
-			HWR_StoreWallRange(0, highfrac);
-		}
-	}
-
-	// Bottom contained in start?
-	if (last <= start->last)
-		return;
-
-	while (last >= (start+1)->first-1)
-	{
-		// There is a fragment between two posts.
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(0, 1);
-			poorhack = true;
-		}
-		else
-		{
-			lowfrac  = HWR_ClipViewSegment(max(start->last-1,start->first), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
-			highfrac = HWR_ClipViewSegment(min((start+1)->first+1,(start+1)->last), (polyvertex_t *)gl_curline->pv1, (polyvertex_t *)gl_curline->pv2);
-			HWR_StoreWallRange(lowfrac, highfrac);
-		}
-		start++;
-
-		if (last <= start->last)
-			return;
-	}
-
-	if (first == start->first+1) // 1 line texture
-	{
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(0, 1);
-			poorhack = true;
-		}
-		else
-			HWR_StoreWallRange(0, 1);
-	}
-	else
-	{
-		// There is a fragment after *next.
-		if (!cv_glclipwalls.value)
-		{
-			if (!poorhack) HWR_StoreWallRange(0,1);
-			poorhack = true;
-		}
-		else
-		{
-			lowfrac = HWR_ClipViewSegment(max(start->last - 1,
-				start->first), (polyvertex_t *)gl_curline->pv1,
-				(polyvertex_t *)gl_curline->pv2);
-			HWR_StoreWallRange(lowfrac, 1);
-		}
-	}
-}
-
-// --------------------------------------------------------------------------
-//  HWR_ClipToSolidSegs check if it is hide by wall (solidsegs)
-// --------------------------------------------------------------------------
-static boolean HWR_ClipToSolidSegs(INT32 first, INT32 last)
-{
-	cliprange_t * start;
-
-	// Find the first range that touches the range
-	//  (adjacent pixels are touching).
-	start = gl_solidsegs;
-	while (start->last < first-1)
-		start++;
-
-	if (first < start->first)
-		return true;
-
-	// Bottom contained in start?
-	if (last <= start->last)
-		return false;
-
-	return true;
-}
-
-//
-// HWR_ClearClipSegs
-//
-static void HWR_ClearClipSegs(void)
-{
-	gl_solidsegs[0].first = -0x7fffffff;
-	gl_solidsegs[0].last = -1;
-	gl_solidsegs[1].first = vid.width; //viewwidth;
-	gl_solidsegs[1].last = 0x7fffffff;
-	hw_newend = gl_solidsegs+2;
-}
-#endif // NEWCLIP
 
 // -----------------+
 // HWR_AddLine      : Clips the given segment and adds any visible pieces to the line list.
@@ -2275,11 +1929,6 @@ static void HWR_ClearClipSegs(void)
 static void HWR_AddLine(seg_t * line)
 {
 	angle_t angle1, angle2;
-#ifndef NEWCLIP
-	INT32 x1, x2;
-	angle_t span, tspan;
-	boolean bothceilingssky = false, bothfloorssky = false;
-#endif
 
 	// SoM: Backsector needs to be run through R_FakeFlat
 	static sector_t tempsec;
@@ -2315,104 +1964,22 @@ static void HWR_AddLine(seg_t * line)
 	angle1 = R_PointToAngle64(v1x, v1y);
 	angle2 = R_PointToAngle64(v2x, v2y);
 
-#ifdef NEWCLIP
-	 // PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle!
+	// PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle!
 	if (angle2 - angle1 < ANGLE_180)
-		return;
-
-	// PrBoom: use REAL clipping math YAYYYYYYY!!!
-
-	if (!gld_clipper_SafeCheckRange(angle2, angle1))
-    {
-		return;
-    }
-
-	checkforemptylines = true;
-#else
-	// Clip to view edges.
-	span = angle1 - angle2;
-
-	// backface culling : span is < ANGLE_180 if ang1 > ang2 : the seg is facing
-	if (span >= ANGLE_180)
-		return;
-
-	// Global angle needed by segcalc.
-	//rw_angle1 = angle1;
-	angle1 -= dup_viewangle;
-	angle2 -= dup_viewangle;
-
-	tspan = angle1 + gl_clipangle;
-	if (tspan > 2*gl_clipangle)
-	{
-		tspan -= 2*gl_clipangle;
-
-		// Totally off the left edge?
-		if (tspan >= span)
-			return;
-
-		angle1 = gl_clipangle;
-	}
-	tspan = gl_clipangle - angle2;
-	if (tspan > 2*gl_clipangle)
-	{
-		tspan -= 2*gl_clipangle;
-
-		// Totally off the left edge?
-		if (tspan >= span)
-			return;
-
-		angle2 = (angle_t)-(signed)gl_clipangle;
-	}
-
-#if 0
-	{
-		float fx1,fx2,fy1,fy2;
-		//BP: test with a better projection than viewangletox[R_PointToAngle(angle)]
-		// do not enable this at release 4 mul and 2 div
-		fx1 = ((polyvertex_t *)(line->pv1))->x-gl_viewx;
-		fy1 = ((polyvertex_t *)(line->pv1))->y-gl_viewy;
-		fy2 = (fx1 * gl_viewcos + fy1 * gl_viewsin);
-		if (fy2 < 0)
-			// the point is back
-			fx1 = 0;
-		else
-			fx1 = gl_windowcenterx + (fx1 * gl_viewsin - fy1 * gl_viewcos) * gl_centerx / fy2;
-
-		fx2 = ((polyvertex_t *)(line->pv2))->x-gl_viewx;
-		fy2 = ((polyvertex_t *)(line->pv2))->y-gl_viewy;
-		fy1 = (fx2 * gl_viewcos + fy2 * gl_viewsin);
-		if (fy1 < 0)
-			// the point is back
-			fx2 = vid.width;
-		else
-			fx2 = gl_windowcenterx + (fx2 * gl_viewsin - fy2 * gl_viewcos) * gl_centerx / fy1;
+		return;
 
-		x1 = fx1+0.5f;
-		x2 = fx2+0.5f;
-	}
-#else
-	// The seg is in the view range,
-	// but not necessarily visible.
-	angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
-	angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
+	// PrBoom: use REAL clipping math YAYYYYYYY!!!
 
-	x1 = gl_viewangletox[angle1];
-	x2 = gl_viewangletox[angle2];
-#endif
-	// Does not cross a pixel?
-//	if (x1 == x2)
-/*	{
-		// BP: HERE IS THE MAIN PROBLEM !
-		//CONS_Debug(DBG_RENDER, "tineline\n");
+	if (!gld_clipper_SafeCheckRange(angle2, angle1))
+    {
 		return;
-	}
-*/
-#endif
+    }
+
+	checkforemptylines = true;
 
 	gl_backsector = line->backsector;
 	bothceilingssky = bothfloorssky = false;
 
-#ifdef NEWCLIP
 	if (!line->backsector)
     {
 		gld_clipper_SafeAddClipRange(angle2, angle1);
@@ -2455,115 +2022,6 @@ static void HWR_AddLine(seg_t * line)
     }
 
 	HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
-	return;
-#else
-	// Single sided line?
-	if (!gl_backsector)
-		goto clipsolid;
-
-	gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
-
-	if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum)
-		bothceilingssky = true;
-	if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum)
-		bothfloorssky = true;
-
-	if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
-	{
-		if (!line->polyseg &&
-			!line->sidedef->midtexture
-			&& ((!gl_frontsector->ffloors && !gl_backsector->ffloors)
-				|| Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags)))
-			return; // line is empty, don't even bother
-
-		goto clippass; // treat like wide open window instead
-	}
-
-	if (gl_frontsector->f_slope || gl_frontsector->c_slope || gl_backsector->f_slope || gl_backsector->c_slope)
-	{
-		fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends
-		fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends
-
-#define SLOPEPARAMS(slope, end1, end2, normalheight) \
-		end1 = P_GetZAt(slope, v1x, v1y, normalheight); \
-		end2 = P_GetZAt(slope, v2x, v2y, normalheight);
-
-		SLOPEPARAMS(gl_frontsector->f_slope, frontf1, frontf2, gl_frontsector->  floorheight)
-		SLOPEPARAMS(gl_frontsector->c_slope, frontc1, frontc2, gl_frontsector->ceilingheight)
-		SLOPEPARAMS( gl_backsector->f_slope,  backf1,  backf2,  gl_backsector->  floorheight)
-		SLOPEPARAMS( gl_backsector->c_slope,  backc1,  backc2,  gl_backsector->ceilingheight)
-#undef SLOPEPARAMS
-		// if both ceilings are skies, consider it always "open"
-		// same for floors
-		if (!bothceilingssky && !bothfloorssky)
-		{
-			// Closed door.
-			if ((backc1 <= frontf1 && backc2 <= frontf2)
-				|| (backf1 >= frontc1 && backf2 >= frontc2))
-			{
-				goto clipsolid;
-			}
-
-			// Check for automap fix.
-			if (backc1 <= backf1 && backc2 <= backf2
-			&& ((backc1 >= frontc1 && backc2 >= frontc2) || gl_curline->sidedef->toptexture)
-			&& ((backf1 <= frontf1 && backf2 >= frontf2) || gl_curline->sidedef->bottomtexture))
-				goto clipsolid;
-		}
-
-		// Window.
-		if (!bothceilingssky) // ceilings are always the "same" when sky
-			if (backc1 != frontc1 || backc2 != frontc2)
-				goto clippass;
-		if (!bothfloorssky)	// floors are always the "same" when sky
-			if (backf1 != frontf1 || backf2 != frontf2)
-				goto clippass;
-	}
-	else
-	{
-		// if both ceilings are skies, consider it always "open"
-		// same for floors
-		if (!bothceilingssky && !bothfloorssky)
-		{
-			// Closed door.
-			if (gl_backsector->ceilingheight <= gl_frontsector->floorheight ||
-				gl_backsector->floorheight >= gl_frontsector->ceilingheight)
-				goto clipsolid;
-
-			// Check for automap fix.
-			if (gl_backsector->ceilingheight <= gl_backsector->floorheight
-			&& ((gl_backsector->ceilingheight >= gl_frontsector->ceilingheight) || gl_curline->sidedef->toptexture)
-			&& ((gl_backsector->floorheight <= gl_backsector->floorheight) || gl_curline->sidedef->bottomtexture))
-				goto clipsolid;
-		}
-
-		// Window.
-		if (!bothceilingssky) // ceilings are always the "same" when sky
-			if (gl_backsector->ceilingheight != gl_frontsector->ceilingheight)
-				goto clippass;
-		if (!bothfloorssky)	// floors are always the "same" when sky
-			if (gl_backsector->floorheight != gl_frontsector->floorheight)
-				goto clippass;
-	}
-
-	// Reject empty lines used for triggers and special events.
-	// Identical floor and ceiling on both sides,
-	//  identical light levels on both sides,
-	//  and no middle texture.
-	if (R_IsEmptyLine(gl_curline, gl_frontsector, gl_backsector))
-		return;
-
-clippass:
-	if (x1 == x2)
-		{  x2++;x1 -= 2; }
-	HWR_ClipPassWallSegment(x1, x2-1);
-	return;
-
-clipsolid:
-	if (x1 == x2)
-		goto clippass;
-	HWR_ClipSolidWallSegment(x1, x2-1);
-#endif
 }
 
 // HWR_CheckBBox
@@ -2578,23 +2036,19 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
 	INT32 boxpos;
 	fixed_t px1, py1, px2, py2;
 	angle_t angle1, angle2;
-#ifndef NEWCLIP
-	INT32 sx1, sx2;
-	angle_t span, tspan;
-#endif
 
 	// Find the corners of the box
 	// that define the edges from current viewpoint.
-	if (dup_viewx <= bspcoord[BOXLEFT])
+	if (viewx <= bspcoord[BOXLEFT])
 		boxpos = 0;
-	else if (dup_viewx < bspcoord[BOXRIGHT])
+	else if (viewx < bspcoord[BOXRIGHT])
 		boxpos = 1;
 	else
 		boxpos = 2;
 
-	if (dup_viewy >= bspcoord[BOXTOP])
+	if (viewy >= bspcoord[BOXTOP])
 		boxpos |= 0;
-	else if (dup_viewy > bspcoord[BOXBOTTOM])
+	else if (viewy > bspcoord[BOXBOTTOM])
 		boxpos |= 1<<2;
 	else
 		boxpos |= 2<<2;
@@ -2607,59 +2061,9 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
 	px2 = bspcoord[checkcoord[boxpos][2]];
 	py2 = bspcoord[checkcoord[boxpos][3]];
 
-#ifdef NEWCLIP
 	angle1 = R_PointToAngle64(px1, py1);
 	angle2 = R_PointToAngle64(px2, py2);
 	return gld_clipper_SafeCheckRange(angle2, angle1);
-#else
-	// check clip list for an open space
-	angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle;
-	angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle;
-
-	span = angle1 - angle2;
-
-	// Sitting on a line?
-	if (span >= ANGLE_180)
-		return true;
-
-	tspan = angle1 + gl_clipangle;
-
-	if (tspan > 2*gl_clipangle)
-	{
-		tspan -= 2*gl_clipangle;
-
-		// Totally off the left edge?
-		if (tspan >= span)
-			return false;
-
-		angle1 = gl_clipangle;
-	}
-	tspan = gl_clipangle - angle2;
-	if (tspan > 2*gl_clipangle)
-	{
-		tspan -= 2*gl_clipangle;
-
-		// Totally off the left edge?
-		if (tspan >= span)
-			return false;
-
-		angle2 = (angle_t)-(signed)gl_clipangle;
-	}
-
-	// Find the first clippost
-	//  that touches the source post
-	//  (adjacent pixels are touching).
-	angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
-	angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
-	sx1 = gl_viewangletox[angle1];
-	sx2 = gl_viewangletox[angle2];
-
-	// Does not cross a pixel.
-	if (sx1 == sx2)
-		return false;
-
-	return HWR_ClipToSolidSegs(sx1, sx2 - 1);
-#endif
 }
 
 //
@@ -2672,36 +2076,14 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
 static inline void HWR_AddPolyObjectSegs(void)
 {
 	size_t i, j;
-	seg_t *gl_fakeline = Z_Calloc(sizeof(seg_t), PU_STATIC, NULL);
-	polyvertex_t *pv1 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
-	polyvertex_t *pv2 = Z_Calloc(sizeof(polyvertex_t), PU_STATIC, NULL);
 
 	// Sort through all the polyobjects
 	for (i = 0; i < numpolys; ++i)
 	{
 		// Render the polyobject's lines
 		for (j = 0; j < po_ptrs[i]->segCount; ++j)
-		{
-			// Copy the info of a polyobject's seg, then convert it to OpenGL floating point
-			M_Memcpy(gl_fakeline, po_ptrs[i]->segs[j], sizeof(seg_t));
-
-			// Now convert the line to float and add it to be rendered
-			pv1->x = FIXED_TO_FLOAT(gl_fakeline->v1->x);
-			pv1->y = FIXED_TO_FLOAT(gl_fakeline->v1->y);
-			pv2->x = FIXED_TO_FLOAT(gl_fakeline->v2->x);
-			pv2->y = FIXED_TO_FLOAT(gl_fakeline->v2->y);
-
-			gl_fakeline->pv1 = pv1;
-			gl_fakeline->pv2 = pv2;
-
-			HWR_AddLine(gl_fakeline);
-		}
+			HWR_AddLine(po_ptrs[i]->segs[j]);
 	}
-
-	// Free temporary data no longer needed
-	Z_Free(pv2);
-	Z_Free(pv1);
-	Z_Free(gl_fakeline);
 }
 
 static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
@@ -2726,13 +2108,8 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
 	static FOutVector *planeVerts = NULL;
 	static UINT16 numAllocedPlaneVerts = 0;
 
-	if (nrPlaneVerts < 3)   // Not even a triangle?
-		return;
-	else if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size
-	{
-		CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
+	if (!r_renderfloors || nrPlaneVerts < 3)   // Not even a triangle?
 		return;
-	}
 
 	// Allocate plane-vertex buffer if we need to
 	if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
@@ -2875,7 +2252,7 @@ static void HWR_AddPolyObjectPlanes(void)
 			}
 			else
 			{
-				HWR_GetLevelFlat(&levelflats[polyobjsector->floorpic]);
+				HWR_GetLevelFlat(&levelflats[polyobjsector->floorpic], false);
 				HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
 										(light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->floorpic],
 										polyobjsector, 255, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
@@ -2898,7 +2275,7 @@ static void HWR_AddPolyObjectPlanes(void)
 			}
 			else
 			{
-				HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic]);
+				HWR_GetLevelFlat(&levelflats[polyobjsector->ceilingpic], false);
 				HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
 				                          (light == -1 ? gl_frontsector->lightlevel : *gl_frontsector->lightlist[light].lightlevel), &levelflats[polyobjsector->ceilingpic],
 				                          polyobjsector, 255, (light == -1 ? gl_frontsector->extra_colormap : *gl_frontsector->lightlist[light].extra_colormap));
@@ -3021,15 +2398,14 @@ static void HWR_Subsector(size_t num)
 	sub->sector->extra_colormap = gl_frontsector->extra_colormap;
 
 	// render floor ?
-#ifdef DOPLANES
 	// yeah, easy backface cull! :)
-	if (cullFloorHeight < dup_viewz)
+	if (cullFloorHeight < viewz)
 	{
 		if (gl_frontsector->floorpic != skyflatnum)
 		{
 			if (sub->validcount != validcount)
 			{
-				HWR_GetLevelFlat(&levelflats[gl_frontsector->floorpic]);
+				HWR_GetLevelFlat(&levelflats[gl_frontsector->floorpic], false);
 				HWR_RenderPlane(sub, &extrasubsectors[num], false,
 					// Hack to make things continue to work around slopes.
 					locFloorHeight == cullFloorHeight ? locFloorHeight : gl_frontsector->floorheight,
@@ -3037,21 +2413,15 @@ static void HWR_Subsector(size_t num)
 					PF_Occlude, floorlightlevel, &levelflats[gl_frontsector->floorpic], NULL, 255, floorcolormap);
 			}
 		}
-		else
-		{
-#ifdef POLYSKY
-			HWR_RenderSkyPlane(&extrasubsectors[num], locFloorHeight);
-#endif
-		}
 	}
 
-	if (cullCeilingHeight > dup_viewz)
+	if (cullCeilingHeight > viewz)
 	{
 		if (gl_frontsector->ceilingpic != skyflatnum)
 		{
 			if (sub->validcount != validcount)
 			{
-				HWR_GetLevelFlat(&levelflats[gl_frontsector->ceilingpic]);
+				HWR_GetLevelFlat(&levelflats[gl_frontsector->ceilingpic], false);
 				HWR_RenderPlane(sub, &extrasubsectors[num], true,
 					// Hack to make things continue to work around slopes.
 					locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gl_frontsector->ceilingheight,
@@ -3059,21 +2429,12 @@ static void HWR_Subsector(size_t num)
 					PF_Occlude, ceilinglightlevel, &levelflats[gl_frontsector->ceilingpic], NULL, 255, ceilingcolormap);
 			}
 		}
-		else
-		{
-#ifdef POLYSKY
-			HWR_RenderSkyPlane(&extrasubsectors[num], locCeilingHeight);
-#endif
-		}
 	}
 
-#ifndef POLYSKY
 	// Moved here because before, when above the ceiling and the floor does not have the sky flat, it doesn't draw the sky
 	if (gl_frontsector->ceilingpic == skyflatnum || gl_frontsector->floorpic == skyflatnum)
 		drawsky = true;
-#endif
 
-#ifdef R_FAKEFLOORS
 	if (gl_frontsector->ffloors)
 	{
 		/// \todo fix light, xoffs, yoffs, extracolormap ?
@@ -3102,14 +2463,14 @@ static void HWR_Subsector(size_t num)
 
 			if (centerHeight <= locCeilingHeight &&
 			    centerHeight >= locFloorHeight &&
-			    ((dup_viewz < bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
-			     (dup_viewz > bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
+			    ((viewz < bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
+			     (viewz > bottomCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
 			{
 				if (rover->fofflags & FOF_FOG)
 				{
 					UINT8 alpha;
 
-					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false);
+					light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
 					alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
 
 					HWR_AddTransparentFloor(0,
@@ -3118,11 +2479,11 @@ static void HWR_Subsector(size_t num)
 					                       *rover->bottomheight,
 					                       *gl_frontsector->lightlist[light].lightlevel,
 					                       alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
-										   true, rover->master->frontsector->extra_colormap);
+										   true, false, rover->master->frontsector->extra_colormap);
 				}
 				else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) // SoM: Flags are more efficient
 				{
-					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false);
+					light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
 
 					HWR_AddTransparentFloor(&levelflats[*rover->bottompic],
 					                       &extrasubsectors[num],
@@ -3131,12 +2492,12 @@ static void HWR_Subsector(size_t num)
 					                       *gl_frontsector->lightlist[light].lightlevel,
 					                       max(0, min(rover->alpha, 255)), rover->master->frontsector,
 					                       HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
-					                       false, *gl_frontsector->lightlist[light].extra_colormap);
+					                       false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap);
 				}
 				else
 				{
-					HWR_GetLevelFlat(&levelflats[*rover->bottompic]);
-					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < bottomCullHeight ? true : false);
+					HWR_GetLevelFlat(&levelflats[*rover->bottompic], rover->fofflags & FOF_SPLAT);
+					light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
 					HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
 					                rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
 				}
@@ -3147,14 +2508,14 @@ static void HWR_Subsector(size_t num)
 
 			if (centerHeight >= locFloorHeight &&
 			    centerHeight <= locCeilingHeight &&
-			    ((dup_viewz > topCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
-			     (dup_viewz < topCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
+			    ((viewz > topCullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
+			     (viewz < topCullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
 			{
 				if (rover->fofflags & FOF_FOG)
 				{
 					UINT8 alpha;
 
-					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false);
+					light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
 					alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
 
 					HWR_AddTransparentFloor(0,
@@ -3163,11 +2524,11 @@ static void HWR_Subsector(size_t num)
 					                       *rover->topheight,
 					                       *gl_frontsector->lightlist[light].lightlevel,
 					                       alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
-										   true, rover->master->frontsector->extra_colormap);
+										   true, false, rover->master->frontsector->extra_colormap);
 				}
 				else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
 				{
-					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false);
+					light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
 
 					HWR_AddTransparentFloor(&levelflats[*rover->toppic],
 					                        &extrasubsectors[num],
@@ -3176,20 +2537,18 @@ static void HWR_Subsector(size_t num)
 					                        *gl_frontsector->lightlist[light].lightlevel,
 					                        max(0, min(rover->alpha, 255)), rover->master->frontsector,
 					                        HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
-					                        false, *gl_frontsector->lightlist[light].extra_colormap);
+					                        false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap);
 				}
 				else
 				{
-					HWR_GetLevelFlat(&levelflats[*rover->toppic]);
-					light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < topCullHeight ? true : false);
+					HWR_GetLevelFlat(&levelflats[*rover->toppic], rover->fofflags & FOF_SPLAT);
+					light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
 					HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
 					                  rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
 				}
 			}
 		}
 	}
-#endif
-#endif //doplanes
 
 	// Draw all the polyobjects in this subsector
 	if (sub->polyList)
@@ -3221,10 +2580,10 @@ static void HWR_Subsector(size_t num)
 		}
 	}
 
-// Hurder ici se passe les choses INT32�essantes!
-// on vient de tracer le sol et le plafond
-// on trace �pr�ent d'abord les sprites et ensuite les murs
-// hurdler: faux: on ajoute seulement les sprites, le murs sont trac� d'abord
+	// Hurdler: here interesting things are happening!
+	// we have just drawn the floor and ceiling
+	// we now draw the sprites first and then the walls
+	// hurdler: false: we only add the sprites, the walls are drawn first
 	if (line)
 	{
 		// draw sprites first, coz they are clipped to the solidsegs of
@@ -3256,59 +2615,11 @@ static void HWR_Subsector(size_t num)
 //  traversing subtree recursively.
 // Just call with BSP root.
 
-#ifdef coolhack
-//t;b;l;r
-static fixed_t hackbbox[4];
-//BOXTOP,
-//BOXBOTTOM,
-//BOXLEFT,
-//BOXRIGHT
-static boolean HWR_CheckHackBBox(fixed_t *bb)
-{
-	if (bb[BOXTOP] < hackbbox[BOXBOTTOM]) //y up
-		return false;
-	if (bb[BOXBOTTOM] > hackbbox[BOXTOP])
-		return false;
-	if (bb[BOXLEFT] > hackbbox[BOXRIGHT])
-		return false;
-	if (bb[BOXRIGHT] < hackbbox[BOXLEFT])
-		return false;
-	return true;
-}
-#endif
-
 // BP: big hack for a test in lighning ref : 1249753487AB
 fixed_t *hwbbox;
 
 static void HWR_RenderBSPNode(INT32 bspnum)
 {
-	/*//GZDoom code
-	if(bspnum == -1)
-	{
-		HWR_Subsector(subsectors);
-		return;
-	}
-	while(!((size_t)bspnum&(~NF_SUBSECTOR))) // Keep going until found a subsector
-	{
-		node_t *bsp = &nodes[bspnum];
-
-		// Decide which side the view point is on
-		INT32 side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
-
-		// Recursively divide front space (toward the viewer)
-		HWR_RenderBSPNode(bsp->children[side]);
-
-		// Possibly divide back space (away from viewer)
-		side ^= 1;
-
-		if (!HWR_CheckBBox(bsp->bbox[side]))
-			return;
-
-		bspnum = bsp->children[side];
-	}
-
-	HWR_Subsector(bspnum-1);
-*/
 	node_t *bsp = &nodes[bspnum];
 
 	// Decide which side the view point is on
@@ -3333,7 +2644,7 @@ static void HWR_RenderBSPNode(INT32 bspnum)
 	}
 
 	// Decide which side the view point is on.
-	side = R_PointOnSide(dup_viewx, dup_viewy, bsp);
+	side = R_PointOnSide(viewx, viewy, bsp);
 
 	// BP: big hack for a test in lighning ref : 1249753487AB
 	hwbbox = bsp->bbox[side];
@@ -3350,100 +2661,6 @@ static void HWR_RenderBSPNode(INT32 bspnum)
 	}
 }
 
-/*
-//
-// Clear 'stack' of subsectors to draw
-//
-static void HWR_ClearDrawSubsectors(void)
-{
-	gl_drawsubsector_p = gl_drawsubsectors;
-}
-
-//
-// Draw subsectors pushed on the drawsubsectors 'stack', back to front
-//
-static void HWR_RenderSubsectors(void)
-{
-	while (gl_drawsubsector_p > gl_drawsubsectors)
-	{
-		HWR_RenderBSPNode(
-		lastsubsec->nextsubsec = bspnum & (~NF_SUBSECTOR);
-	}
-}
-*/
-
-// ==========================================================================
-//                                                              FROM R_MAIN.C
-// ==========================================================================
-
-//BP : exactely the same as R_InitTextureMapping
-void HWR_InitTextureMapping(void)
-{
-	angle_t i;
-	INT32 x;
-	INT32 t;
-	fixed_t focallength;
-	fixed_t grcenterx;
-	fixed_t grcenterxfrac;
-	INT32 grviewwidth;
-
-#define clipanglefov (FIELDOFVIEW>>ANGLETOFINESHIFT)
-
-	grviewwidth = vid.width;
-	grcenterx = grviewwidth/2;
-	grcenterxfrac = grcenterx<<FRACBITS;
-
-	// Use tangent table to generate viewangletox:
-	//  viewangletox will give the next greatest x
-	//  after the view angle.
-	//
-	// Calc focallength
-	//  so FIELDOFVIEW angles covers SCREENWIDTH.
-	focallength = FixedDiv(grcenterxfrac,
-		FINETANGENT(FINEANGLES/4+clipanglefov/2));
-
-	for (i = 0; i < FINEANGLES/2; i++)
-	{
-		if (FINETANGENT(i) > FRACUNIT*2)
-			t = -1;
-		else if (FINETANGENT(i) < -FRACUNIT*2)
-			t = grviewwidth+1;
-		else
-		{
-			t = FixedMul(FINETANGENT(i), focallength);
-			t = (grcenterxfrac - t+FRACUNIT-1)>>FRACBITS;
-
-			if (t < -1)
-				t = -1;
-			else if (t > grviewwidth+1)
-				t = grviewwidth+1;
-		}
-		gl_viewangletox[i] = t;
-	}
-
-	// Scan viewangletox[] to generate xtoviewangle[]:
-	//  xtoviewangle will give the smallest view angle
-	//  that maps to x.
-	for (x = 0; x <= grviewwidth; x++)
-	{
-		i = 0;
-		while (gl_viewangletox[i]>x)
-			i++;
-		gl_xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90;
-	}
-
-	// Take out the fencepost cases from viewangletox.
-	for (i = 0; i < FINEANGLES/2; i++)
-	{
-		if (gl_viewangletox[i] == -1)
-			gl_viewangletox[i] = 0;
-		else if (gl_viewangletox[i] == grviewwidth+1)
-			gl_viewangletox[i]  = grviewwidth;
-	}
-
-	gl_clipangle = gl_xtoviewangle[0];
-}
-
 // ==========================================================================
 // gl_things.c
 // ==========================================================================
@@ -4392,7 +3609,6 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
 	}
 }
 
-#ifdef HWPRECIP
 // Sprite drawer for precipitation
 static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
 {
@@ -4493,7 +3709,6 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
 
 	HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false);
 }
-#endif
 
 // --------------------------------------------------------------------------
 // Sort vissprites by distance
@@ -4620,6 +3835,7 @@ typedef struct
 	sector_t *FOFSector;
 	FBITFIELD blend;
 	boolean fogplane;
+	boolean chromakeyed;
 	extracolormap_t *planecolormap;
 	INT32 drawcount;
 } planeinfo_t;
@@ -4661,7 +3877,7 @@ static INT32 drawcount = 0;
 #define MAX_TRANSPARENTFLOOR 512
 
 // This will likely turn into a copy of HWR_Add3DWater and replace it.
-void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
+void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, boolean chromakeyed, extracolormap_t *planecolormap)
 {
 	static size_t allocedplanes = 0;
 
@@ -4684,6 +3900,7 @@ void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boo
 	planeinfo[numplanes].FOFSector = FOFSector;
 	planeinfo[numplanes].blend = blend;
 	planeinfo[numplanes].fogplane = fogplane;
+	planeinfo[numplanes].chromakeyed = chromakeyed;
 	planeinfo[numplanes].planecolormap = planecolormap;
 	planeinfo[numplanes].drawcount = drawcount++;
 
@@ -4757,7 +3974,7 @@ static int CompareDrawNodePlanes(const void *p1, const void *p2)
 	size_t n2 = *(const size_t*)p2;
 	if (!sortnode[n1].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n1)");
 	if (!sortnode[n2].plane) I_Error("CompareDrawNodePlanes: Uh.. This isn't a plane! (n2)");
-	return ABS(sortnode[n2].plane->fixedheight - viewz) - ABS(sortnode[n1].plane->fixedheight - viewz);
+	return abs(sortnode[n2].plane->fixedheight - viewz) - abs(sortnode[n1].plane->fixedheight - viewz);
 }
 
 //
@@ -4850,7 +4067,7 @@ static void HWR_CreateDrawNodes(void)
 			gl_frontsector = NULL;
 
 			if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
-				HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat);
+				HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->chromakeyed);
 			HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
 				sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->planecolormap);
 		}
@@ -4859,9 +4076,11 @@ static void HWR_CreateDrawNodes(void)
 			// We aren't traversing the BSP tree, so make gl_frontsector null to avoid crashes.
 			gl_frontsector = NULL;
 
+			polyobj_t *po = sortnode[sortindex[i]].polyplane->polysector;
+
 			if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
-				HWR_GetLevelFlat(sortnode[sortindex[i]].polyplane->levelflat);
-			HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
+				HWR_GetLevelFlat(sortnode[sortindex[i]].polyplane->levelflat, po->flags & POF_SPLAT);
+			HWR_RenderPolyObjectPlane(po, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
 				sortnode[sortindex[i]].polyplane->levelflat, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
 		}
 		else if (sortnode[sortindex[i]].wall)
@@ -4899,12 +4118,9 @@ static void HWR_DrawSprites(void)
 		gl_vissprite_t *spr = gl_vsprorder[i];
 		if (spr->bbox)
 			HWR_DrawBoundingBox(spr);
-		else
-#ifdef HWPRECIP
-		if (spr->precip)
+		else if (spr->precip)
 			HWR_DrawPrecipitationSprite(spr);
 		else
-#endif
 		{
 			if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow)
 			{
@@ -4975,9 +4191,7 @@ static UINT8 sectorlight;
 static void HWR_AddSprites(sector_t *sec)
 {
 	mobj_t *thing;
-#ifdef HWPRECIP
 	precipmobj_t *precipthing;
-#endif
 	fixed_t limit_dist, hoop_limit_dist;
 
 	// BSP is traversed by subsector.
@@ -5010,7 +4224,6 @@ static void HWR_AddSprites(sector_t *sec)
 		}
 	}
 
-#ifdef HWPRECIP
 	// no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
 	if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
 	{
@@ -5020,7 +4233,6 @@ static void HWR_AddSprites(sector_t *sec)
 				HWR_ProjectPrecipitationSprite(precipthing);
 		}
 	}
-#endif
 }
 
 // --------------------------------------------------------------------------
@@ -5073,6 +4285,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	// uncapped/interpolation
 	interpmobjstate_t interp = {0};
 
+	if (!r_renderthings)
+		return;
+
 	if (!thing)
 		return;
 
@@ -5149,9 +4364,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	//Fab : 02-08-98: 'skin' override spritedef currently used for skin
 	if (thing->skin && thing->sprite == SPR_PLAY)
 	{
-		sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
+		sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
 #ifdef ROTSPRITE
-		sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
+		sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
 #endif
 	}
 	else
@@ -5517,7 +4732,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	vis->angle = interp.angle;
 }
 
-#ifdef HWPRECIP
 // Precipitation projector for hardware mode
 static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 {
@@ -5646,7 +4860,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 		thing->precipflags |= PCF_THUNK;
 	}
 }
-#endif
 
 static void HWR_ProjectBoundingBox(mobj_t *thing)
 {
@@ -5856,41 +5069,18 @@ static void HWR_DrawSkyBackground(player_t *player)
 	if (cv_glskydome.value)
 	{
 		FTransform dometransform;
-		const float fpov = FixedToFloat(R_GetPlayerFov(player));
-		postimg_t *type;
 
-		if (splitscreen && player == &players[secondarydisplayplayer])
-			type = &postimgtype2;
-		else
-			type = &postimgtype;
+		memcpy(&dometransform, &atransform, sizeof(FTransform));
 
-		memset(&dometransform, 0x00, sizeof(FTransform));
+		dometransform.x      = 0.0;
+		dometransform.y      = 0.0;
+		dometransform.z      = 0.0;
 
 		//04/01/2000: Hurdler: added for T&L
 		//                     It should replace all other gl_viewxxx when finished
 		HWR_SetTransformAiming(&dometransform, player, false);
 		dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 
-		if (*type == postimg_flip)
-			dometransform.flip = true;
-		else
-			dometransform.flip = false;
-
-		dometransform.scalex = 1;
-		dometransform.scaley = (float)vid.width/vid.height;
-		dometransform.scalez = 1;
-		dometransform.fovxangle = fpov; // Tails
-		dometransform.fovyangle = fpov; // Tails
-		if (player->viewrollangle != 0)
-		{
-			fixed_t rol = AngleFixed(player->viewrollangle);
-			dometransform.rollangle = FIXED_TO_FLOAT(rol);
-			dometransform.roll = true;
-			dometransform.rollx = 1.0f;
-			dometransform.rollz = 0.0f;
-		}
-		dometransform.splitscreen = splitscreen;
-
 		HWR_GetTexture(texturetranslation[skytexture]);
 
 		if (gl_sky.texture != texturetranslation[skytexture])
@@ -5937,7 +5127,7 @@ static void HWR_DrawSkyBackground(player_t *player)
 		// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
 		// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
 
-		angle = (dup_viewangle + gl_xtoviewangle[0]);
+		angle = (viewangle + xtoviewangle[0]);
 
 		dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
 
@@ -6001,10 +5191,10 @@ static inline void HWR_ClearView(void)
 
 	/// \bug faB - enable depth mask, disable color mask
 
-	HWD.pfnGClipRect((INT32)gl_viewwindowx,
-	                 (INT32)gl_viewwindowy,
-	                 (INT32)(gl_viewwindowx + gl_viewwidth),
-	                 (INT32)(gl_viewwindowy + gl_viewheight),
+	HWD.pfnGClipRect((INT32)viewwindowx,
+	                 (INT32)viewwindowy,
+	                 (INT32)(viewwindowx + viewwidth),
+	                 (INT32)(viewwindowy + viewheight),
 	                 ZCLIP_PLANE);
 	HWD.pfnClearBuffer(false, true, 0);
 
@@ -6019,32 +5209,6 @@ static inline void HWR_ClearView(void)
 // -----------------+
 void HWR_SetViewSize(void)
 {
-	// setup view size
-	gl_viewwidth = (float)vid.width;
-	gl_viewheight = (float)vid.height;
-
-	if (splitscreen)
-		gl_viewheight /= 2;
-
-	gl_centerx = gl_viewwidth / 2;
-	gl_basecentery = gl_viewheight / 2; //note: this is (gl_centerx * gl_viewheight / gl_viewwidth)
-
-	gl_viewwindowx = (vid.width - gl_viewwidth) / 2;
-	gl_windowcenterx = (float)(vid.width / 2);
-	if (fabsf(gl_viewwidth - vid.width) < 1.0E-36f)
-	{
-		gl_baseviewwindowy = 0;
-		gl_basewindowcentery = gl_viewheight / 2;               // window top left corner at 0,0
-	}
-	else
-	{
-		gl_baseviewwindowy = (vid.height-gl_viewheight) / 2;
-		gl_basewindowcentery = (float)(vid.height / 2);
-	}
-
-	gl_pspritexscale = gl_viewwidth / BASEVIDWIDTH;
-	gl_pspriteyscale = ((vid.height*gl_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width;
-
 	HWD.pfnFlushScreenTextures();
 }
 
@@ -6078,12 +5242,8 @@ static void HWR_SetShaderState(void)
 	HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader());
 }
 
-// ==========================================================================
-// Same as rendering the player view, but from the skybox object
-// ==========================================================================
-void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
+static void HWR_SetupView(player_t *player, INT32 viewnumber, float fpov, boolean skybox)
 {
-	const float fpov = FixedToFloat(R_GetPlayerFov(player));
 	postimg_t *type;
 
 	if (splitscreen && player == &players[secondarydisplayplayer])
@@ -6100,55 +5260,41 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 		stplyr = saved_player;
 #ifdef ALAM_LIGHTING
 		HWR_SetLights(viewnumber);
+#else
+		(void)viewnumber;
 #endif
 	}
 
 	// note: sets viewangle, viewx, viewy, viewz
-	R_SkyboxFrame(player);
-
-	// copy view cam position for local use
-	dup_viewx = viewx;
-	dup_viewy = viewy;
-	dup_viewz = viewz;
-	dup_viewangle = viewangle;
-
-	// set window position
-	gl_centery = gl_basecentery;
-	gl_viewwindowy = gl_baseviewwindowy;
-	gl_windowcentery = gl_basewindowcentery;
-	if (splitscreen && viewnumber == 1)
-	{
-		gl_viewwindowy += (vid.height/2);
-		gl_windowcentery += (vid.height/2);
-	}
-
-	// check for new console commands.
-	NetUpdate();
+	if (skybox)
+		R_SkyboxFrame(player);
+	else
+		R_SetupFrame(player);
 
-	gl_viewx = FIXED_TO_FLOAT(dup_viewx);
-	gl_viewy = FIXED_TO_FLOAT(dup_viewy);
-	gl_viewz = FIXED_TO_FLOAT(dup_viewz);
-	gl_viewsin = FIXED_TO_FLOAT(viewsin);
-	gl_viewcos = FIXED_TO_FLOAT(viewcos);
+	gl_viewx = FixedToFloat(viewx);
+	gl_viewy = FixedToFloat(viewy);
+	gl_viewz = FixedToFloat(viewz);
+	gl_viewsin = FixedToFloat(viewsin);
+	gl_viewcos = FixedToFloat(viewcos);
 
 	//04/01/2000: Hurdler: added for T&L
 	//                     It should replace all other gl_viewxxx when finished
 	memset(&atransform, 0x00, sizeof(FTransform));
 
-	HWR_SetTransformAiming(&atransform, player, true);
+	HWR_SetTransformAiming(&atransform, player, skybox);
 	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 
-	gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
-	gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
+	gl_viewludsin = FixedToFloat(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
+	gl_viewludcos = FixedToFloat(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
 
 	if (*type == postimg_flip)
 		atransform.flip = true;
 	else
 		atransform.flip = false;
 
-	atransform.x      = gl_viewx;  // FIXED_TO_FLOAT(viewx)
-	atransform.y      = gl_viewy;  // FIXED_TO_FLOAT(viewy)
-	atransform.z      = gl_viewz;  // FIXED_TO_FLOAT(viewz)
+	atransform.x      = gl_viewx;
+	atransform.y      = gl_viewy;
+	atransform.z      = gl_viewz;
 	atransform.scalex = 1;
 	atransform.scaley = (float)vid.width/vid.height;
 	atransform.scalez = 1;
@@ -6158,7 +5304,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 	if (player->viewrollangle != 0)
 	{
 		fixed_t rol = AngleFixed(player->viewrollangle);
-		atransform.rollangle = FIXED_TO_FLOAT(rol);
+		atransform.rollangle = FixedToFloat(rol);
 		atransform.roll = true;
 		atransform.rollx = 1.0f;
 		atransform.rollz = 0.0f;
@@ -6166,6 +5312,19 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 	atransform.splitscreen = splitscreen;
 
 	gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
+}
+
+// ==========================================================================
+// Same as rendering the player view, but from the skybox object
+// ==========================================================================
+void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
+{
+	const float fpov = FixedToFloat(R_GetPlayerFov(player));
+
+	HWR_SetupView(player, viewnumber, fpov, true);
+
+	// check for new console commands.
+	NetUpdate();
 
 	//------------------------------------------------------------------------
 	HWR_ClearView();
@@ -6180,19 +5339,15 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 
 	drawcount = 0;
 
-#ifdef NEWCLIP
 	if (rendermode == render_opengl)
 	{
-		angle_t a1 = gld_FrustumAngle(gl_aimingangle);
+		angle_t a1 = gld_FrustumAngle(fpov, gl_aimingangle);
 		gld_clipper_Clear();
 		gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
 #ifdef HAVE_SPHEREFRUSTRUM
 		gld_FrustrumSetup();
 #endif
 	}
-#else
-	HWR_ClearClipSegs();
-#endif
 
 	//04/01/2000: Hurdler: added for T&L
 	//                     Actually it only works on Walls and Planes
@@ -6257,17 +5412,11 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 {
 	const float fpov = FixedToFloat(R_GetPlayerFov(player));
-	postimg_t *type;
 
 	const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on
 
 	FRGBAFloat ClearColor;
 
-	if (splitscreen && player == &players[secondarydisplayplayer])
-		type = &postimgtype2;
-	else
-		type = &postimgtype;
-
 	ClearColor.red = 0.0f;
 	ClearColor.green = 0.0f;
 	ClearColor.blue = 0.0f;
@@ -6284,83 +5433,13 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 		HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
 	PS_STOP_TIMING(ps_hw_skyboxtime);
 
-	if (!HWR_ShouldUsePaletteRendering())
-	{
-		// do we really need to save player (is it not the same)?
-		player_t *saved_player = stplyr;
-		stplyr = player;
-		ST_doPaletteStuff();
-		stplyr = saved_player;
-#ifdef ALAM_LIGHTING
-		HWR_SetLights(viewnumber);
-#endif
-	}
+	HWR_SetupView(player, viewnumber, fpov, false);
 
-	// note: sets viewangle, viewx, viewy, viewz
-	R_SetupFrame(player);
 	framecount++; // timedemo
 
-	// copy view cam position for local use
-	dup_viewx = viewx;
-	dup_viewy = viewy;
-	dup_viewz = viewz;
-	dup_viewangle = viewangle;
-
-	// set window position
-	gl_centery = gl_basecentery;
-	gl_viewwindowy = gl_baseviewwindowy;
-	gl_windowcentery = gl_basewindowcentery;
-	if (splitscreen && viewnumber == 1)
-	{
-		gl_viewwindowy += (vid.height/2);
-		gl_windowcentery += (vid.height/2);
-	}
-
 	// check for new console commands.
 	NetUpdate();
 
-	gl_viewx = FIXED_TO_FLOAT(dup_viewx);
-	gl_viewy = FIXED_TO_FLOAT(dup_viewy);
-	gl_viewz = FIXED_TO_FLOAT(dup_viewz);
-	gl_viewsin = FIXED_TO_FLOAT(viewsin);
-	gl_viewcos = FIXED_TO_FLOAT(viewcos);
-
-	//04/01/2000: Hurdler: added for T&L
-	//                     It should replace all other gl_viewxxx when finished
-	memset(&atransform, 0x00, sizeof(FTransform));
-
-	HWR_SetTransformAiming(&atransform, player, false);
-	atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
-
-	gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
-	gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT));
-
-	if (*type == postimg_flip)
-		atransform.flip = true;
-	else
-		atransform.flip = false;
-
-	atransform.x      = gl_viewx;  // FIXED_TO_FLOAT(viewx)
-	atransform.y      = gl_viewy;  // FIXED_TO_FLOAT(viewy)
-	atransform.z      = gl_viewz;  // FIXED_TO_FLOAT(viewz)
-	atransform.scalex = 1;
-	atransform.scaley = (float)vid.width/vid.height;
-	atransform.scalez = 1;
-
-	atransform.fovxangle = fpov; // Tails
-	atransform.fovyangle = fpov; // Tails
-	if (player->viewrollangle != 0)
-	{
-		fixed_t rol = AngleFixed(player->viewrollangle);
-		atransform.rollangle = FIXED_TO_FLOAT(rol);
-		atransform.roll = true;
-		atransform.rollx = 1.0f;
-		atransform.rollz = 0.0f;
-	}
-	atransform.splitscreen = splitscreen;
-
-	gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
-
 	//------------------------------------------------------------------------
 	HWR_ClearView(); // Clears the depth buffer and resets the view I believe
 
@@ -6374,19 +5453,15 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
 
 	drawcount = 0;
 
-#ifdef NEWCLIP
 	if (rendermode == render_opengl)
 	{
-		angle_t a1 = gld_FrustumAngle(gl_aimingangle);
+		angle_t a1 = gld_FrustumAngle(fpov, gl_aimingangle);
 		gld_clipper_Clear();
 		gld_clipper_SafeAddClipRange(viewangle + a1, viewangle - a1);
 #ifdef HAVE_SPHEREFRUSTRUM
 		gld_FrustrumSetup();
 #endif
 	}
-#else
-	HWR_ClearClipSegs();
-#endif
 
 	//04/01/2000: Hurdler: added for T&L
 	//                     Actually it only works on Walls and Planes
@@ -6484,7 +5559,7 @@ static void HWR_TogglePaletteRendering(void)
 			// The textures will still be converted to RGBA by r_opengl.
 			// This however makes hw_cache use paletted blending for composite textures!
 			// (patchformat is not touched)
-			textureformat = GL_TEXFMT_P_8;
+			textureformat = GL_TEXFMT_AP_88;
 
 			HWR_SetMapPalette();
 			HWR_SetPalette(pLocalPalette);
@@ -6666,10 +5741,6 @@ void HWR_AddCommands(void)
 	CV_RegisterVar(&cv_glpaletterendering);
 	CV_RegisterVar(&cv_glpalettedepth);
 	CV_RegisterVar(&cv_glwireframe);
-
-#ifndef NEWCLIP
-	CV_RegisterVar(&cv_glclipwalls);
-#endif
 }
 
 // --------------------------------------------------------------------------
@@ -6759,6 +5830,9 @@ void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 te
 {
 	static size_t allocedwalls = 0;
 
+	if (!r_renderwalls)
+		return;
+
 	// Force realloc if buffer has been freed
 	if (!wallinfo)
 		allocedwalls = 0;
@@ -6787,6 +5861,9 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend,
 
 	INT32 shader = SHADER_NONE;
 
+	if (!r_renderwalls)
+		return;
+
 	// Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting
 	HWR_Lighting(pSurf, lightlevel, wallcolormap);
 
@@ -6876,7 +5953,7 @@ void HWR_DoPostProcessor(player_t *player)
 		if (*type == postimg_water)
 		{
 			WAVELENGTH = 5;
-			AMPLITUDE = 20;
+			AMPLITUDE = 40;
 			FREQUENCY = 8;
 		}
 		else
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 2d4c74583a1c47d35ab22b26e119874dab68e190..ea610a48b477824fd1d59e45ce70802bce5e460a 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -35,11 +35,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
 void HWR_ClearSkyDome(void);
 void HWR_BuildSkyDome(void);
-void HWR_DrawViewBorder(INT32 clearlines);
 void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum);
-void HWR_InitTextureMapping(void);
 void HWR_SetViewSize(void);
-void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option);
 void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap);
 void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
 void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap);
@@ -48,7 +45,6 @@ void HWR_CreateStaticLightmaps(INT32 bspnum);
 void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color);
 void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength);
 void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor);	// Lat: separate flags from color since color needs to be an uint to work right.
-void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum);
 
 UINT8 *HWR_GetScreenshot(void);
 boolean HWR_Screenshot(const char *pathname);
@@ -103,16 +99,11 @@ extern consvar_t cv_glpalettedepth;
 
 extern consvar_t cv_glwireframe;
 
-extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy;
-
-extern float gl_viewwindowx, gl_basewindowcentery;
-
 // BP: big hack for a test in lighting ref : 1249753487AB
 extern fixed_t *hwbbox;
 extern FTransform atransform;
 extern float gl_viewsin, gl_viewcos;
 
-
 // Render stats
 extern ps_metric_t ps_hw_skyboxtime;
 extern ps_metric_t ps_hw_nodesorttime;
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index ef0341bd5da7b73b5b9757a06a8eab2df521967f..0bb8de851bd2ad1b1891b92322943df83d349539 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -571,19 +571,15 @@ void HWR_LoadModels(void)
 		}
 
 		// Add sprite models.
-		// Must be 4 characters long exactly. Otherwise, it's not a sprite name.
-		if (len == 4)
+		for (i = 0; i < numsprites; i++)
 		{
-			for (i = 0; i < numsprites; i++)
+			if (stricmp(name, sprnames[i]) == 0)
 			{
-				if (stricmp(name, sprnames[i]) == 0)
-				{
-					md2_models[i].scale = scale;
-					md2_models[i].offset = offset;
-					md2_models[i].found = true;
-					strcpy(md2_models[i].filename, filename);
-					goto modelfound;
-				}
+				md2_models[i].scale = scale;
+				md2_models[i].offset = offset;
+				md2_models[i].found = true;
+				strcpy(md2_models[i].filename, filename);
+				goto modelfound;
 			}
 		}
 
@@ -1078,30 +1074,47 @@ static boolean HWR_CanInterpolateSprite2(modelspr2frames_t *spr2frame)
 	return spr2frame->interpolate;
 }
 
-//
-// HWR_GetModelSprite2 (see P_GetSkinSprite2)
-// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
-// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
-//
-
-static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *player)
+static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2)
 {
-	UINT8 super = 0, i = 0;
+	if (!md2 || !md2->model)
+		return NULL;
 
-	if (!md2 || !md2->model || !md2->model->spr2frames || !skin)
-		return 0;
+	boolean is_super = spr2 & SPR2F_SUPER;
 
-	if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
-		return 0;
+	spr2 &= SPR2F_MASK;
+
+	if (spr2 >= free_spr2)
+		return NULL;
+
+	if (is_super)
+	{
+		modelspr2frames_t *frames = md2->model->superspr2frames;
+		if (frames && md2->model->superspr2frames[spr2].numframes)
+			return &md2->model->superspr2frames[spr2];
+	}
+
+	if (md2->model->spr2frames)
+		return &md2->model->spr2frames[spr2];
+
+	return NULL;
+}
 
-	while (!md2->model->spr2frames[spr2].numframes
+static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player)
+{
+	UINT16 super = 0;
+	UINT8 i = 0;
+
+	if (!md2 || !md2->model || !skin)
+		return HWR_GetModelSprite2Frames(md2, 0);
+
+	while (!HWR_GetModelSprite2Frames(md2, spr2)
 		&& spr2 != SPR2_STND
-		&& ++i != 32) // recursion limiter
+		&& ++i < 32) // recursion limiter
 	{
-		if (spr2 & FF_SPR2SUPER)
+		if (spr2 & SPR2F_SUPER)
 		{
-			super = FF_SPR2SUPER;
-			spr2 &= ~FF_SPR2SUPER;
+			super = SPR2F_SUPER;
+			spr2 &= ~SPR2F_SUPER;
 			continue;
 		}
 
@@ -1130,9 +1143,9 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
 	}
 
 	if (i >= 32) // probably an infinite loop...
-		return 0;
+		spr2 = 0;
 
-	return spr2;
+	return HWR_GetModelSprite2Frames(md2, spr2);
 }
 
 // Adjust texture coords of model to fit into a patch's max_s and max_t
@@ -1188,7 +1201,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 	char filename[64];
 	INT32 frame = 0;
 	INT32 nextFrame = -1;
-	UINT8 spr2 = 0;
+	modelspr2frames_t *spr2frames = NULL;
 	FTransform p;
 	FSurfaceInfo Surf;
 
@@ -1418,18 +1431,24 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			tics = (float)spr->mobj->anim_duration;
 		}
 
+		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
+			sprdef = P_GetSkinSpritedef(spr->mobj->skin, spr->mobj->sprite2);
+		else
+			sprdef = &sprites[spr->mobj->sprite];
+
 		frame = (spr->mobj->frame & FF_FRAMEMASK);
-		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
+		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
+			spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
+		if (spr2frames)
 		{
-			spr2 = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
-			mod = md2->model->spr2frames[spr2].numframes;
+			mod = spr2frames->numframes;
 #ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod
-			if (mod > (INT32)((skin_t *)spr->mobj->skin)->sprites[spr2].numframes)
-				mod = ((skin_t *)spr->mobj->skin)->sprites[spr2].numframes;
+			if (mod > (INT32)sprdef->numframes)
+				mod = sprdef->numframes;
 #endif
 			if (!mod)
 				mod = 1;
-			frame = md2->model->spr2frames[spr2].frames[frame%mod];
+			frame = spr2frames->frames[frame % mod];
 		}
 		else
 		{
@@ -1449,13 +1468,18 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			if (durs > INTERPOLERATION_LIMIT)
 				durs = INTERPOLERATION_LIMIT;
 
-			if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
+			if (spr2frames)
 			{
-				if (HWR_CanInterpolateSprite2(&md2->model->spr2frames[spr2])
+				UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]);
+
+				// Add or remove SPR2F_SUPER based on certain conditions
+				next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj);
+
+				if (HWR_CanInterpolateSprite2(spr2frames)
 					&& (spr->mobj->frame & FF_ANIMATE
 					|| (spr->mobj->state->nextstate != S_NULL
 					&& states[spr->mobj->state->nextstate].sprite == SPR_PLAY
-					&& ((P_GetSkinSprite2(spr->mobj->skin, (((spr->mobj->player && spr->mobj->player->powers[pw_super]) ? FF_SPR2SUPER : 0)|states[spr->mobj->state->nextstate].frame) & FF_FRAMEMASK, spr->mobj->player) == spr->mobj->sprite2)))))
+					&& ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2)))))
 				{
 					nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1;
 					if (nextFrame >= mod)
@@ -1466,7 +1490,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 							nextFrame = 0;
 					}
 					if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE))
-						nextFrame = md2->model->spr2frames[spr2].frames[nextFrame];
+						nextFrame = spr2frames->frames[nextFrame];
 					else
 						nextFrame = -1;
 				}
@@ -1502,11 +1526,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		else
 			p.z = FIXED_TO_FLOAT(interp.z);
 
-		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
-			sprdef = &((skin_t *)spr->mobj->skin)->sprites[spr->mobj->sprite2];
-		else
-			sprdef = &sprites[spr->mobj->sprite];
-
 		sprframe = &sprdef->spriteframes[spr->mobj->frame & FF_FRAMEMASK];
 
 		if (sprframe->rotate || papersprite)
diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c
index 0d656f35ad8e72673134f1bf53f561842b280f49..5856473e4c9855c6416f97843cd476fde2c587d2 100644
--- a/src/hardware/hw_model.c
+++ b/src/hardware/hw_model.c
@@ -292,6 +292,7 @@ void LoadModelSprite2(model_t *model)
 {
 	INT32 i;
 	modelspr2frames_t *spr2frames = NULL;
+	modelspr2frames_t *superspr2frames = NULL;
 	INT32 numframes = model->meshes[0].numFrames;
 	char *framename = model->frameNames;
 
@@ -335,25 +336,33 @@ void LoadModelSprite2(model_t *model)
 				spr2idx = 0;
 				while (spr2idx < free_spr2)
 				{
+					modelspr2frames_t *frames = NULL;
 					if (!memcmp(spr2names[spr2idx], name, 4))
 					{
 						if (!spr2frames)
-							spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES*2, PU_STATIC, NULL);
+							spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
+						frames = spr2frames;
+
 						if (super)
-							spr2idx |= FF_SPR2SUPER;
+						{
+							if (!superspr2frames)
+								superspr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
+							frames = superspr2frames;
+						}
+
 						if (framechars[0])
 						{
 							frame = atoi(framechars);
-							if (spr2frames[spr2idx].numframes < frame+1)
-								spr2frames[spr2idx].numframes = frame+1;
+							if (frames[spr2idx].numframes < frame+1)
+								frames[spr2idx].numframes = frame+1;
 						}
 						else
 						{
-							frame = spr2frames[spr2idx].numframes;
-							spr2frames[spr2idx].numframes++;
+							frame = frames[spr2idx].numframes;
+							frames[spr2idx].numframes++;
 						}
-						spr2frames[spr2idx].frames[frame] = i;
-						spr2frames[spr2idx].interpolate = interpolate;
+						frames[spr2idx].frames[frame] = i;
+						frames[spr2idx].interpolate = interpolate;
 						break;
 					}
 					spr2idx++;
@@ -366,7 +375,10 @@ void LoadModelSprite2(model_t *model)
 
 	if (model->spr2frames)
 		Z_Free(model->spr2frames);
+	if (model->superspr2frames)
+		Z_Free(model->superspr2frames);
 	model->spr2frames = spr2frames;
+	model->superspr2frames = superspr2frames;
 }
 
 //
diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h
index f057271df1397f528a615f93331480f620586417..5eb649b173303d72dba16a46c0793ab4d29f351c 100644
--- a/src/hardware/hw_model.h
+++ b/src/hardware/hw_model.h
@@ -101,6 +101,7 @@ typedef struct model_s
 	char *frameNames;
 	boolean interpolate[256];
 	modelspr2frames_t *spr2frames;
+	modelspr2frames_t *superspr2frames;
 
 	// the max_s and max_t values that the uvs are currently adjusted to
 	// (if a sprite is used as a texture)
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index acd09f614318f433567a5764f2cf453d26315e9d..75a92c2fb33ad542b0931786a9b4688a9f9dccbc 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -180,7 +180,7 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
 // GL_MSG_Warning   : Raises a warning.
 // -----------------+
 
-static void GL_MSG_Warning(const char *format, ...)
+FUNCPRINTF static void GL_MSG_Warning(const char *format, ...)
 {
 	char str[4096] = "";
 	va_list arglist;
@@ -203,7 +203,7 @@ static void GL_MSG_Warning(const char *format, ...)
 // GL_MSG_Error     : Raises an error.
 // -----------------+
 
-static void GL_MSG_Error(const char *format, ...)
+FUNCPRINTF static void GL_MSG_Error(const char *format, ...)
 {
 	char str[4096] = "";
 	va_list arglist;
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 4b199f6b3a669b51acdf7f7a45197abd465e78cd..16c59d9cf82bb9b92067f3c792a5f29292e7cdfd 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -61,21 +61,22 @@
 #define HU_CSAY       2 // Server CECHOes to everyone.
 
 //-------------------------------------------
-//              heads up font
+//              Fonts & stuff
 //-------------------------------------------
-patch_t *hu_font[HU_FONTSIZE];
-patch_t *tny_font[HU_FONTSIZE];
+// Font definitions
+fontdef_t hu_font;
+fontdef_t tny_font;
+fontdef_t cred_font;
+fontdef_t lt_font;
+fontdef_t ntb_font;
+fontdef_t nto_font;
+
+// Numbers
 patch_t *tallnum[10]; // 0-9
 patch_t *nightsnum[10]; // 0-9
-
-// Level title and credits fonts
-patch_t *lt_font[LT_FONTSIZE];
-patch_t *cred_font[CRED_FONTSIZE];
 patch_t *ttlnum[10]; // act numbers (0-9)
-
-// Name tag fonts
-patch_t *ntb_font[NT_FONTSIZE];
-patch_t *nto_font[NT_FONTSIZE];
+patch_t *tallminus;
+patch_t *tallinfin;
 
 static player_t *plr;
 boolean chat_on; // entering a chat message?
@@ -91,8 +92,6 @@ patch_t *bflagico;
 patch_t *rmatcico;
 patch_t *bmatcico;
 patch_t *tagico;
-patch_t *tallminus;
-patch_t *tallinfin;
 
 //-------------------------------------------
 //              coop hud
@@ -188,53 +187,26 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum);
 void HU_LoadGraphics(void)
 {
 	char buffer[9];
-	INT32 i, j;
+	INT32 i;
 
 	if (dedicated)
 		return;
 
-	j = HU_FONTSTART;
-	for (i = 0; i < HU_FONTSIZE; i++, j++)
-	{
-		// cache the heads-up font for entire game execution
-		sprintf(buffer, "STCFN%.3d", j);
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			hu_font[i] = NULL;
-		else
-			hu_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-
-		// tiny version of the heads-up font
-		sprintf(buffer, "TNYFN%.3d", j);
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			tny_font[i] = NULL;
-		else
-			tny_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	j = LT_FONTSTART;
-	for (i = 0; i < LT_FONTSIZE; i++)
-	{
-		sprintf(buffer, "LTFNT%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			lt_font[i] = NULL;
-		else
-			lt_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	// cache the credits font for entire game execution (why not?)
-	j = CRED_FONTSTART;
-	for (i = 0; i < CRED_FONTSIZE; i++)
-	{
-		sprintf(buffer, "CRFNT%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			cred_font[i] = NULL;
-		else
-			cred_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
+	// Cache fonts
+	HU_LoadFontCharacters(&hu_font,   "STCFN");
+	HU_LoadFontCharacters(&tny_font,  "TNYFN");
+	HU_LoadFontCharacters(&cred_font, "CRFNT");
+	HU_LoadFontCharacters(&lt_font,   "LTFNT");
+	HU_LoadFontCharacters(&ntb_font,  "NTFNT");
+	HU_LoadFontCharacters(&nto_font,  "NTFNO");
+
+	// For each font, set kerning, space width, character width and line spacing
+	HU_SetFontProperties(&hu_font,   0,  4,  8, 12);
+	HU_SetFontProperties(&tny_font,  0,  2,  4, 12);
+	HU_SetFontProperties(&cred_font, 0, 16, 16, 16);
+	HU_SetFontProperties(&lt_font,   0, 16, 20, 20);
+	HU_SetFontProperties(&ntb_font,  2,  4, 20, 21);
+	HU_SetFontProperties(&nto_font,  0,  4, 20, 21);
 
 	//cache numbers too!
 	for (i = 0; i < 10; i++)
@@ -243,45 +215,14 @@ void HU_LoadGraphics(void)
 		tallnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
 		sprintf(buffer, "NGTNUM%d", i);
 		nightsnum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
+		sprintf(buffer, "TTL%.2d", i);
+		ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
 	}
 
 	// minus for negative tallnums
 	tallminus = (patch_t *)W_CachePatchName("STTMINUS", PU_HUDGFX);
 	tallinfin = (patch_t *)W_CachePatchName("STTINFIN", PU_HUDGFX);
 
-	// cache act numbers for level titles
-	for (i = 0; i < 10; i++)
-	{
-		sprintf(buffer, "TTL%.2d", i);
-		ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	// cache the base name tag font for entire game execution
-	j = NT_FONTSTART;
-	for (i = 0; i < NT_FONTSIZE; i++)
-	{
-		sprintf(buffer, "NTFNT%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			ntb_font[i] = NULL;
-		else
-			ntb_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	// cache the outline name tag font for entire game execution
-	j = NT_FONTSTART;
-	for (i = 0; i < NT_FONTSIZE; i++)
-	{
-		sprintf(buffer, "NTFNO%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			nto_font[i] = NULL;
-		else
-			nto_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
 	// cache the crosshairs, don't bother to know which one is being used,
 	// just cache all 3, they're so small anyway.
 	for (i = 0; i < HU_CROSSHAIRS; i++)
@@ -323,6 +264,29 @@ void HU_LoadGraphics(void)
 	//emeraldpics[2][7] = W_CachePatchName("EMBOX8", PU_HUDGFX); -- unused
 }
 
+void HU_LoadFontCharacters(fontdef_t *font, const char *prefix)
+{
+		char buffer[9];
+		INT32 i, j = FONTSTART;
+
+		for (i = 0; i < FONTSIZE; i++, j++)
+		{
+			sprintf(buffer, "%.5s%.3d", prefix, j);
+			if (W_CheckNumForName(buffer) == LUMPERROR)
+				font->chars[i] = NULL;
+			else
+				font->chars[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
+		}
+}
+
+void HU_SetFontProperties(fontdef_t *font, INT32 kerning, UINT32 spacewidth, UINT32 charwidth, UINT32 linespacing)
+{
+	font->kerning = kerning;
+	font->spacewidth = spacewidth;
+	font->charwidth = charwidth;
+	font->linespacing = linespacing;
+}
+
 // Initialise Heads up
 // once at game startup.
 //
@@ -465,9 +429,12 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
 	numwords = COM_Argc() - usedargs;
 	I_Assert(numwords > 0);
 
-	if (CHAT_MUTE) // TODO: Per Player mute.
+	if (CHAT_MUTE)
 	{
-		HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
+		if (cv_mute.value)
+			HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
+		else
+			HU_AddChatText(va("%s>ERROR: You have been muted. You can't say anything.", "\x85"), false);
 		return;
 	}
 
@@ -496,10 +463,10 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
 		// what we're gonna do now is check if the player exists
 		// with that logic, characters 4 and 5 are our numbers:
 		const char *newmsg;
-		char playernum[3];
+		char playernum[3+1];
 		INT32 spc = 1; // used if playernum[1] is a space.
 
-		strncpy(playernum, msg+3, 3);
+		strncpy(playernum, msg+3, sizeof(playernum)-1);
 		// check for undesirable characters in our "number"
 		if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9')))
 		{
@@ -644,9 +611,9 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
 	msg = (char *)*p;
 	SKIPSTRINGL(*p, HU_MAXMSGLEN + 1);
 
-	if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
+	if ((cv_mute.value || players[playernum].muted || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum)))
 	{
-		CONS_Alert(CONS_WARNING, cv_mute.value ?
+		CONS_Alert(CONS_WARNING, (cv_mute.value || players[playernum].muted) ?
 			M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
 			player_names[playernum]);
 		if (server)
@@ -962,14 +929,17 @@ static void HU_sendChatMessage(void)
 	// last minute mute check
 	if (CHAT_MUTE)
 	{
-		HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
+		if (cv_mute.value)
+			HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false);
+		else
+			HU_AddChatText(va("%s>ERROR: You have been muted. You can't say anything.", "\x85"), false);
 		return;
 	}
 
 	if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm
 	{
 		INT32 spc = 1; // used if playernum[1] is a space.
-		char playernum[3];
+		char playernum[3+1];
 		const char *newmsg;
 
 		// what we're gonna do now is check if the player exists
@@ -982,7 +952,7 @@ static void HU_sendChatMessage(void)
 			return;
 		}
 
-		strncpy(playernum, msg+3, 3);
+		strncpy(playernum, msg+3, sizeof(playernum)-1);
 		// check for undesirable characters in our "number"
 		if (!(isdigit(playernum[0]) && isdigit(playernum[1])))
 		{
@@ -1029,6 +999,7 @@ static void HU_sendChatMessage(void)
 void HU_clearChatChars(void)
 {
 	memset(w_chat, '\0', sizeof(w_chat));
+	I_SetTextInputMode(false);
 	chat_on = false;
 	c_input = 0;
 
@@ -1078,6 +1049,7 @@ boolean HU_Responder(event_t *ev)
 		if ((ev->key == gamecontrol[GC_TALKKEY][0] || ev->key == gamecontrol[GC_TALKKEY][1])
 			&& netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise.
 		{
+			I_SetTextInputMode(true);
 			chat_on = true;
 			chat_on_first_event = false;
 			w_chat[0] = 0;
@@ -1089,6 +1061,7 @@ boolean HU_Responder(event_t *ev)
 		if ((ev->key == gamecontrol[GC_TEAMKEY][0] || ev->key == gamecontrol[GC_TEAMKEY][1])
 			&& netgame && !OLD_MUTE)
 		{
+			I_SetTextInputMode(true);
 			chat_on = true;
 			chat_on_first_event = false;
 			w_chat[0] = 0;
@@ -1111,7 +1084,7 @@ boolean HU_Responder(event_t *ev)
 
 		if (ev->type == ev_text)
 		{
-			if ((c < HU_FONTSTART || c > HU_FONTEND || !hu_font[c-HU_FONTSTART])
+			if ((c < FONTSTART || c > FONTEND || !hu_font.chars[c-FONTSTART])
 				&& c != ' ') // Allow spaces, of course
 			{
 				return false;
@@ -1163,6 +1136,7 @@ boolean HU_Responder(event_t *ev)
 			if (!CHAT_MUTE)
 				HU_sendChatMessage();
 
+			I_SetTextInputMode(false);
 			chat_on = false;
 			c_input = 0; // reset input cursor
 			chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :)
@@ -1173,6 +1147,7 @@ boolean HU_Responder(event_t *ev)
 			|| c == gamecontrol[GC_TEAMKEY][0] || c == gamecontrol[GC_TEAMKEY][1])
 			&& c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle.
 		{
+			I_SetTextInputMode(false);
 			chat_on = false;
 			c_input = 0; // reset input cursor
 			I_UpdateMouseGrab();
@@ -1230,199 +1205,81 @@ boolean HU_Responder(event_t *ev)
 //                         HEADS UP DRAWING
 //======================================================================
 
-// Precompile a wordwrapped string to any given width.
-// This is a muuuch better method than V_WORDWRAP.
-// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
-// this one is simplified for the chat drawer.
-static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
-{
-	INT32 c;
-	size_t chw, i, lastusablespace = 0;
-	size_t slen;
-	char *newstring = Z_StrDup(string);
-	INT32 spacewidth = (vid.width < 640) ? 8 : 4, charwidth = (vid.width < 640) ? 8 : 4;
-
-	slen = strlen(string);
-	x = 0;
-
-	for (i = 0; i < slen; ++i)
-	{
-		c = newstring[i];
-		if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09
-			continue;
-
-		if (c == '\n')
-		{
-			x = 0;
-			lastusablespace = 0;
-			continue;
-		}
-
-		if (!(option & V_ALLOWLOWERCASE))
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			chw = spacewidth;
-			lastusablespace = i;
-		}
-		else
-			chw = charwidth;
-
-		x += chw;
-
-		if (lastusablespace != 0 && x > w)
-		{
-			//CONS_Printf("Wrap at index %d\n", i);
-			newstring[lastusablespace] = '\n';
-			i = lastusablespace+1;
-			lastusablespace = 0;
-			x = 0;
-		}
-	}
-	return newstring;
-}
-
-
 // 30/7/18: chaty is now the distance at which the lowest point of the chat will be drawn if that makes any sense.
 
 INT16 chatx = 13, chaty = 169; // let's use this as our coordinates
 
-// chat stuff by VincyTM LOL XD!
-
 // HU_DrawMiniChat
 
 static void HU_drawMiniChat(void)
 {
-	INT32 x = chatx+2;
+	INT32 x = chatx+2, y;
+	INT32 chatheight = 0;
 	INT32 charwidth = 4, charheight = 6;
 	INT32 boxw = cv_chatwidth.value;
 	INT32 dx = 0, dy = 0;
-	size_t i = chat_nummsg_min;
-	boolean prev_linereturn = false; // a hack to prevent double \n while I have no idea why they happen in the first place.
-
-	INT32 msglines = 0;
-	// process all messages once without rendering anything or doing anything fancy so that we know how many lines each message has...
-	INT32 y;
 
 	if (!chat_nummsg_min)
 		return; // needless to say it's useless to do anything if we don't have anything to draw.
 
-	/*if (splitscreen > 1)
-		boxw = max(64, boxw/2);*/
-
-	for (; i>0; i--)
+	for (size_t i = chat_nummsg_min; i > 0; i--)
 	{
-		char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]);
-		size_t j = 0;
-		INT32 linescount = 0;
-
-		while(msg[j]) // iterate through msg
+		char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]);
+		for(size_t j = 0; msg[j]; j++) // iterate through msg
 		{
-			if (msg[j] < HU_FONTSTART) // don't draw
+			if (msg[j] == '\n') // get back down.
 			{
-				if (msg[j] == '\n') // get back down.
-				{
-					++j;
-					if (!prev_linereturn)
-					{
-						linescount += 1;
-						dx = 0;
-					}
-					prev_linereturn = true;
-					continue;
-				}
-				else if (msg[j] & 0x80) // stolen from video.c, nice.
-				{
-					++j;
-					continue;
-				}
-
-				++j;
-			}
-			else
-			{
-				j++;
+				chatheight += charheight;
+				dx = 0;
 			}
-			prev_linereturn = false;
-			dx += charwidth;
-			if (dx >= boxw)
+			else if (msg[j] >= FONTSTART)
 			{
-				dx = 0;
-				linescount += 1;
+				dx += charwidth;
+				if (dx >= boxw)
+				{
+					dx = 0;
+					chatheight += charheight;
+				}
 			}
 		}
-		dy = 0;
 		dx = 0;
-		msglines += linescount+1;
+		chatheight += charheight;
 
 		if (msg)
 			Z_Free(msg);
 	}
 
-	y = chaty - charheight*(msglines+1);
-
-	/*if (splitscreen)
-	{
-		y -= BASEVIDHEIGHT/2;
-		if (splitscreen > 1)
-			y += 16;
-	}*/
-
-	dx = 0;
-	dy = 0;
-	i = 0;
-	prev_linereturn = false;
+	y = chaty - (chatheight + charheight);
 
-	for (; i<=(chat_nummsg_min-1); i++) // iterate through our hot messages
+	for (size_t i = 0; i < chat_nummsg_min; i++) // iterate through our hot messages
 	{
-		INT32 clrflag = 0;
 		INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below...
 		INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one.
-		size_t j = 0;
-		char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it.
+		char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it.
 		UINT8 *colormap = NULL;
 
-		while(msg[j]) // iterate through msg
+		for(size_t j = 0; msg[j]; j++) // iterate through msg
 		{
-			if (msg[j] < HU_FONTSTART) // don't draw
+			if (msg[j] == '\n') // get back down.
 			{
-				if (msg[j] == '\n') // get back down.
-				{
-					++j;
-					if (!prev_linereturn)
-					{
-						dy += charheight;
-						dx = 0;
-					}
-					prev_linereturn = true;
-					continue;
-				}
-				else if (msg[j] & 0x80) // stolen from video.c, nice.
-				{
-					clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-					colormap = V_GetStringColormap(clrflag);
-					++j;
-					continue;
-				}
-
-				++j;
+				dy += charheight;
+				dx = 0;
 			}
-			else
+			else if (msg[j] & 0x80) // get colormap
+				colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
+			else if (msg[j] >= FONTSTART)
 			{
 				if (cv_chatbacktint.value) // on request of wolfy
 					V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
 
-				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap);
-			}
+				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap);
 
-			dx += charwidth;
-			prev_linereturn = false;
-			if (dx >= boxw)
-			{
-				dx = 0;
-				dy += charheight;
+				dx += charwidth;
+				if (dx >= boxw)
+				{
+					dx = 0;
+					dy += charheight;
+				}
 			}
 		}
 		dy += charheight;
@@ -1434,7 +1291,6 @@ static void HU_drawMiniChat(void)
 
 	// decrement addy and make that shit smooth:
 	addy /= 2;
-
 }
 
 // HU_DrawChatLog
@@ -1479,44 +1335,28 @@ static void HU_drawChatLog(INT32 offset)
 
 	for (i=0; i<chat_nummsg_log; i++) // iterate through our chatlog
 	{
-		INT32 clrflag = 0;
-		INT32 j = 0;
-		char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it.
+		char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it.
 		UINT8 *colormap = NULL;
-		while(msg[j]) // iterate through msg
+		for(size_t j = 0; msg[j]; j++) // iterate through msg
 		{
-			if (msg[j] < HU_FONTSTART) // don't draw
+			if (msg[j] == '\n') // get back down.
 			{
-				if (msg[j] == '\n') // get back down.
-				{
-					++j;
-					dy += charheight;
-					dx = 0;
-					continue;
-				}
-				else if (msg[j] & 0x80) // stolen from video.c, nice.
-				{
-					clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-					colormap = V_GetStringColormap(clrflag);
-					++j;
-					continue;
-				}
-
-				++j;
+				dy += charheight;
+				dx = 0;
 			}
-			else
+			else if (msg[j] & 0x80) // get colormap
+				colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
+			else if (msg[j] >= FONTSTART)
 			{
 				if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
-					V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
-				else
-					j++; // don't forget to increment this or we'll get stuck in the limbo.
-			}
+					V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
 
-			dx += charwidth;
-			if (dx >= boxw-charwidth-2 && i<chat_nummsg_log && msg[j] >= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!!
-			{
-				dx = 0;
-				dy += charheight;
+				dx += charwidth;
+				if (dx >= boxw-charwidth-2 && i<chat_nummsg_log) // end of message shouldn't count, nor should invisible characters!!!!
+				{
+					dx = 0;
+					dy += charheight;
+				}
 			}
 		}
 		dy += charheight;
@@ -1526,30 +1366,25 @@ static void HU_drawChatLog(INT32 offset)
 			Z_Free(msg);
 	}
 
-
 	if (((chat_scroll >= chat_maxscroll) || (chat_scrollmedown)) && !(justscrolleddown || justscrolledup || chat_scrolltime)) // was already at the bottom of the page before new maxscroll calculation and was NOT scrolling.
-	{
 		atbottom = true; // we should scroll
-	}
+
 	chat_scrollmedown = false;
 
-	// getmaxscroll through a lazy hack. We do all these loops,
-	// so let's not do more loops that are gonna lag the game more. :P
+	// getmaxscroll through a lazy hack. We do all these loops, so let's not do more loops that are gonna lag the game more. :P
 	chat_maxscroll = max(dy / charheight - cv_chatheight.value, 0);
 
 	// if we're not bound by the time, autoscroll for next frame:
 	if (atbottom)
 		chat_scroll = chat_maxscroll;
 
-	// draw arrows to indicate that we can (or not) scroll.
-	// account for Y = -1 offset in tinyfont
+	// draw arrows to indicate that we can (or not) scroll, accounting for Y = -1 offset in tinyfont
 	if (chat_scroll > 0)
 		V_DrawThinString(chatx-8, ((justscrolledup) ? (chat_topy-1) : (chat_topy)) - 1, V_SNAPTOBOTTOM | V_SNAPTOLEFT | V_YELLOWMAP, "\x1A"); // up arrow
 	if (chat_scroll < chat_maxscroll)
 		V_DrawThinString(chatx-8, chat_bottomy-((justscrolleddown) ? 5 : 6) - 1, V_SNAPTOBOTTOM | V_SNAPTOLEFT | V_YELLOWMAP, "\x1B"); // down arrow
 
-	justscrolleddown = false;
-	justscrolledup = false;
+	justscrolleddown = justscrolledup = false;
 }
 
 //
@@ -1567,7 +1402,6 @@ static void HU_DrawChat(void)
 	INT32 cflag = 0;
 	const char *ntalk = "Say: ", *ttalk = "Team: ";
 	const char *talk = ntalk;
-	const char *mute = "Chat has been muted.";
 
 #ifdef NETSPLITSCREEN
 	if (splitscreen)
@@ -1582,35 +1416,24 @@ static void HU_DrawChat(void)
 #endif
 
 	if (teamtalk)
-	{
 		talk = ttalk;
-#if 0
-		if (players[consoleplayer].ctfteam == 1)
-			t = 0x500;  // Red
-		else if (players[consoleplayer].ctfteam == 2)
-			t = 0x400; // Blue
-#endif
-	}
 
 	if (CHAT_MUTE)
 	{
-		talk = mute;
+		if (cv_mute.value)
+			talk = "Chat has been muted.";
+		else
+			talk = "You have been muted.";
 		typelines = 1;
 		cflag = V_GRAYMAP; // set text in gray if chat is muted.
 	}
 
 	V_DrawFillConsoleMap(chatx, y-1, boxw, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT);
 
-	while (talk[i])
+	for (i = 0; talk[i]; i++)
 	{
-		if (talk[i] < HU_FONTSTART)
-			++i;
-		else
-		{
+		if (talk[i] >= FONTSTART)
 			V_DrawChatCharacter(chatx + c + 2, y, talk[i] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|cflag, true, V_GetStringColormap(talk[i]|cflag));
-			i++;
-		}
-
 		c += charwidth;
 	}
 
@@ -1621,13 +1444,12 @@ static void HU_DrawChat(void)
 		return;
 	}
 
-	i = 0;
 	typelines = 1;
 
 	if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
 		V_DrawChatCharacter(chatx + 2 + c, y+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, true, NULL);
 
-	while (w_chat[i])
+	for (i = 0; w_chat[i]; i++)
 	{
 		boolean skippedline = false;
 		if (c_input == (i+1))
@@ -1644,14 +1466,11 @@ static void HU_DrawChat(void)
 			}
 		}
 
-		//Hurdler: isn't it better like that?
-		if (w_chat[i] < HU_FONTSTART)
-			++i;
-		else
-			V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
+		if (w_chat[i] >= FONTSTART)
+			V_DrawChatCharacter(chatx + c + 2, y, w_chat[i] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
 
 		c += charwidth;
-		if (c > boxw-(charwidth*2) && !skippedline)
+		if (c > boxw-charwidth && !skippedline)
 		{
 			c = 0;
 			y += charheight;
@@ -1673,47 +1492,31 @@ static void HU_DrawChat(void)
 		}
 #endif
 
-		i = 0;
-		for(i=0; (i<MAXPLAYERS); i++)
+		for(i=0; i<MAXPLAYERS; i++)
 		{
 			// filter: (code needs optimization pls help I'm bad with C)
 			if (w_chat[3])
 			{
-				char playernum[3];
+				char playernum[3+1];
 				UINT32 n;
 				// right, that's half important: (w_chat[4] may be a space since /pm0 msg is perfectly acceptable!)
 				if ( ( ((w_chat[3] != 0) && ((w_chat[3] < '0') || (w_chat[3] > '9'))) || ((w_chat[4] != 0) && (((w_chat[4] < '0') || (w_chat[4] > '9'))))) && (w_chat[4] != ' '))
 					break;
 
-				strncpy(playernum, w_chat+3, 3);
+				strncpy(playernum, w_chat+3, sizeof(playernum)-1);
+				playernum[3] = 0;
 				n = atoi(playernum); // turn that into a number
 				// special cases:
-
-				if ((n == 0) && !(w_chat[4] == '0'))
-				{
-					if (!(i<10))
-						continue;
-				}
-				else if ((n == 1) && !(w_chat[3] == '0'))
-				{
-					if (!((i == 1) || ((i >= 10) && (i <= 19))))
-						continue;
-				}
-				else if ((n == 2) && !(w_chat[3] == '0'))
-				{
-					if (!((i == 2) || ((i >= 20) && (i <= 29))))
-						continue;
-				}
-				else if ((n == 3) && !(w_chat[3] == '0'))
-				{
-					if (!((i == 3) || ((i >= 30) && (i <= 31))))
-						continue;
-				}
+				if ((n == 0) && !(w_chat[4] == '0') && (!(i<10)))
+					continue;
+				else if ((n == 1) && !(w_chat[3] == '0') && (!((i == 1) || ((i >= 10) && (i <= 19)))))
+					continue;
+				else if ((n == 2) && !(w_chat[3] == '0') && (!((i == 2) || ((i >= 20) && (i <= 29)))))
+					continue; 
+				else if ((n == 3) && !(w_chat[3] == '0') && (!((i == 3) || ((i >= 30) && (i <= 31)))))
+					continue; 
 				else	// general case.
-				{
-					if (i != n)
-						continue;
-				}
+					if (i != n) continue;
 			}
 
 			if (playeringame[i])
@@ -1744,41 +1547,22 @@ static void HU_DrawChat_Old(void)
 	size_t i = 0;
 	const char *ntalk = "Say: ", *ttalk = "Say-Team: ";
 	const char *talk = ntalk;
-	INT32 charwidth = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
-	INT32 charheight = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->height) * con_scalefactor;
+	INT32 charwidth = 8 * con_scalefactor, charheight = 8 * con_scalefactor;
 	if (teamtalk)
-	{
 		talk = ttalk;
-#if 0
-		if (players[consoleplayer].ctfteam == 1)
-			t = 0x500;  // Red
-		else if (players[consoleplayer].ctfteam == 2)
-			t = 0x400; // Blue
-#endif
-	}
 
-	while (talk[i])
+	for (i = 0; talk[i]; i++)
 	{
-		if (talk[i] < HU_FONTSTART)
-		{
-			++i;
-			//charwidth = 4 * con_scalefactor;
-		}
-		else
-		{
-			//charwidth = (hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor;
-			V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, true);
-		}
+		if (talk[i] >= FONTSTART)
+			V_DrawCharacter(HU_INPUTX + c, y, talk[i] | cv_constextsize.value | V_NOSCALESTART, true);
 		c += charwidth;
 	}
 
 	if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
 		V_DrawCharacter(HU_INPUTX+c, y+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
 
-	i = 0;
-	while (w_chat[i])
+	for (i = 0; w_chat[i]; i++)
 	{
-
 		if (c_input == (i+1) && hu_tick < 4)
 		{
 			INT32 cursorx = (HU_INPUTX+c+charwidth < vid.width) ? (HU_INPUTX + c + charwidth) : (HU_INPUTX); // we may have to go down.
@@ -1786,17 +1570,8 @@ static void HU_DrawChat_Old(void)
 			V_DrawCharacter(cursorx, cursory+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
 		}
 
-		//Hurdler: isn't it better like that?
-		if (w_chat[i] < HU_FONTSTART)
-		{
-			++i;
-			//charwidth = 4 * con_scalefactor;
-		}
-		else
-		{
-			//charwidth = (hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
-			V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, true);
-		}
+		if (w_chat[i] >= FONTSTART)
+			V_DrawCharacter(HU_INPUTX + c, y, w_chat[i] | cv_constextsize.value | V_NOSCALESTART | t, true);
 
 		c += charwidth;
 		if (c >= vid.width)
@@ -1805,9 +1580,6 @@ static void HU_DrawChat_Old(void)
 			y += charheight;
 		}
 	}
-
-	if (hu_tick < 4)
-		V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
 }
 
 // Draw crosshairs at the exact center of the view.
@@ -1893,21 +1665,6 @@ static void HU_DrawCEcho(void)
 	}
 }
 
-static void HU_drawGametype(void)
-{
-	const char *strvalue = NULL;
-
-	if (gametype < 0 || gametype >= gametypecount)
-		return; // not a valid gametype???
-
-	strvalue = Gametype_Names[gametype];
-
-	if (splitscreen)
-		V_DrawString(4, 184, 0, strvalue);
-	else
-		V_DrawString(4, 192, 0, strvalue);
-}
-
 //
 // demo info stuff
 //
@@ -2044,76 +1801,6 @@ void HU_Drawer(void)
 	}
 }
 
-//======================================================================
-//                 HUD MESSAGES CLEARING FROM SCREEN
-//======================================================================
-
-// Clear old messages from the borders around the view window
-// (only for reduced view, refresh the borders when needed)
-//
-// startline: y coord to start clear,
-// clearlines: how many lines to clear.
-//
-static INT32 oldclearlines;
-
-void HU_Erase(void)
-{
-	INT32 topline, bottomline;
-	INT32 y, yoffset;
-
-#ifdef HWRENDER
-	// clear hud msgs on double buffer (OpenGL mode)
-	boolean secondframe;
-	static INT32 secondframelines;
-#endif
-
-	if (con_clearlines == oldclearlines && !con_hudupdate && !chat_on)
-		return;
-
-#ifdef HWRENDER
-	// clear the other frame in double-buffer modes
-	secondframe = (con_clearlines != oldclearlines);
-	if (secondframe)
-		secondframelines = oldclearlines;
-#endif
-
-	// clear the message lines that go away, so use _oldclearlines_
-	bottomline = oldclearlines;
-	oldclearlines = con_clearlines;
-	if (chat_on && OLDCHAT)
-		if (bottomline < 8)
-			bottomline = 8; // only do it for consolechat. consolechat is gay.
-
-	if (automapactive || viewwindowx == 0) // hud msgs don't need to be cleared
-		return;
-
-	// software mode copies view border pattern & beveled edges from the backbuffer
-	if (rendermode == render_soft)
-	{
-		topline = 0;
-		for (y = topline, yoffset = y*vid.width; y < bottomline; y++, yoffset += vid.width)
-		{
-			if (y < viewwindowy || y >= viewwindowy + viewheight)
-				R_VideoErase(yoffset, vid.width); // erase entire line
-			else
-			{
-				R_VideoErase(yoffset, viewwindowx); // erase left border
-				// erase right border
-				R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
-			}
-		}
-		con_hudupdate = false; // if it was set..
-	}
-#ifdef HWRENDER
-	else if (rendermode != render_none)
-	{
-		// refresh just what is needed from the view borders
-		HWR_DrawViewBorder(secondframelines);
-		con_hudupdate = secondframe;
-	}
-#endif
-}
-
 //======================================================================
 //                   IN-LEVEL MULTIPLAYER RANKINGS
 //======================================================================
@@ -2839,7 +2526,8 @@ static void HU_DrawRankings(void)
 	UINT32 whiteplayer;
 
 	// draw the current gametype in the lower right
-	HU_drawGametype();
+	if (gametype >= 0 && gametype < gametypecount)
+		V_DrawString(4, splitscreen ? 184 : 192, 0, Gametype_Names[gametype]);
 
 	if (gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT))
 	{
@@ -3052,7 +2740,7 @@ void HU_DoCEcho(const char *msg)
 {
 	I_OutputMsg("%s\n", msg); // print to log
 
-	strncpy(cechotext, msg, sizeof(cechotext));
+	strncpy(cechotext, msg, sizeof(cechotext)-1);
 	strncat(cechotext, "\\", sizeof(cechotext) - strlen(cechotext) - 1);
 	cechotext[sizeof(cechotext) - 1] = '\0';
 	cechotimer = cechoduration;
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index 8647e4500cb2ce1ebf76015dbcc9031a0b5f4082..ca77ed93002750d6cefa28584d8e4de7be3bfc65 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -19,33 +19,34 @@
 #include "r_defs.h"
 
 //------------------------------------
-//           heads up font
+//           Fonts & stuff
 //------------------------------------
-#define HU_FONTSTART '\x16' // the first font character
-#define HU_FONTEND '~'
-
-#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
-
-// Level title font
-#define LT_FONTSTART '!' // the first font characters
-#define LT_FONTEND 'z' // the last font characters
-#define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1)
-
-#define CRED_FONTSTART '!' // the first font character
-#define CRED_FONTEND 'Z' // the last font character
-#define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1)
-
-// Name tag font
-// Used by base and outline font set
-#define NT_FONTSTART '!' // the first font character
-#define NT_FONTEND 'Z' // the last font character
-#define NT_FONTSIZE (NT_FONTEND - NT_FONTSTART + 1)
+#define FONTSTART '\x16' // the first font character
+#define FONTEND '~'
+#define FONTSIZE (FONTEND - FONTSTART + 1)
 
 #define HU_CROSSHAIRS 3 // maximum of 9 - see HU_Init();
 
 extern char *shiftxform; // english translation shift table
 extern char english_shiftxform[];
 
+typedef struct
+{
+	patch_t *chars[FONTSIZE];
+	INT32 kerning;
+	UINT32 spacewidth;
+	UINT32 charwidth;
+	UINT32 linespacing;
+} fontdef_t;
+
+extern fontdef_t hu_font, tny_font, cred_font, lt_font;
+extern fontdef_t ntb_font, nto_font;
+extern patch_t *tallnum[10];
+extern patch_t *nightsnum[10];
+extern patch_t *ttlnum[10];
+extern patch_t *tallminus;
+extern patch_t *tallinfin;
+
 //------------------------------------
 //        sorted player lines
 //------------------------------------
@@ -69,8 +70,8 @@ typedef struct
 #else
 #define OLDCHAT (cv_consolechat.value == 1 || dedicated || vid.width < 640 || splitscreen)
 #endif
-#define CHAT_MUTE (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))	// this still allows to open the chat but not to type. That's used for scrolling and whatnot.
-#define OLD_MUTE (OLDCHAT && cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))	// this is used to prevent oldchat from opening when muted.
+#define CHAT_MUTE ((cv_mute.value || players[consoleplayer].muted) && !(server || IsPlayerAdmin(consoleplayer)))	// this still allows to open the chat but not to type. That's used for scrolling and whatnot.
+#define OLD_MUTE (OLDCHAT && (cv_mute.value || players[consoleplayer].muted) && !(server || IsPlayerAdmin(consoleplayer)))	// this is used to prevent oldchat from opening when muted.
 
 // some functions
 void HU_AddChatText(const char *text, boolean playsound);
@@ -78,22 +79,12 @@ void HU_AddChatText(const char *text, boolean playsound);
 // set true when entering a chat message
 extern boolean chat_on;
 
-extern patch_t *hu_font[HU_FONTSIZE], *tny_font[HU_FONTSIZE];
-extern patch_t *tallnum[10];
-extern patch_t *nightsnum[10];
-extern patch_t *lt_font[LT_FONTSIZE];
-extern patch_t *cred_font[CRED_FONTSIZE];
-extern patch_t *ntb_font[NT_FONTSIZE];
-extern patch_t *nto_font[NT_FONTSIZE];
-extern patch_t *ttlnum[10];
 extern patch_t *emeraldpics[3][8];
 extern patch_t *rflagico;
 extern patch_t *bflagico;
 extern patch_t *rmatcico;
 extern patch_t *bmatcico;
 extern patch_t *tagico;
-extern patch_t *tallminus;
-extern patch_t *tallinfin;
 extern patch_t *tokenicon;
 
 // set true whenever the tab rankings are being shown for any reason
@@ -103,6 +94,8 @@ extern boolean hu_showscores;
 void HU_Init(void);
 
 void HU_LoadGraphics(void);
+void HU_LoadFontCharacters(fontdef_t *font, const char *prefix);
+void HU_SetFontProperties(fontdef_t *font, INT32 kerning, UINT32 spacewidth, UINT32 charwidth, UINT32 linespacing);
 
 // reset heads up when consoleplayer respawns.
 void HU_Start(void);
@@ -111,7 +104,6 @@ boolean HU_Responder(event_t *ev);
 void HU_Ticker(void);
 void HU_Drawer(void);
 char HU_dequeueChatChar(void);
-void HU_Erase(void);
 void HU_clearChatChars(void);
 void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags);	// Lat': Ping drawer for scoreboard.
 void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);
diff --git a/src/i_system.h b/src/i_system.h
index 3f0e05d127fa4ed5ce9aa8fbe89ff109773851f4..f4d169113c50b0ae5e2c1aca53b4d04f128658f4 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -339,4 +339,12 @@ void I_SetMouseGrab(boolean grab);
 */
 const char *I_GetSysName(void);
 
+/** \brief Sets text input mode. When enabled, keyboard inputs will respect dead keys.
+ */
+void I_SetTextInputMode(boolean active);
+
+/** \brief Retrieves current text input mode.
+ */
+boolean I_GetTextInputMode(void);
+
 #endif
diff --git a/src/i_video.h b/src/i_video.h
index 8efca5f9ab28da6312755d9e11a6c8791149f26b..4b459e25b67bd207bfae911365e1a15eec101db0 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -40,10 +40,6 @@ extern rendermode_t rendermode;
 */
 extern rendermode_t chosenrendermode;
 
-/**	\brief use highcolor modes if true
-*/
-extern boolean highcolor;
-
 /**	\brief setup video mode
 */
 void I_StartupGraphics(void);
@@ -108,8 +104,8 @@ void VID_CheckGLLoaded(rendermode_t oldrender);
 	\return	name of video mode
 */
 const char *VID_GetModeName(INT32 modenum);
-void VID_PrepareModeList(void); /// note hack for SDL
 
+void VID_PrepareModeList(void);
 
 /**	\brief can video system do fullscreen
 */
diff --git a/src/info.c b/src/info.c
index 9f8c2b8115169d5da5ce4e98f4ec12bba22966ae..d66c24af81aaafb851e6a83e699d2027add29cb5 100644
--- a/src/info.c
+++ b/src/info.c
@@ -26,9 +26,10 @@
 #include "hardware/hw_light.h"
 #endif
 
+
 // Hey, moron! If you change this table, don't forget about the sprite enum in info.h and the sprite lights in hw_light.c!
 // For the sake of constant merge conflicts, let's spread this out
-char sprnames[NUMSPRITES + 1][5] =
+char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
 {
 	"NULL", // invisible object
 	"UNKN",
@@ -525,7 +526,7 @@ char sprnames[NUMSPRITES + 1][5] =
 	"GWLR",
 };
 
-char spr2names[NUMPLAYERSPRITES][5] =
+char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1] =
 {
 	"STND",
 	"WAIT",
@@ -648,13 +649,13 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
 
 	0, // SPR2_TRNS,
 
-	FF_SPR2SUPER|SPR2_STND, // SPR2_NSTD,
-	FF_SPR2SUPER|SPR2_FALL, // SPR2_NFLT,
+	SPR2_STND, // SPR2_NSTD,
+	SPR2_FALL, // SPR2_NFLT,
 	0, // SPR2_NFLY, (will never be referenced unless skin 0 lacks this)
 	SPR2_NFLY, // SPR2_NDRL,
-	FF_SPR2SUPER|SPR2_STUN, // SPR2_NSTN,
+	SPR2_STUN, // SPR2_NSTN,
 	SPR2_NSTN, // SPR2_NPUL,
-	FF_SPR2SUPER|SPR2_ROLL, // SPR2_NATK,
+	SPR2_ROLL, // SPR2_NATK,
 
 	0, // SPR2_TAL0, (this will look mighty stupid but oh well)
 	SPR2_TAL0, // SPR2_TAL1,
@@ -691,3309 +692,3309 @@ state_t states[NUMSTATES] =
 	// (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
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_INVISIBLE
-
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 0, 0, S_NULL}, // S_SPAWNSTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 1, 0, S_NULL}, // S_SEESTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 2, 0, S_NULL}, // S_MELEESTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 3, 0, S_NULL}, // S_MISSILESTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 4, 0, S_NULL}, // S_DEATHSTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 5, 0, S_NULL}, // S_XDEATHSTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL}, // S_RAISESTATE
+	{SPR_NULL, 0,  1, {NULL}, 0, 0, S_NULL, 0}, // S_NULL
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_UNKNOWN
+	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_INVISIBLE
+
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 0, 0, S_NULL, 0}, // S_SPAWNSTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 1, 0, S_NULL, 0}, // S_SEESTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 2, 0, S_NULL, 0}, // S_MELEESTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 3, 0, S_NULL, 0}, // S_MISSILESTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 4, 0, S_NULL, 0}, // S_DEATHSTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 5, 0, S_NULL, 0}, // S_XDEATHSTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL, 0}, // S_RAISESTATE
 
 	// Thok
-	{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_THOK
+	{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL, 0}, // S_THOK
 
 	// Player
-	{SPR_PLAY, SPR2_STND|FF_ANIMATE,    105, {NULL}, 0,  7, S_PLAY_WAIT}, // S_PLAY_STND
-	{SPR_PLAY, SPR2_WAIT|FF_ANIMATE,     -1, {NULL}, 0, 16, S_NULL},      // S_PLAY_WAIT
-	{SPR_PLAY, SPR2_WALK,                 4, {NULL}, 0,  0, S_PLAY_WALK}, // S_PLAY_WALK
-	{SPR_PLAY, SPR2_SKID,                 1, {NULL}, 0,  0, S_PLAY_WALK}, // S_PLAY_SKID
-	{SPR_PLAY, SPR2_RUN ,                 2, {NULL}, 0,  0, S_PLAY_RUN},  // S_PLAY_RUN
-	{SPR_PLAY, SPR2_DASH,                 2, {NULL}, 0,  0, S_PLAY_DASH}, // S_PLAY_DASH
-	{SPR_PLAY, SPR2_PAIN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL}, // S_PLAY_PAIN
-	{SPR_PLAY, SPR2_STUN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL}, // S_PLAY_STUN
-	{SPR_PLAY, SPR2_DEAD|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL},      // S_PLAY_DEAD
-	{SPR_PLAY, SPR2_DRWN|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL},      // S_PLAY_DRWN
-	{SPR_PLAY, SPR2_ROLL,                 1, {NULL}, 0,  0, S_PLAY_ROLL}, // S_PLAY_ROLL
-	{SPR_PLAY, SPR2_GASP|FF_ANIMATE,     14, {NULL}, 0,  4, S_PLAY_WALK}, // S_PLAY_GASP
-	{SPR_PLAY, SPR2_JUMP,                 1, {NULL}, 0,  0, S_PLAY_JUMP}, // S_PLAY_JUMP
-	{SPR_PLAY, SPR2_SPNG,                 2, {NULL}, 0,  0, S_PLAY_SPRING}, // S_PLAY_SPRING
-	{SPR_PLAY, SPR2_FALL,                 2, {NULL}, 0,  0, S_PLAY_FALL}, // S_PLAY_FALL
-	{SPR_PLAY, SPR2_EDGE,                12, {NULL}, 0,  0, S_PLAY_EDGE}, // S_PLAY_EDGE
-	{SPR_PLAY, SPR2_RIDE,                 4, {NULL}, 0,  0, S_PLAY_RIDE}, // S_PLAY_RIDE
+	{SPR_PLAY, SPR2_STND|FF_ANIMATE,    105, {NULL}, 0,  7, S_PLAY_WAIT, 0}, // S_PLAY_STND
+	{SPR_PLAY, SPR2_WAIT|FF_ANIMATE,     -1, {NULL}, 0, 16, S_NULL, 0},      // S_PLAY_WAIT
+	{SPR_PLAY, SPR2_WALK,                 4, {NULL}, 0,  0, S_PLAY_WALK, 0}, // S_PLAY_WALK
+	{SPR_PLAY, SPR2_SKID,                 1, {NULL}, 0,  0, S_PLAY_WALK, 0}, // S_PLAY_SKID
+	{SPR_PLAY, SPR2_RUN ,                 2, {NULL}, 0,  0, S_PLAY_RUN, 0},  // S_PLAY_RUN
+	{SPR_PLAY, SPR2_DASH,                 2, {NULL}, 0,  0, S_PLAY_DASH, 0}, // S_PLAY_DASH
+	{SPR_PLAY, SPR2_PAIN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL, 0}, // S_PLAY_PAIN
+	{SPR_PLAY, SPR2_STUN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL, 0}, // S_PLAY_STUN
+	{SPR_PLAY, SPR2_DEAD|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL, 0},      // S_PLAY_DEAD
+	{SPR_PLAY, SPR2_DRWN|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL, 0},      // S_PLAY_DRWN
+	{SPR_PLAY, SPR2_ROLL,                 1, {NULL}, 0,  0, S_PLAY_ROLL, 0}, // S_PLAY_ROLL
+	{SPR_PLAY, SPR2_GASP|FF_ANIMATE,     14, {NULL}, 0,  4, S_PLAY_WALK, 0}, // S_PLAY_GASP
+	{SPR_PLAY, SPR2_JUMP,                 1, {NULL}, 0,  0, S_PLAY_JUMP, 0}, // S_PLAY_JUMP
+	{SPR_PLAY, SPR2_SPNG,                 2, {NULL}, 0,  0, S_PLAY_SPRING, 0}, // S_PLAY_SPRING
+	{SPR_PLAY, SPR2_FALL,                 2, {NULL}, 0,  0, S_PLAY_FALL, 0}, // S_PLAY_FALL
+	{SPR_PLAY, SPR2_EDGE,                12, {NULL}, 0,  0, S_PLAY_EDGE, 0}, // S_PLAY_EDGE
+	{SPR_PLAY, SPR2_RIDE,                 4, {NULL}, 0,  0, S_PLAY_RIDE, 0}, // S_PLAY_RIDE
 
 	// CA2_SPINDASH
-	{SPR_PLAY, SPR2_SPIN,                 2, {NULL}, 0,  0, S_PLAY_SPINDASH}, // S_PLAY_SPINDASH
+	{SPR_PLAY, SPR2_SPIN,                 2, {NULL}, 0,  0, S_PLAY_SPINDASH, 0}, // S_PLAY_SPINDASH
 
 	// CA_FLY/CA_SWIM
-	{SPR_PLAY, SPR2_FLY ,                 2, {NULL}, 0,  0, S_PLAY_FLY},  // S_PLAY_FLY
-	{SPR_PLAY, SPR2_SWIM,                 4, {NULL}, 0,  0, S_PLAY_SWIM}, // S_PLAY_SWIM
-	{SPR_PLAY, SPR2_TIRE,                12, {NULL}, 0,  0, S_PLAY_FLY_TIRED}, // S_PLAY_FLY_TIRED
+	{SPR_PLAY, SPR2_FLY ,                 2, {NULL}, 0,  0, S_PLAY_FLY, 0},  // S_PLAY_FLY
+	{SPR_PLAY, SPR2_SWIM,                 4, {NULL}, 0,  0, S_PLAY_SWIM, 0}, // S_PLAY_SWIM
+	{SPR_PLAY, SPR2_TIRE,                12, {NULL}, 0,  0, S_PLAY_FLY_TIRED, 0}, // S_PLAY_FLY_TIRED
 
 	// CA_GLIDEANDCLIMB
-	{SPR_PLAY, SPR2_GLID,                 2, {NULL}, 0,  0, S_PLAY_GLIDE}, // S_PLAY_GLIDE
-	{SPR_PLAY, SPR2_LAND,                 7, {NULL}, 0,  0, S_PLAY_STND},  // S_PLAY_GLIDE_LANDING
-	{SPR_PLAY, SPR2_CLNG|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL},       // S_PLAY_CLING
-	{SPR_PLAY, SPR2_CLMB,                 5, {NULL}, 0,  0, S_PLAY_CLIMB}, // S_PLAY_CLIMB
+	{SPR_PLAY, SPR2_GLID,                 2, {NULL}, 0,  0, S_PLAY_GLIDE, 0}, // S_PLAY_GLIDE
+	{SPR_PLAY, SPR2_LAND,                 7, {NULL}, 0,  0, S_PLAY_STND, 0},  // S_PLAY_GLIDE_LANDING
+	{SPR_PLAY, SPR2_CLNG|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL, 0},       // S_PLAY_CLING
+	{SPR_PLAY, SPR2_CLMB,                 5, {NULL}, 0,  0, S_PLAY_CLIMB, 0}, // S_PLAY_CLIMB
 
 	// CA_FLOAT/CA_SLOWFALL
-	{SPR_PLAY, SPR2_FLT ,                 7, {NULL}, 0,  0, S_PLAY_FLOAT}, // S_PLAY_FLOAT
-	{SPR_PLAY, SPR2_FRUN,                 7, {NULL}, 0,  0, S_PLAY_FLOAT_RUN},  // S_PLAY_FLOAT_RUN
+	{SPR_PLAY, SPR2_FLT ,                 7, {NULL}, 0,  0, S_PLAY_FLOAT, 0}, // S_PLAY_FLOAT
+	{SPR_PLAY, SPR2_FRUN,                 7, {NULL}, 0,  0, S_PLAY_FLOAT_RUN, 0},  // S_PLAY_FLOAT_RUN
 
 	// CA_BOUNCE
-	{SPR_PLAY, SPR2_BNCE|FF_ANIMATE,     -1, {NULL},             0,  0, S_NULL},                // S_PLAY_BOUNCE
-	{SPR_PLAY, SPR2_LAND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE,  0, S_PLAY_BOUNCE_LANDING}, // S_PLAY_BOUNCE_LANDING
+	{SPR_PLAY, SPR2_BNCE|FF_ANIMATE,     -1, {NULL},             0,  0, S_NULL, 0},                // S_PLAY_BOUNCE
+	{SPR_PLAY, SPR2_LAND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE,  0, S_PLAY_BOUNCE_LANDING, 0}, // S_PLAY_BOUNCE_LANDING
 
 	// CA2_GUNSLINGER
-	{SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE,  2, {NULL}, S_PLAY_FIRE_FINISH, 0, S_PLAY_FIRE},   // S_PLAY_FIRE
-	{SPR_PLAY, SPR2_FIRE,                 15, {NULL},        S_PLAY_STND, 0, S_PLAY_STND},   // S_PLAY_FIRE_FINISH
+	{SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE,  2, {NULL}, S_PLAY_FIRE_FINISH, 0, S_PLAY_FIRE, 0},   // S_PLAY_FIRE
+	{SPR_PLAY, SPR2_FIRE,                 15, {NULL},        S_PLAY_STND, 0, S_PLAY_STND, 0},   // S_PLAY_FIRE_FINISH
 
 	// CA_TWINSPIN
-	{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN
+	{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN, 0}, // S_PLAY_TWINSPIN
 
 	// CA2_MELEE
-	{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
-	{SPR_PLAY, SPR2_MLEE,                70, {NULL},                   0, 0, S_PLAY_FALL},  // S_PLAY_MELEE_FINISH
-	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK},  // S_PLAY_MELEE_LANDING
+	{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE, 0}, // S_PLAY_MELEE
+	{SPR_PLAY, SPR2_MLEE,                70, {NULL},                   0, 0, S_PLAY_FALL, 0},  // S_PLAY_MELEE_FINISH
+	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK, 0},  // S_PLAY_MELEE_LANDING
 
 	// SF_SUPER
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS1
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3}, // S_PLAY_SUPER_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4}, // S_PLAY_SUPER_TRANS3
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5}, // S_PLAY_SUPER_TRANS4
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6}, // S_PLAY_SUPER_TRANS5
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL},         // S_PLAY_SUPER_TRANS6
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_SUPER_TRANS2, 0}, // S_PLAY_SUPER_TRANS1
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3, 0}, // S_PLAY_SUPER_TRANS2
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4, 0}, // S_PLAY_SUPER_TRANS3
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5, 0}, // S_PLAY_SUPER_TRANS4
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6, 0}, // S_PLAY_SUPER_TRANS5
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL, 0},         // S_PLAY_SUPER_TRANS6
 
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY
+	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY, 0}, //S_OBJPLACE_DUMMY
 
 	// 1-Up box sprites (uses player sprite)
-	{SPR_PLAY, SPR2_LIFE,  2, {NULL}, 0, 18, S_PLAY_BOX2},  // S_PLAY_BOX1
-	{SPR_NULL,         0,  1, {NULL}, 0, 18, S_PLAY_BOX1},  // S_PLAY_BOX2
-	{SPR_PLAY, SPR2_LIFE,  4, {NULL}, 0,  4, S_PLAY_ICON2}, // S_PLAY_ICON1
-	{SPR_NULL,         0, 12, {NULL}, 0,  4, S_PLAY_ICON3}, // S_PLAY_ICON2
-	{SPR_PLAY, SPR2_LIFE, 20, {NULL}, 0,  4, S_NULL},       // S_PLAY_ICON3
+	{SPR_PLAY, SPR2_LIFE,  2, {NULL}, 0, 18, S_PLAY_BOX2, 0},  // S_PLAY_BOX1
+	{SPR_NULL,         0,  1, {NULL}, 0, 18, S_PLAY_BOX1, 0},  // S_PLAY_BOX2
+	{SPR_PLAY, SPR2_LIFE,  4, {NULL}, 0,  4, S_PLAY_ICON2, 0}, // S_PLAY_ICON1
+	{SPR_NULL,         0, 12, {NULL}, 0,  4, S_PLAY_ICON3, 0}, // S_PLAY_ICON2
+	{SPR_PLAY, SPR2_LIFE, 20, {NULL}, 0,  4, S_NULL, 0},       // S_PLAY_ICON3
 
 	// Level end sign (uses player sprite)
-	{SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 2, {NULL}, 0, 29, S_PLAY_SIGN},         // S_PLAY_SIGN
+	{SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 2, {NULL}, 0, 29, S_PLAY_SIGN, 0},         // S_PLAY_SIGN
 
 	// NiGHTS Player, transforming
-	{SPR_PLAY, SPR2_TRNS|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_NIGHTS_TRANS2}, // S_PLAY_NIGHTS_TRANS1
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS3}, // S_PLAY_NIGHTS_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS4}, // S_PLAY_NIGHTS_TRANS3
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS5}, // S_PLAY_NIGHTS_TRANS4
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS6}, // S_PLAY_NIGHTS_TRANS5
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 21, {A_FadeOverlay}, 2, 0, S_PLAY_NIGHTS_FLOAT},  // S_PLAY_NIGHTS_TRANS5
+	{SPR_PLAY, SPR2_TRNS|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_NIGHTS_TRANS2, 0}, // S_PLAY_NIGHTS_TRANS1
+	{SPR_PLAY, SPR2_TRNS,                3, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS3, 0}, // S_PLAY_NIGHTS_TRANS2
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS4, 0}, // S_PLAY_NIGHTS_TRANS3
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS5, 0}, // S_PLAY_NIGHTS_TRANS4
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS6, 0}, // S_PLAY_NIGHTS_TRANS5
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 21, {A_FadeOverlay}, 2, 0, S_PLAY_NIGHTS_FLOAT, 0},  // S_PLAY_NIGHTS_TRANS5
 
 	// NiGHTS Player
-	{SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND},  // S_PLAY_NIGHTS_STAND
-	{SPR_PLAY, SPR2_NFLT, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_FLOAT},  // S_PLAY_NIGHTS_FLOAT
-	{SPR_PLAY, SPR2_NFLY, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY},    // S_PLAY_NIGHTS_FLY
-	{SPR_PLAY, SPR2_NDRL, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL},  // S_PLAY_NIGHTS_DRILL
-	{SPR_PLAY, SPR2_NSTN, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_STUN},   // S_PLAY_NIGHTS_STUN
-	{SPR_PLAY, SPR2_NPUL, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_PULL},   // S_PLAY_NIGHTS_PULL
-	{SPR_PLAY, SPR2_NATK, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_ATTACK}, // S_PLAY_NIGHTS_ATTACK
+	{SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND, 0},  // S_PLAY_NIGHTS_STAND
+	{SPR_PLAY, SPR2_NFLT, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_FLOAT, 0},  // S_PLAY_NIGHTS_FLOAT
+	{SPR_PLAY, SPR2_NFLY, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY, 0},    // S_PLAY_NIGHTS_FLY
+	{SPR_PLAY, SPR2_NDRL, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL, 0},  // S_PLAY_NIGHTS_DRILL
+	{SPR_PLAY, SPR2_NSTN, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_STUN, 0},   // S_PLAY_NIGHTS_STUN
+	{SPR_PLAY, SPR2_NPUL, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_PULL, 0},   // S_PLAY_NIGHTS_PULL
+	{SPR_PLAY, SPR2_NATK, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_ATTACK, 0}, // S_PLAY_NIGHTS_ATTACK
 
 	// c:
-	{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART,  5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND}, // S_TAILSOVERLAY_STAND
-	{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES}, // S_TAILSOVERLAY_0DEGREES
-	{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES}, // S_TAILSOVERLAY_PLUS30DEGREES
-	{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES}, // S_TAILSOVERLAY_PLUS60DEGREES
-	{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES}, // S_TAILSOVERLAY_MINUS30DEGREES
-	{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES}, // S_TAILSOVERLAY_MINUS60DEGREES
-	{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_RUN}, // S_TAILSOVERLAY_RUN
-	{SPR_PLAY, SPR2_TAL7|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_FLY}, // S_TAILSOVERLAY_FLY
-	{SPR_PLAY, SPR2_TAL8|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_TIRE}, // S_TAILSOVERLAY_TIRE
-	{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN}, // S_TAILSOVERLAY_PAIN
-	{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP
-	{SPR_PLAY, SPR2_TALB                , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE
-	{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH}, // S_TAILSOVERLAY_DASH
+	{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART,  5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND, 0}, // S_TAILSOVERLAY_STAND
+	{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES, 0}, // S_TAILSOVERLAY_0DEGREES
+	{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES, 0}, // S_TAILSOVERLAY_PLUS30DEGREES
+	{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES, 0}, // S_TAILSOVERLAY_PLUS60DEGREES
+	{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES, 0}, // S_TAILSOVERLAY_MINUS30DEGREES
+	{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES, 0}, // S_TAILSOVERLAY_MINUS60DEGREES
+	{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_RUN, 0}, // S_TAILSOVERLAY_RUN
+	{SPR_PLAY, SPR2_TAL7|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_FLY, 0}, // S_TAILSOVERLAY_FLY
+	{SPR_PLAY, SPR2_TAL8|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_TIRE, 0}, // S_TAILSOVERLAY_TIRE
+	{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN, 0}, // S_TAILSOVERLAY_PAIN
+	{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP, 0}, // S_TAILSOVERLAY_GASP
+	{SPR_PLAY, SPR2_TALB                , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE, 0}, // S_TAILSOVERLAY_EDGE
+	{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH, 0}, // S_TAILSOVERLAY_DASH
 
 	// [:
-	{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH
+	{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1, 0}, // S_JETFUMEFLASH
 
 	// Blue Crawla
-	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND},   // S_POSS_STND
-	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2},   // S_POSS_RUN1
-	{SPR_POSS, 1, 3, {A_Chase}, 0, 0, S_POSS_RUN3},   // S_POSS_RUN2
-	{SPR_POSS, 2, 3, {A_Chase}, 0, 0, S_POSS_RUN4},   // S_POSS_RUN3
-	{SPR_POSS, 3, 3, {A_Chase}, 0, 0, S_POSS_RUN5},   // S_POSS_RUN4
-	{SPR_POSS, 4, 3, {A_Chase}, 0, 0, S_POSS_RUN6},   // S_POSS_RUN5
-	{SPR_POSS, 5, 3, {A_Chase}, 0, 0, S_POSS_RUN1},   // S_POSS_RUN6
+	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND, 0},   // S_POSS_STND
+	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2, 0},   // S_POSS_RUN1
+	{SPR_POSS, 1, 3, {A_Chase}, 0, 0, S_POSS_RUN3, 0},   // S_POSS_RUN2
+	{SPR_POSS, 2, 3, {A_Chase}, 0, 0, S_POSS_RUN4, 0},   // S_POSS_RUN3
+	{SPR_POSS, 3, 3, {A_Chase}, 0, 0, S_POSS_RUN5, 0},   // S_POSS_RUN4
+	{SPR_POSS, 4, 3, {A_Chase}, 0, 0, S_POSS_RUN6, 0},   // S_POSS_RUN5
+	{SPR_POSS, 5, 3, {A_Chase}, 0, 0, S_POSS_RUN1, 0},   // S_POSS_RUN6
 
 	// Red Crawla
-	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND},   // S_SPOS_STND
-	{SPR_SPOS, 0, 1, {A_Chase}, 0, 0, S_SPOS_RUN2},   // S_SPOS_RUN1
-	{SPR_SPOS, 1, 1, {A_Chase}, 0, 0, S_SPOS_RUN3},   // S_SPOS_RUN2
-	{SPR_SPOS, 2, 1, {A_Chase}, 0, 0, S_SPOS_RUN4},   // S_SPOS_RUN3
-	{SPR_SPOS, 3, 1, {A_Chase}, 0, 0, S_SPOS_RUN5},   // S_SPOS_RUN4
-	{SPR_SPOS, 4, 1, {A_Chase}, 0, 0, S_SPOS_RUN6},   // S_SPOS_RUN5
-	{SPR_SPOS, 5, 1, {A_Chase}, 0, 0, S_SPOS_RUN1},   // S_SPOS_RUN6
+	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND, 0},   // S_SPOS_STND
+	{SPR_SPOS, 0, 1, {A_Chase}, 0, 0, S_SPOS_RUN2, 0},   // S_SPOS_RUN1
+	{SPR_SPOS, 1, 1, {A_Chase}, 0, 0, S_SPOS_RUN3, 0},   // S_SPOS_RUN2
+	{SPR_SPOS, 2, 1, {A_Chase}, 0, 0, S_SPOS_RUN4, 0},   // S_SPOS_RUN3
+	{SPR_SPOS, 3, 1, {A_Chase}, 0, 0, S_SPOS_RUN5, 0},   // S_SPOS_RUN4
+	{SPR_SPOS, 4, 1, {A_Chase}, 0, 0, S_SPOS_RUN6, 0},   // S_SPOS_RUN5
+	{SPR_SPOS, 5, 1, {A_Chase}, 0, 0, S_SPOS_RUN1, 0},   // S_SPOS_RUN6
 
 	// Greenflower Fish
-	{SPR_FISH, 1, 1, {NULL}, 0, 0, S_FISH2},         // S_FISH1
-	{SPR_FISH, 1, 1, {A_FishJump}, 0, 0, S_FISH1},   // S_FISH2
-	{SPR_FISH, 0, 1, {NULL}, 0, 0, S_FISH4},         // S_FISH3
-	{SPR_FISH, 0, 1, {A_FishJump}, 0, 0, S_FISH3},   // S_FISH4
+	{SPR_FISH, 1, 1, {NULL}, 0, 0, S_FISH2, 0},         // S_FISH1
+	{SPR_FISH, 1, 1, {A_FishJump}, 0, 0, S_FISH1, 0},   // S_FISH2
+	{SPR_FISH, 0, 1, {NULL}, 0, 0, S_FISH4, 0},         // S_FISH3
+	{SPR_FISH, 0, 1, {A_FishJump}, 0, 0, S_FISH3, 0},   // S_FISH4
 
 	// Gold Buzz
-	{SPR_BUZZ, 0, 2, {A_Look}, 0, 0, S_BUZZLOOK2},   // S_BUZZLOOK1
-	{SPR_BUZZ, 1, 2, {A_Look}, 0, 0, S_BUZZLOOK1},   // S_BUZZLOOK2
-	{SPR_BUZZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_BUZZFLY2}, // S_BUZZFLY1
-	{SPR_BUZZ, 1, 2, {A_BuzzFly}, 0, 0, S_BUZZFLY1}, // S_BUZZFLY2
+	{SPR_BUZZ, 0, 2, {A_Look}, 0, 0, S_BUZZLOOK2, 0},   // S_BUZZLOOK1
+	{SPR_BUZZ, 1, 2, {A_Look}, 0, 0, S_BUZZLOOK1, 0},   // S_BUZZLOOK2
+	{SPR_BUZZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_BUZZFLY2, 0}, // S_BUZZFLY1
+	{SPR_BUZZ, 1, 2, {A_BuzzFly}, 0, 0, S_BUZZFLY1, 0}, // S_BUZZFLY2
 
 	// Red Buzz
-	{SPR_RBUZ, 0, 2, {A_Look}, 0, 0, S_RBUZZLOOK2},   // S_RBUZZLOOK1
-	{SPR_RBUZ, 1, 2, {A_Look}, 0, 0, S_RBUZZLOOK1},   // S_RBUZZLOOK2
-	{SPR_RBUZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_RBUZZFLY2}, // S_RBUZZFLY1
-	{SPR_RBUZ, 1, 2, {A_BuzzFly}, 0, 0, S_RBUZZFLY1}, // S_RBUZZFLY2
+	{SPR_RBUZ, 0, 2, {A_Look}, 0, 0, S_RBUZZLOOK2, 0},   // S_RBUZZLOOK1
+	{SPR_RBUZ, 1, 2, {A_Look}, 0, 0, S_RBUZZLOOK1, 0},   // S_RBUZZLOOK2
+	{SPR_RBUZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_RBUZZFLY2, 0}, // S_RBUZZFLY1
+	{SPR_RBUZ, 1, 2, {A_BuzzFly}, 0, 0, S_RBUZZFLY1, 0}, // S_RBUZZFLY2
 
 	// Jetty-Syn Bomber
-	{SPR_JETB, 0, 4, {A_Look}, 0, 0, S_JETBLOOK2},      // S_JETBLOOK1
-	{SPR_JETB, 1, 4, {A_Look}, 0, 0, S_JETBLOOK1},      // S_JETBLOOK2
-	{SPR_JETB, 0, 1, {A_JetbThink}, 0, 0, S_JETBZOOM2}, // S_JETBZOOM1
-	{SPR_JETB, 1, 1, {A_JetbThink}, 0, 0, S_JETBZOOM1}, // S_JETBZOOM2
+	{SPR_JETB, 0, 4, {A_Look}, 0, 0, S_JETBLOOK2, 0},      // S_JETBLOOK1
+	{SPR_JETB, 1, 4, {A_Look}, 0, 0, S_JETBLOOK1, 0},      // S_JETBLOOK2
+	{SPR_JETB, 0, 1, {A_JetbThink}, 0, 0, S_JETBZOOM2, 0}, // S_JETBZOOM1
+	{SPR_JETB, 1, 1, {A_JetbThink}, 0, 0, S_JETBZOOM1, 0}, // S_JETBZOOM2
 
 	// Jetty-Syn Gunner
-	{SPR_JETG, 0, 4, {A_Look}, 0, 0, S_JETGLOOK2},       // S_JETGLOOK1
-	{SPR_JETG, 1, 4, {A_Look}, 0, 0, S_JETGLOOK1},       // S_JETGLOOK2
-	{SPR_JETG, 0, 1, {A_JetgThink}, 0, 0, S_JETGZOOM2},  // S_JETGZOOM1
-	{SPR_JETG, 1, 1, {A_JetgThink}, 0, 0, S_JETGZOOM1},  // S_JETGZOOM2
-	{SPR_JETG, 2, 1, {A_JetgShoot}, 0, 0, S_JETGSHOOT2}, // S_JETGSHOOT1
-	{SPR_JETG, 3, 1, {NULL}, 0, 0, S_JETGZOOM1},         // S_JETGSHOOT2
+	{SPR_JETG, 0, 4, {A_Look}, 0, 0, S_JETGLOOK2, 0},       // S_JETGLOOK1
+	{SPR_JETG, 1, 4, {A_Look}, 0, 0, S_JETGLOOK1, 0},       // S_JETGLOOK2
+	{SPR_JETG, 0, 1, {A_JetgThink}, 0, 0, S_JETGZOOM2, 0},  // S_JETGZOOM1
+	{SPR_JETG, 1, 1, {A_JetgThink}, 0, 0, S_JETGZOOM1, 0},  // S_JETGZOOM2
+	{SPR_JETG, 2, 1, {A_JetgShoot}, 0, 0, S_JETGSHOOT2, 0}, // S_JETGSHOOT1
+	{SPR_JETG, 3, 1, {NULL}, 0, 0, S_JETGZOOM1, 0},         // S_JETGSHOOT2
 
 	// Crawla Commander
-	{SPR_CCOM, 0, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND2}, // S_CCOMMAND1
-	{SPR_CCOM, 1, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND1}, // S_CCOMMAND2
-	{SPR_CCOM, 2, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND4}, // S_CCOMMAND3
-	{SPR_CCOM, 3, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND3}, // S_CCOMMAND4
+	{SPR_CCOM, 0, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND2, 0}, // S_CCOMMAND1
+	{SPR_CCOM, 1, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND1, 0}, // S_CCOMMAND2
+	{SPR_CCOM, 2, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND4, 0}, // S_CCOMMAND3
+	{SPR_CCOM, 3, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND3, 0}, // S_CCOMMAND4
 
 	// Deton
-	{SPR_DETN, 0, 35, {A_Look}, 0, 0, S_DETON1},       // S_DETON1
-	{SPR_DETN, 0,  1, {A_DetonChase}, 0, 0, S_DETON3},  // S_DETON2
-	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON4},  // S_DETON3
-	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON5},  // S_DETON4
-	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON6},  // S_DETON5
-	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON7},  // S_DETON6
-	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON8},  // S_DETON7
-	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON9},  // S_DETON8
-	{SPR_DETN, 7,  1, {A_DetonChase}, 0, 0, S_DETON10}, // S_DETON9
-	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON11}, // S_DETON10
-	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON12}, // S_DETON11
-	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON13}, // S_DETON12
-	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON14}, // S_DETON13
-	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON15}, // S_DETON14
-	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON2},  // S_DETON15
+	{SPR_DETN, 0, 35, {A_Look}, 0, 0, S_DETON1, 0},       // S_DETON1
+	{SPR_DETN, 0,  1, {A_DetonChase}, 0, 0, S_DETON3, 0},  // S_DETON2
+	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON4, 0},  // S_DETON3
+	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON5, 0},  // S_DETON4
+	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON6, 0},  // S_DETON5
+	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON7, 0},  // S_DETON6
+	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON8, 0},  // S_DETON7
+	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON9, 0},  // S_DETON8
+	{SPR_DETN, 7,  1, {A_DetonChase}, 0, 0, S_DETON10, 0}, // S_DETON9
+	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON11, 0}, // S_DETON10
+	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON12, 0}, // S_DETON11
+	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON13, 0}, // S_DETON12
+	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON14, 0}, // S_DETON13
+	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON15, 0}, // S_DETON14
+	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON2, 0},  // S_DETON15
 
 	// Skim Mine Dropper
-	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM2},    // S_SKIM1
-	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM1},    // S_SKIM2
-	{SPR_SKIM, 0, 14,        {NULL}, 0, 0, S_SKIM4},    // S_SKIM3
-	{SPR_SKIM, 0, 14,  {A_DropMine}, 0, 0, S_SKIM1},    // S_SKIM4
+	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM2, 0},    // S_SKIM1
+	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM1, 0},    // S_SKIM2
+	{SPR_SKIM, 0, 14,        {NULL}, 0, 0, S_SKIM4, 0},    // S_SKIM3
+	{SPR_SKIM, 0, 14,  {A_DropMine}, 0, 0, S_SKIM1, 0},    // S_SKIM4
 
 	// 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_LinedefExecuteFromArg}, 0, 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
-	{SPR_TURR, 1, 2, {A_Pain}, 0, 0, S_TURRETPOPUP2},  // S_TURRETPOPUP1
-	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPUP3},  // S_TURRETPOPUP2
-	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPUP4},  // S_TURRETPOPUP3
-	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPUP5},  // S_TURRETPOPUP4
-	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPUP6},  // S_TURRETPOPUP5
-	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPUP7},  // S_TURRETPOPUP6
-	{SPR_TURR, 7, 2, {NULL}, 0, 0, S_TURRETPOPUP8},  // S_TURRETPOPUP7
-	{SPR_TURR, 8, 14,{NULL}, 0, 0, S_TURRETSHOOT},   // S_TURRETPOPUP8
-	{SPR_TURR, 8, 14,{A_JetgShoot}, 0, 0, S_TURRETPOPDOWN1}, // S_TURRETSHOOT
-	{SPR_TURR, 7, 2, {A_Pain}, 0, 0, S_TURRETPOPDOWN2},        // S_TURRETPOPDOWN1
-	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPDOWN3},        // S_TURRETPOPDOWN2
-	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPDOWN4},        // S_TURRETPOPDOWN3
-	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPDOWN5},        // S_TURRETPOPDOWN4
-	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPDOWN6},        // S_TURRETPOPDOWN5
-	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPDOWN7},        // S_TURRETPOPDOWN6
-	{SPR_TURR, 1, 2, {NULL}, 0, 0, S_TURRETPOPDOWN8},        // S_TURRETPOPDOWN7
-	{SPR_TURR, 0, 69,{A_SetTics}, 0, 1, S_TURRETLOOK},       // S_TURRETPOPDOWN8
+	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretStop}, 0, 0, S_TURRETFIRE, 0},   // S_TURRET
+	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretFire}, 0, 0, S_TURRET, 0},       // S_TURRETFIRE
+	{SPR_TRET, FF_FULLBRIGHT|1, 7, {A_Pain}, 0, 0, S_TURRETSHOCK2, 0},       // S_TURRETSHOCK1
+	{SPR_TRET, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_TURRETSHOCK3, 0},         // S_TURRETSHOCK2
+	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK4, 0},         // S_TURRETSHOCK3
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK5, 0},         // S_TURRETSHOCK4
+	{SPR_TRET, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_TURRETSHOCK6, 0},         // S_TURRETSHOCK5
+	{SPR_TRET, FF_FULLBRIGHT|2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7, 0},       // S_TURRETSHOCK6
+	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK8, 0},         // S_TURRETSHOCK7
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK9, 0},         // S_TURRETSHOCK8
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecuteFromArg}, 0, 0, S_XPLD1, 0}, // S_TURRETSHOCK9
+
+	{SPR_TURR, 0, 1, {A_Look}, 1, 0, S_TURRETPOPDOWN8, 0},          // S_TURRETLOOK
+	{SPR_TURR, 0, 0, {A_FaceTarget}, 0, 0, S_TURRETPOPUP1, 0},  // S_TURRETSEE
+	{SPR_TURR, 1, 2, {A_Pain}, 0, 0, S_TURRETPOPUP2, 0},  // S_TURRETPOPUP1
+	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPUP3, 0},  // S_TURRETPOPUP2
+	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPUP4, 0},  // S_TURRETPOPUP3
+	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPUP5, 0},  // S_TURRETPOPUP4
+	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPUP6, 0},  // S_TURRETPOPUP5
+	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPUP7, 0},  // S_TURRETPOPUP6
+	{SPR_TURR, 7, 2, {NULL}, 0, 0, S_TURRETPOPUP8, 0},  // S_TURRETPOPUP7
+	{SPR_TURR, 8, 14,{NULL}, 0, 0, S_TURRETSHOOT, 0},   // S_TURRETPOPUP8
+	{SPR_TURR, 8, 14,{A_JetgShoot}, 0, 0, S_TURRETPOPDOWN1, 0}, // S_TURRETSHOOT
+	{SPR_TURR, 7, 2, {A_Pain}, 0, 0, S_TURRETPOPDOWN2, 0},        // S_TURRETPOPDOWN1
+	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPDOWN3, 0},        // S_TURRETPOPDOWN2
+	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPDOWN4, 0},        // S_TURRETPOPDOWN3
+	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPDOWN5, 0},        // S_TURRETPOPDOWN4
+	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPDOWN6, 0},        // S_TURRETPOPDOWN5
+	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPDOWN7, 0},        // S_TURRETPOPDOWN6
+	{SPR_TURR, 1, 2, {NULL}, 0, 0, S_TURRETPOPDOWN8, 0},        // S_TURRETPOPDOWN7
+	{SPR_TURR, 0, 69,{A_SetTics}, 0, 1, S_TURRETLOOK, 0},       // S_TURRETPOPDOWN8
 
 	// Spincushion
-	{SPR_SHRP, 0,  2, {A_Look},                 0, 0, S_SPINCUSHION_LOOK},   // S_SPINCUSHION_LOOK
-	{SPR_SHRP, 1,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE2}, // S_SPINCUSHION_CHASE1
-	{SPR_SHRP, 2,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE3}, // S_SPINCUSHION_CHASE2
-	{SPR_SHRP, 3,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE4}, // S_SPINCUSHION_CHASE3
-	{SPR_SHRP, 0,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE1}, // S_SPINCUSHION_CHASE4
-	{SPR_SHRP, 0,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM2},   // S_SPINCUSHION_AIM1
-	{SPR_SHRP, 4,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM3},   // S_SPINCUSHION_AIM2
-	{SPR_SHRP, 5,  2, {A_SetObjectFlags}, MF_PAIN, 2, S_SPINCUSHION_AIM4},   // S_SPINCUSHION_AIM3
-	{SPR_SHRP, 6, 16, {A_MultiShotDist}, (MT_DUST<<16)|6, -32, S_SPINCUSHION_AIM5}, // S_SPINCUSHION_AIM4
-	{SPR_SHRP, 6,  0, {A_PlaySound},   sfx_shrpgo, 1, S_SPINCUSHION_SPIN1},  // S_SPINCUSHION_AIM5
-	{SPR_SHRP, 6,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN2},  // S_SPINCUSHION_SPIN1
-	{SPR_SHRP, 8,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN3},  // S_SPINCUSHION_SPIN2
-	{SPR_SHRP, 7,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN4},  // S_SPINCUSHION_SPIN3
-	{SPR_SHRP, 8,  1, {A_SharpSpin},  MT_SPINDUST, 0, S_SPINCUSHION_SPIN1},  // S_SPINCUSHION_SPIN4
-	{SPR_SHRP, 6,  1, {A_PlaySound},    sfx_s3k69, 1, S_SPINCUSHION_STOP2},  // S_SPINCUSHION_STOP1
-	{SPR_SHRP, 6,  4, {A_SharpDecel},           0, 0, S_SPINCUSHION_STOP2},  // S_SPINCUSHION_STOP2
-	{SPR_SHRP, 5,  4, {A_FaceTarget},           0, 0, S_SPINCUSHION_STOP4},  // S_SPINCUSHION_STOP3
-	{SPR_SHRP, 4,  4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK},   // S_SPINCUSHION_STOP4
+	{SPR_SHRP, 0,  2, {A_Look},                 0, 0, S_SPINCUSHION_LOOK, 0},   // S_SPINCUSHION_LOOK
+	{SPR_SHRP, 1,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE2, 0}, // S_SPINCUSHION_CHASE1
+	{SPR_SHRP, 2,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE3, 0}, // S_SPINCUSHION_CHASE2
+	{SPR_SHRP, 3,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE4, 0}, // S_SPINCUSHION_CHASE3
+	{SPR_SHRP, 0,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE1, 0}, // S_SPINCUSHION_CHASE4
+	{SPR_SHRP, 0,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM2, 0},   // S_SPINCUSHION_AIM1
+	{SPR_SHRP, 4,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM3, 0},   // S_SPINCUSHION_AIM2
+	{SPR_SHRP, 5,  2, {A_SetObjectFlags}, MF_PAIN, 2, S_SPINCUSHION_AIM4, 0},   // S_SPINCUSHION_AIM3
+	{SPR_SHRP, 6, 16, {A_MultiShotDist}, (MT_DUST<<16)|6, -32, S_SPINCUSHION_AIM5, 0}, // S_SPINCUSHION_AIM4
+	{SPR_SHRP, 6,  0, {A_PlaySound},   sfx_shrpgo, 1, S_SPINCUSHION_SPIN1, 0},  // S_SPINCUSHION_AIM5
+	{SPR_SHRP, 6,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN2, 0},  // S_SPINCUSHION_SPIN1
+	{SPR_SHRP, 8,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN3, 0},  // S_SPINCUSHION_SPIN2
+	{SPR_SHRP, 7,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN4, 0},  // S_SPINCUSHION_SPIN3
+	{SPR_SHRP, 8,  1, {A_SharpSpin},  MT_SPINDUST, 0, S_SPINCUSHION_SPIN1, 0},  // S_SPINCUSHION_SPIN4
+	{SPR_SHRP, 6,  1, {A_PlaySound},    sfx_s3k69, 1, S_SPINCUSHION_STOP2, 0},  // S_SPINCUSHION_STOP1
+	{SPR_SHRP, 6,  4, {A_SharpDecel},           0, 0, S_SPINCUSHION_STOP2, 0},  // S_SPINCUSHION_STOP2
+	{SPR_SHRP, 5,  4, {A_FaceTarget},           0, 0, S_SPINCUSHION_STOP4, 0},  // S_SPINCUSHION_STOP3
+	{SPR_SHRP, 4,  4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK, 0},   // S_SPINCUSHION_STOP4
 
 	// Crushstacean
-	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2},     // S_CRUSHSTACEAN_ROAM1
-	{SPR_CRAB, 1,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3},     // S_CRUSHSTACEAN_ROAM2
-	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4},     // S_CRUSHSTACEAN_ROAM3
-	{SPR_CRAB, 2,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1},     // S_CRUSHSTACEAN_ROAM4
-	{SPR_CRAB, 0, 40, {NULL},                0,                        0, S_CRUSHSTACEAN_ROAM1},     // S_CRUSHSTACEAN_ROAMPAUSE
-	{SPR_CRAB, 0, 10, {NULL},                0,                        0, S_CRUSHSTACEAN_PUNCH2},    // S_CRUSHSTACEAN_PUNCH1
-	{SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0,                        0, S_CRUSHSTACEAN_ROAMPAUSE}, // S_CRUSHSTACEAN_PUNCH2
-	{SPR_CRAB, 3,  1, {A_CrushclawAim},   40,               20, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_AIM
-	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 0, S_CRUSHCLAW_STAY, S_CRUSHCLAW_OUT}, // S_CRUSHCLAW_OUT
-	{SPR_CRAB, 3, 10, {NULL},              0,                0, S_CRUSHCLAW_IN},  // S_CRUSHCLAW_STAY
-	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN},  // S_CRUSHCLAW_IN
-	{SPR_CRAB, 3, 37, {NULL},              0,                0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_WAIT
-	{SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CRUSHCHAIN
+	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2, 0},     // S_CRUSHSTACEAN_ROAM1
+	{SPR_CRAB, 1,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3, 0},     // S_CRUSHSTACEAN_ROAM2
+	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4, 0},     // S_CRUSHSTACEAN_ROAM3
+	{SPR_CRAB, 2,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1, 0},     // S_CRUSHSTACEAN_ROAM4
+	{SPR_CRAB, 0, 40, {NULL},                0,                        0, S_CRUSHSTACEAN_ROAM1, 0},     // S_CRUSHSTACEAN_ROAMPAUSE
+	{SPR_CRAB, 0, 10, {NULL},                0,                        0, S_CRUSHSTACEAN_PUNCH2, 0},    // S_CRUSHSTACEAN_PUNCH1
+	{SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0,                        0, S_CRUSHSTACEAN_ROAMPAUSE, 0}, // S_CRUSHSTACEAN_PUNCH2
+	{SPR_CRAB, 3,  1, {A_CrushclawAim},   40,               20, S_CRUSHCLAW_AIM, 0}, // S_CRUSHCLAW_AIM
+	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 0, S_CRUSHCLAW_STAY, S_CRUSHCLAW_OUT, 0}, // S_CRUSHCLAW_OUT
+	{SPR_CRAB, 3, 10, {NULL},              0,                0, S_CRUSHCLAW_IN, 0},  // S_CRUSHCLAW_STAY
+	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN, 0},  // S_CRUSHCLAW_IN
+	{SPR_CRAB, 3, 37, {NULL},              0,                0, S_CRUSHCLAW_AIM, 0}, // S_CRUSHCLAW_WAIT
+	{SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CRUSHCHAIN
 
 	// Banpyura
-	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM2}, // S_BANPYURA_ROAM1
-	{SPR_CR2B, 1,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM3}, // S_BANPYURA_ROAM2
-	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM4}, // S_BANPYURA_ROAM3
-	{SPR_CR2B, 2,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM1}, // S_BANPYURA_ROAM4
-	{SPR_CR2B, 0, 40, {NULL},                0,                    0, S_BANPYURA_ROAM1}, // S_BANPYURA_ROAMPAUSE
-
-	{SPR_CSPR, 0, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1}, // S_CDIAG1
-	{SPR_CSPR, 1, 1, {A_Pain},          0,  0, S_CDIAG3}, // S_CDIAG2
-	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG4}, // S_CDIAG3
-	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG5}, // S_CDIAG4
-	{SPR_CSPR, 4, 1, {A_CrushclawAim}, 50, 20, S_CDIAG6}, // S_CDIAG5
-	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG7}, // S_CDIAG6
-	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG8}, // S_CDIAG7
-	{SPR_CSPR, 1, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1}, // S_CDIAG8
+	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM2, 0}, // S_BANPYURA_ROAM1
+	{SPR_CR2B, 1,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM3, 0}, // S_BANPYURA_ROAM2
+	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM4, 0}, // S_BANPYURA_ROAM3
+	{SPR_CR2B, 2,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM1, 0}, // S_BANPYURA_ROAM4
+	{SPR_CR2B, 0, 40, {NULL},                0,                    0, S_BANPYURA_ROAM1, 0}, // S_BANPYURA_ROAMPAUSE
+
+	{SPR_CSPR, 0, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1, 0}, // S_CDIAG1
+	{SPR_CSPR, 1, 1, {A_Pain},          0,  0, S_CDIAG3, 0}, // S_CDIAG2
+	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG4, 0}, // S_CDIAG3
+	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG5, 0}, // S_CDIAG4
+	{SPR_CSPR, 4, 1, {A_CrushclawAim}, 50, 20, S_CDIAG6, 0}, // S_CDIAG5
+	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG7, 0}, // S_CDIAG6
+	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG8, 0}, // S_CDIAG7
+	{SPR_CSPR, 1, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1, 0}, // S_CDIAG8
 
 	// Jet Jaw
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM2}, // S_JETJAW_ROAM1
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM3}, // S_JETJAW_ROAM2
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM4}, // S_JETJAW_ROAM3
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM5}, // S_JETJAW_ROAM4
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM6}, // S_JETJAW_ROAM5
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM7}, // S_JETJAW_ROAM6
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM8}, // S_JETJAW_ROAM7
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM1}, // S_JETJAW_ROAM8
-	{SPR_JJAW, 0, 1, {A_DualAction}, S_JETJAW_CHOMP16, S_JETJAW_SOUND,  S_JETJAW_CHOMP2}, // S_JETJAW_CHOMP1
-	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP3}, // S_JETJAW_CHOMP2
-	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP4}, // S_JETJAW_CHOMP3
-	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP5}, // S_JETJAW_CHOMP4
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP6}, // S_JETJAW_CHOMP5
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP7}, // S_JETJAW_CHOMP6
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP8}, // S_JETJAW_CHOMP7
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP9}, // S_JETJAW_CHOMP8
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP10}, // S_JETJAW_CHOMP9
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP11}, // S_JETJAW_CHOMP10
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP12}, // S_JETJAW_CHOMP11
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP13}, // S_JETJAW_CHOMP12
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP14}, // S_JETJAW_CHOMP13
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP15}, // S_JETJAW_CHOMP14
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP16}, // S_JETJAW_CHOMP15
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP1}, // S_JETJAW_CHOMP16
-	{SPR_JJAW, 0, 1, {A_PlayAttackSound},          0,               0,   S_JETJAW_SOUND}, // S_JETJAW_SOUND
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM2, 0}, // S_JETJAW_ROAM1
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM3, 0}, // S_JETJAW_ROAM2
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM4, 0}, // S_JETJAW_ROAM3
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM5, 0}, // S_JETJAW_ROAM4
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM6, 0}, // S_JETJAW_ROAM5
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM7, 0}, // S_JETJAW_ROAM6
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM8, 0}, // S_JETJAW_ROAM7
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM1, 0}, // S_JETJAW_ROAM8
+	{SPR_JJAW, 0, 1, {A_DualAction}, S_JETJAW_CHOMP16, S_JETJAW_SOUND,  S_JETJAW_CHOMP2, 0}, // S_JETJAW_CHOMP1
+	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP3, 0}, // S_JETJAW_CHOMP2
+	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP4, 0}, // S_JETJAW_CHOMP3
+	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP5, 0}, // S_JETJAW_CHOMP4
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP6, 0}, // S_JETJAW_CHOMP5
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP7, 0}, // S_JETJAW_CHOMP6
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP8, 0}, // S_JETJAW_CHOMP7
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP9, 0}, // S_JETJAW_CHOMP8
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP10, 0}, // S_JETJAW_CHOMP9
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP11, 0}, // S_JETJAW_CHOMP10
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP12, 0}, // S_JETJAW_CHOMP11
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP13, 0}, // S_JETJAW_CHOMP12
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP14, 0}, // S_JETJAW_CHOMP13
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP15, 0}, // S_JETJAW_CHOMP14
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP16, 0}, // S_JETJAW_CHOMP15
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP1, 0}, // S_JETJAW_CHOMP16
+	{SPR_JJAW, 0, 1, {A_PlayAttackSound},          0,               0,   S_JETJAW_SOUND, 0}, // S_JETJAW_SOUND
 
 	// Snailer
-	{SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1}, // S_SNAILER1
-	{SPR_BOM1, 0, 0, {A_FlickySpawn}, 1<<17, 0, S_XPLD1}, // S_SNAILER_FLICKY
+	{SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1, 0}, // S_SNAILER1
+	{SPR_BOM1, 0, 0, {A_FlickySpawn}, 1<<17, 0, S_XPLD1, 0}, // S_SNAILER_FLICKY
 
 	// Vulture
-	{SPR_VLTR, 4, 35,        {A_Look},         1, 0, S_VULTURE_STND},  // S_VULTURE_STND
-	{SPR_VLTR, 4, 3,         {A_VultureHover}, 0, 0, S_VULTURE_DRIFT}, // S_VULTURE_DRIFT
-	{SPR_VLTR, 0, 6,         {A_VultureBlast}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM1
-	{SPR_VLTR, 0, 3,         {A_VultureFly},   0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM2
-	{SPR_VLTR, 0, 3*TICRATE, {NULL},           0, 0, S_VULTURE_DRIFT}, // S_VULTURE_STUNNED
+	{SPR_VLTR, 4, 35,        {A_Look},         1, 0, S_VULTURE_STND, 0},  // S_VULTURE_STND
+	{SPR_VLTR, 4, 3,         {A_VultureHover}, 0, 0, S_VULTURE_DRIFT, 0}, // S_VULTURE_DRIFT
+	{SPR_VLTR, 0, 6,         {A_VultureBlast}, 0, 0, S_VULTURE_ZOOM2, 0}, // S_VULTURE_ZOOM1
+	{SPR_VLTR, 0, 3,         {A_VultureFly},   0, 0, S_VULTURE_ZOOM2, 0}, // S_VULTURE_ZOOM2
+	{SPR_VLTR, 0, 3*TICRATE, {NULL},           0, 0, S_VULTURE_DRIFT, 0}, // S_VULTURE_STUNNED
 
 	// Pointy
-	{SPR_PNTY, 0,  1, {A_PointyThink}, 0, 0, S_POINTY1}, // S_POINTY1
+	{SPR_PNTY, 0,  1, {A_PointyThink}, 0, 0, S_POINTY1, 0}, // S_POINTY1
 
 	// Pointy Ball
-	{SPR_PNTY, 1,  1, {A_CheckBuddy}, 0, 0, S_POINTYBALL1}, // S_POINTYBALL1
+	{SPR_PNTY, 1,  1, {A_CheckBuddy}, 0, 0, S_POINTYBALL1, 0}, // S_POINTYBALL1
 
 	// Robo-Hood
-	{SPR_ARCH, 0,       4,            {A_Look}, 2048<<FRACBITS,   0, S_ROBOHOOD_LOOK},  // S_ROBOHOOD_LOOK
-	{SPR_ARCH, 0,       1,       {A_HoodThink},              0,   0, S_ROBOHOOD_STAND}, // S_ROBOHOOD_STAND
-	{SPR_ARCH, 2, TICRATE, {A_PlayActiveSound},              0,   0, S_ROBOHOOD_FIRE2}, // S_ROBOHOOD_FIRE1
-	{SPR_ARCH, 2,      20,        {A_HoodFire},       MT_ARROW,   0, S_ROBOHOOD_STAND}, // S_ROBOHOOD_FIRE2
-	{SPR_ARCH, 1,       1,      {A_FaceTarget},              0,   0, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP1
-	{SPR_ARCH, 1,       1,        {A_BunnyHop},              4, -10, S_ROBOHOOD_JUMP3}, // S_ROBOHOOD_JUMP2
-	{SPR_ARCH, 1,       1,        {A_HoodFall},              0,   0, S_ROBOHOOD_JUMP3}, // S_ROBOHOOD_JUMP3
+	{SPR_ARCH, 0,       4,            {A_Look}, 2048<<FRACBITS,   0, S_ROBOHOOD_LOOK, 0},  // S_ROBOHOOD_LOOK
+	{SPR_ARCH, 0,       1,       {A_HoodThink},              0,   0, S_ROBOHOOD_STAND, 0}, // S_ROBOHOOD_STAND
+	{SPR_ARCH, 2, TICRATE, {A_PlayActiveSound},              0,   0, S_ROBOHOOD_FIRE2, 0}, // S_ROBOHOOD_FIRE1
+	{SPR_ARCH, 2,      20,        {A_HoodFire},       MT_ARROW,   0, S_ROBOHOOD_STAND, 0}, // S_ROBOHOOD_FIRE2
+	{SPR_ARCH, 1,       1,      {A_FaceTarget},              0,   0, S_ROBOHOOD_JUMP2, 0}, // S_ROBOHOOD_JUMP1
+	{SPR_ARCH, 1,       1,        {A_BunnyHop},              4, -10, S_ROBOHOOD_JUMP3, 0}, // S_ROBOHOOD_JUMP2
+	{SPR_ARCH, 1,       1,        {A_HoodFall},              0,   0, S_ROBOHOOD_JUMP3, 0}, // S_ROBOHOOD_JUMP3
 
 	// Castlebot Facestabber
-	{SPR_CBFS, 0,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND2},   // S_FACESTABBER_STND1
-	{SPR_CBFS, 1,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND3},   // S_FACESTABBER_STND2
-	{SPR_CBFS, 2,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND4},   // S_FACESTABBER_STND3
-	{SPR_CBFS, 3,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND5},   // S_FACESTABBER_STND4
-	{SPR_CBFS, 4,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND6},   // S_FACESTABBER_STND5
-	{SPR_CBFS, 5,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND1},   // S_FACESTABBER_STND6
-	{SPR_CBFS, 0,  1,  {A_FaceStabRev},                  20, S_FACESTABBER_CHARGE2, S_FACESTABBER_CHARGE1}, // S_FACESTABBER_CHARGE1
-	{SPR_CBFS, 0,  0,   {A_FaceTarget},                   0,                     0, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE2
-	{SPR_CBFS, 7,  1, {A_FaceStabHurl},                   6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE3
-	{SPR_CBFS, 7,  1, {A_FaceStabMiss}, 0,   S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE4
-	{SPR_CBFS, 0, 35,         {A_Pain}, 0,                     0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN
-	{SPR_CBFS, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE2},  // S_FACESTABBER_DIE1
-	{SPR_NULL, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE3},  // S_FACESTABBER_DIE2
-	{SPR_NULL, 0,  0,       {A_Repeat}, 7, S_FACESTABBER_DIE1,    S_XPLD_FLICKY},       // S_FACESTABBER_DIE3
-
-	{SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSPEAR
+	{SPR_CBFS, 0,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND2, 0},   // S_FACESTABBER_STND1
+	{SPR_CBFS, 1,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND3, 0},   // S_FACESTABBER_STND2
+	{SPR_CBFS, 2,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND4, 0},   // S_FACESTABBER_STND3
+	{SPR_CBFS, 3,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND5, 0},   // S_FACESTABBER_STND4
+	{SPR_CBFS, 4,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND6, 0},   // S_FACESTABBER_STND5
+	{SPR_CBFS, 5,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND1, 0},   // S_FACESTABBER_STND6
+	{SPR_CBFS, 0,  1,  {A_FaceStabRev},                  20, S_FACESTABBER_CHARGE2, S_FACESTABBER_CHARGE1, 0}, // S_FACESTABBER_CHARGE1
+	{SPR_CBFS, 0,  0,   {A_FaceTarget},                   0,                     0, S_FACESTABBER_CHARGE3, 0}, // S_FACESTABBER_CHARGE2
+	{SPR_CBFS, 7,  1, {A_FaceStabHurl},                   6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3, 0}, // S_FACESTABBER_CHARGE3
+	{SPR_CBFS, 7,  1, {A_FaceStabMiss}, 0,   S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4, 0}, // S_FACESTABBER_CHARGE4
+	{SPR_CBFS, 0, 35,         {A_Pain}, 0,                     0, S_FACESTABBER_STND1, 0}, // S_FACESTABBER_PAIN
+	{SPR_CBFS, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE2, 0},  // S_FACESTABBER_DIE1
+	{SPR_NULL, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE3, 0},  // S_FACESTABBER_DIE2
+	{SPR_NULL, 0,  0,       {A_Repeat}, 7, S_FACESTABBER_DIE1,    S_XPLD_FLICKY, 0},       // S_FACESTABBER_DIE3
+
+	{SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FACESTABBERSPEAR
 
 	// Egg Guard
-	{SPR_SPSH,  0,  1,       {A_Look}, 0, 0, S_EGGGUARD_STND},  // S_EGGGUARD_STND
-	{SPR_SPSH,  1,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK2}, // S_EGGGUARD_WALK1
-	{SPR_SPSH,  2,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK3}, // S_EGGGUARD_WALK2
-	{SPR_SPSH,  3,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK4}, // S_EGGGUARD_WALK3
-	{SPR_SPSH,  4,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK1}, // S_EGGGUARD_WALK4
-	{SPR_SPSH,  5,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD2},  // S_EGGGUARD_MAD1
-	{SPR_SPSH,  6,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD3},  // S_EGGGUARD_MAD2
-	{SPR_SPSH,  7, 15,         {NULL}, 0, 0, S_EGGGUARD_RUN1},  // S_EGGGUARD_MAD3
-	{SPR_SPSH,  8,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN2},  // S_EGGGUARD_RUN1
-	{SPR_SPSH,  9,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN3},  // S_EGGGUARD_RUN2
-	{SPR_SPSH, 10,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN4},  // S_EGGGUARD_RUN3
-	{SPR_SPSH, 11,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN1},  // S_EGGGUARD_RUN4
-
-	{SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD},  // S_EGGSHIELD
-	{SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_EGGSHIELDBREAK
+	{SPR_SPSH,  0,  1,       {A_Look}, 0, 0, S_EGGGUARD_STND, 0},  // S_EGGGUARD_STND
+	{SPR_SPSH,  1,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK2, 0}, // S_EGGGUARD_WALK1
+	{SPR_SPSH,  2,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK3, 0}, // S_EGGGUARD_WALK2
+	{SPR_SPSH,  3,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK4, 0}, // S_EGGGUARD_WALK3
+	{SPR_SPSH,  4,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK1, 0}, // S_EGGGUARD_WALK4
+	{SPR_SPSH,  5,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD2, 0},  // S_EGGGUARD_MAD1
+	{SPR_SPSH,  6,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD3, 0},  // S_EGGGUARD_MAD2
+	{SPR_SPSH,  7, 15,         {NULL}, 0, 0, S_EGGGUARD_RUN1, 0},  // S_EGGGUARD_MAD3
+	{SPR_SPSH,  8,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN2, 0},  // S_EGGGUARD_RUN1
+	{SPR_SPSH,  9,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN3, 0},  // S_EGGGUARD_RUN2
+	{SPR_SPSH, 10,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN4, 0},  // S_EGGGUARD_RUN3
+	{SPR_SPSH, 11,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN1, 0},  // S_EGGGUARD_RUN4
+
+	{SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD, 0},  // S_EGGSHIELD
+	{SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL, 0}, // S_EGGSHIELDBREAK
 
 	// Green Snapper
-	{SPR_GSNP, 0, TICRATE, {NULL},             0,              0,               S_SNAPPER_SPAWN2}, // S_SNAPPER_SPAWN
-	{SPR_GSNP, 0, 2,       {A_SnapperSpawn},   MT_SNAPPER_LEG, MT_SNAPPER_HEAD, S_GSNAPPER_STND},  // S_SNAPPER_SPAWN2
-	{SPR_GSNP, 0, 1,       {A_SnapperThinker}, 0,              0,               S_GSNAPPER_STND},  // S_GSNAPPER_STND
-	{SPR_GSNP, 0, 2,       {A_Chase},          0,              0,               S_GSNAPPER2},      // S_GSNAPPER1
-	{SPR_GSNP, 1, 2,       {A_Chase},          0,              0,               S_GSNAPPER3},      // S_GSNAPPER2
-	{SPR_GSNP, 2, 2,       {A_Chase},          0,              0,               S_GSNAPPER4},      // S_GSNAPPER3
-	{SPR_GSNP, 3, 2,       {A_Chase},          0,              0,               S_GSNAPPER1},      // S_GSNAPPER4
-	{SPR_GSNP, 0, 0,       {A_KillSegments},   0,              0,               S_XPLD_FLICKY},    // S_SNAPPER_XPLD
-	{SPR_GSNL, 0, -1,      {NULL},             0,              0,               S_NULL},           // S_SNAPPER_LEG
-	{SPR_GSNL, 1, -1,      {NULL},             0,              0,               S_NULL},           // S_SNAPPER_LEGRAISE
-	{SPR_GSNH, 0, -1,      {NULL},             0,              0,               S_NULL},           // S_SNAPPER_HEAD
+	{SPR_GSNP, 0, TICRATE, {NULL},             0,              0,               S_SNAPPER_SPAWN2, 0}, // S_SNAPPER_SPAWN
+	{SPR_GSNP, 0, 2,       {A_SnapperSpawn},   MT_SNAPPER_LEG, MT_SNAPPER_HEAD, S_GSNAPPER_STND, 0},  // S_SNAPPER_SPAWN2
+	{SPR_GSNP, 0, 1,       {A_SnapperThinker}, 0,              0,               S_GSNAPPER_STND, 0},  // S_GSNAPPER_STND
+	{SPR_GSNP, 0, 2,       {A_Chase},          0,              0,               S_GSNAPPER2, 0},      // S_GSNAPPER1
+	{SPR_GSNP, 1, 2,       {A_Chase},          0,              0,               S_GSNAPPER3, 0},      // S_GSNAPPER2
+	{SPR_GSNP, 2, 2,       {A_Chase},          0,              0,               S_GSNAPPER4, 0},      // S_GSNAPPER3
+	{SPR_GSNP, 3, 2,       {A_Chase},          0,              0,               S_GSNAPPER1, 0},      // S_GSNAPPER4
+	{SPR_GSNP, 0, 0,       {A_KillSegments},   0,              0,               S_XPLD_FLICKY, 0},    // S_SNAPPER_XPLD
+	{SPR_GSNL, 0, -1,      {NULL},             0,              0,               S_NULL, 0},           // S_SNAPPER_LEG
+	{SPR_GSNL, 1, -1,      {NULL},             0,              0,               S_NULL, 0},           // S_SNAPPER_LEGRAISE
+	{SPR_GSNH, 0, -1,      {NULL},             0,              0,               S_NULL, 0},           // S_SNAPPER_HEAD
 
 	// Minus
-	{SPR_MNUD, 0,            1,  {NULL},           0, 0, S_MINUS_STND},     // S_MINUS_INIT (required for objectplace to work)
-	{SPR_NULL, 0,            10, {A_Look},         0, 0, S_MINUS_STND},     // S_MINUS_STND
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 1, 0, S_MINUS_DIGGING2}, // S_MINUS_DIGGING1
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING3}, // S_MINUS_DIGGING2
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING4}, // S_MINUS_DIGGING3
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING1}, // S_MINUS_DIGGING4
-	{SPR_NULL, 0,            25, {NULL},           0, 0, S_MINUS_POPUP},    // S_MINUS_BURST0
-	{SPR_MNUD, FF_ANIMATE,   5,  {NULL},           1, 2, S_MINUS_BURST2},   // S_MINUS_BURST1
-	{SPR_MNUD, 1|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST3},   // S_MINUS_BURST2
-	{SPR_MNUD, 2|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST4},   // S_MINUS_BURST3
-	{SPR_MNUD, 3|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST5},   // S_MINUS_BURST4
-	{SPR_MNUD, 4|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUSDIRT2},     // S_MINUS_BURST5
-	{SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1}, // S_MINUS_POPUP
-	{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2},   // S_MINUS_AERIAL1
-	{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3},   // S_MINUS_AERIAL2
-	{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4},   // S_MINUS_AERIAL3
-	{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1},   // S_MINUS_AERIAL4
-
-	{SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1
-	{SPR_MNUD, 5,          8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2
-	{SPR_MNUD, 4,          8, {NULL}, 3, 5, S_MINUSDIRT4}, // S_MINUSDIRT3
-	{SPR_MNUD, 3,          8, {NULL}, 3, 5, S_MINUSDIRT5}, // S_MINUSDIRT4
-	{SPR_MNUD, 2,          8, {NULL}, 3, 5, S_MINUSDIRT6}, // S_MINUSDIRT5
-	{SPR_MNUD, 1,          8, {NULL}, 3, 5, S_MINUSDIRT7}, // S_MINUSDIRT6
-	{SPR_MNUD, 0,          8, {NULL}, 3, 5, S_NULL},       // S_MINUSDIRT7
+	{SPR_MNUD, 0,            1,  {NULL},           0, 0, S_MINUS_STND, 0},     // S_MINUS_INIT (required for objectplace to work)
+	{SPR_NULL, 0,            10, {A_Look},         0, 0, S_MINUS_STND, 0},     // S_MINUS_STND
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 1, 0, S_MINUS_DIGGING2, 0}, // S_MINUS_DIGGING1
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING3, 0}, // S_MINUS_DIGGING2
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING4, 0}, // S_MINUS_DIGGING3
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING1, 0}, // S_MINUS_DIGGING4
+	{SPR_NULL, 0,            25, {NULL},           0, 0, S_MINUS_POPUP, 0},    // S_MINUS_BURST0
+	{SPR_MNUD, FF_ANIMATE,   5,  {NULL},           1, 2, S_MINUS_BURST2, 0},   // S_MINUS_BURST1
+	{SPR_MNUD, 1|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST3, 0},   // S_MINUS_BURST2
+	{SPR_MNUD, 2|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST4, 0},   // S_MINUS_BURST3
+	{SPR_MNUD, 3|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST5, 0},   // S_MINUS_BURST4
+	{SPR_MNUD, 4|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUSDIRT2, 0},     // S_MINUS_BURST5
+	{SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1, 0}, // S_MINUS_POPUP
+	{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2, 0},   // S_MINUS_AERIAL1
+	{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3, 0},   // S_MINUS_AERIAL2
+	{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4, 0},   // S_MINUS_AERIAL3
+	{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1, 0},   // S_MINUS_AERIAL4
+
+	{SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2, 0}, // S_MINUSDIRT1
+	{SPR_MNUD, 5,          8, {NULL}, 3, 5, S_MINUSDIRT3, 0}, // S_MINUSDIRT2
+	{SPR_MNUD, 4,          8, {NULL}, 3, 5, S_MINUSDIRT4, 0}, // S_MINUSDIRT3
+	{SPR_MNUD, 3,          8, {NULL}, 3, 5, S_MINUSDIRT5, 0}, // S_MINUSDIRT4
+	{SPR_MNUD, 2,          8, {NULL}, 3, 5, S_MINUSDIRT6, 0}, // S_MINUSDIRT5
+	{SPR_MNUD, 1,          8, {NULL}, 3, 5, S_MINUSDIRT7, 0}, // S_MINUSDIRT6
+	{SPR_MNUD, 0,          8, {NULL}, 3, 5, S_NULL, 0},       // S_MINUSDIRT7
 
 	// Spring Shell
-	{SPR_SSHL,  0,  4, {A_Look},  0, 0, S_SSHELL_STND},    // S_SSHELL_STND
-	{SPR_SSHL,  0,  4, {A_Chase}, 0, 0, S_SSHELL_RUN2},    // S_SSHELL_RUN1
-	{SPR_SSHL,  1,  4, {A_Chase}, 0, 0, S_SSHELL_RUN3},    // S_SSHELL_RUN2
-	{SPR_SSHL,  2,  4, {A_Chase}, 0, 0, S_SSHELL_RUN4},    // S_SSHELL_RUN3
-	{SPR_SSHL,  3,  4, {A_Chase}, 0, 0, S_SSHELL_RUN1},    // S_SSHELL_RUN4
-	{SPR_SSHL,  7,  4, {A_Pain},  0, 0, S_SSHELL_SPRING2}, // S_SSHELL_SPRING1
-	{SPR_SSHL,  6,  1, {NULL},    0, 0, S_SSHELL_SPRING3}, // S_SSHELL_SPRING2
-	{SPR_SSHL,  5,  1, {NULL},    0, 0, S_SSHELL_SPRING4}, // S_SSHELL_SPRING3
-	{SPR_SSHL,  4,  1, {NULL},    0, 0, S_SSHELL_RUN1},    // S_SSHELL_SPRING4
+	{SPR_SSHL,  0,  4, {A_Look},  0, 0, S_SSHELL_STND, 0},    // S_SSHELL_STND
+	{SPR_SSHL,  0,  4, {A_Chase}, 0, 0, S_SSHELL_RUN2, 0},    // S_SSHELL_RUN1
+	{SPR_SSHL,  1,  4, {A_Chase}, 0, 0, S_SSHELL_RUN3, 0},    // S_SSHELL_RUN2
+	{SPR_SSHL,  2,  4, {A_Chase}, 0, 0, S_SSHELL_RUN4, 0},    // S_SSHELL_RUN3
+	{SPR_SSHL,  3,  4, {A_Chase}, 0, 0, S_SSHELL_RUN1, 0},    // S_SSHELL_RUN4
+	{SPR_SSHL,  7,  4, {A_Pain},  0, 0, S_SSHELL_SPRING2, 0}, // S_SSHELL_SPRING1
+	{SPR_SSHL,  6,  1, {NULL},    0, 0, S_SSHELL_SPRING3, 0}, // S_SSHELL_SPRING2
+	{SPR_SSHL,  5,  1, {NULL},    0, 0, S_SSHELL_SPRING4, 0}, // S_SSHELL_SPRING3
+	{SPR_SSHL,  4,  1, {NULL},    0, 0, S_SSHELL_RUN1, 0},    // S_SSHELL_SPRING4
 
 	// Spring Shell (yellow)
-	{SPR_SSHL,  8,  4, {A_Look},  0, 0, S_YSHELL_STND},    // S_YSHELL_STND
-	{SPR_SSHL,  8,  4, {A_Chase}, 0, 0, S_YSHELL_RUN2},    // S_YSHELL_RUN1
-	{SPR_SSHL,  9,  4, {A_Chase}, 0, 0, S_YSHELL_RUN3},    // S_YSHELL_RUN2
-	{SPR_SSHL, 10,  4, {A_Chase}, 0, 0, S_YSHELL_RUN4},    // S_YSHELL_RUN3
-	{SPR_SSHL, 11,  4, {A_Chase}, 0, 0, S_YSHELL_RUN1},    // S_YSHELL_RUN4
-	{SPR_SSHL, 15,  4, {A_Pain},  0, 0, S_YSHELL_SPRING2}, // S_YSHELL_SPRING1
-	{SPR_SSHL, 14,  1, {NULL},    0, 0, S_YSHELL_SPRING3}, // S_YSHELL_SPRING2
-	{SPR_SSHL, 13,  1, {NULL},    0, 0, S_YSHELL_SPRING4}, // S_YSHELL_SPRING3
-	{SPR_SSHL, 12,  1, {NULL},    0, 0, S_YSHELL_RUN1},    // S_YSHELL_SPRING4
+	{SPR_SSHL,  8,  4, {A_Look},  0, 0, S_YSHELL_STND, 0},    // S_YSHELL_STND
+	{SPR_SSHL,  8,  4, {A_Chase}, 0, 0, S_YSHELL_RUN2, 0},    // S_YSHELL_RUN1
+	{SPR_SSHL,  9,  4, {A_Chase}, 0, 0, S_YSHELL_RUN3, 0},    // S_YSHELL_RUN2
+	{SPR_SSHL, 10,  4, {A_Chase}, 0, 0, S_YSHELL_RUN4, 0},    // S_YSHELL_RUN3
+	{SPR_SSHL, 11,  4, {A_Chase}, 0, 0, S_YSHELL_RUN1, 0},    // S_YSHELL_RUN4
+	{SPR_SSHL, 15,  4, {A_Pain},  0, 0, S_YSHELL_SPRING2, 0}, // S_YSHELL_SPRING1
+	{SPR_SSHL, 14,  1, {NULL},    0, 0, S_YSHELL_SPRING3, 0}, // S_YSHELL_SPRING2
+	{SPR_SSHL, 13,  1, {NULL},    0, 0, S_YSHELL_SPRING4, 0}, // S_YSHELL_SPRING3
+	{SPR_SSHL, 12,  1, {NULL},    0, 0, S_YSHELL_RUN1, 0},    // S_YSHELL_SPRING4
 
 	// Unidus
-	{SPR_UNID, 0, 4, {A_Look},       0, 0, S_UNIDUS_STND}, // S_UNIDUS_STND
-	{SPR_UNID, 0, 1, {A_Chase},      0, 0, S_UNIDUS_RUN }, // S_UNIDUS_RUN
-	{SPR_UNID, 1, 1, {A_UnidusBall}, 1, 0, S_UNIDUS_BALL}, // S_UNIDUS_BALL
+	{SPR_UNID, 0, 4, {A_Look},       0, 0, S_UNIDUS_STND, 0}, // S_UNIDUS_STND
+	{SPR_UNID, 0, 1, {A_Chase},      0, 0, S_UNIDUS_RUN , 0}, // S_UNIDUS_RUN
+	{SPR_UNID, 1, 1, {A_UnidusBall}, 1, 0, S_UNIDUS_BALL, 0}, // S_UNIDUS_BALL
 
 	// Canarivore
-	{SPR_CANA, 0, 5,  {A_Look},          1200*FRACUNIT+1,   1,                 S_CANARIVORE_LOOK},      // S_CANARIVORE_LOOK
-	{SPR_CANA, 0, 3,  {A_PlaySound},     sfx_s3k76,         1,                 S_CANARIVORE_AWAKEN2},   // S_CANARIVORE_AWAKEN1
-	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_AWAKEN3},   // S_CANARIVORE_AWAKEN2
-	{SPR_CANA, 2, 8,  {NULL},            0,                 0,                 S_CANARIVORE_GAS1},      // S_CANARIVORE_AWAKEN3
-	{SPR_CANA, 2, 15, {A_PlaySound},     sfx_s3k93,         1,                 S_CANARIVORE_GAS2},      // S_CANARIVORE_GAS1
-	{SPR_CANA, 1, 4,  {NULL},            0,                 0,                 S_CANARIVORE_GAS3},      // S_CANARIVORE_GAS2
-	{SPR_CANA, 2, 0,  {A_PlaySound},     sfx_s3k97,         1,                 S_CANARIVORE_GAS4},      // S_CANARIVORE_GAS3
-	{SPR_CANA, 2, 5,  {A_CanarivoreGas}, MT_CANARIVORE_GAS, 0,                 S_CANARIVORE_GAS5},      // S_CANARIVORE_GAS4
-	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_GASREPEAT}, // S_CANARIVORE_GAS5
-	{SPR_CANA, 2, 0,  {A_Repeat},        6,                 S_CANARIVORE_GAS4, S_CANARIVORE_CLOSE1},    // S_CANARIVORE_GASREPEAT
-	{SPR_CANA, 1, 8,  {NULL},            0,                 0,                 S_CANARIVORE_CLOSE2},     // S_CANARIVORE_CLOSE1
-	{SPR_CANA, 0, 90, {NULL},            sfx_s3k5d,         1,                 S_CANARIVORE_LOOK},      // S_CANARIVORE_CLOSE2
-
-	{SPR_CANG, 0|FF_TRANS90, 2,         {NULL},            0, 0,       S_CANARIVOREGAS_2}, // S_CANARIVOREGAS_1
-	{SPR_CANG, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_CANARIVOREGAS_3}, // S_CANARIVOREGAS_2
-	{SPR_CANG, 0|FF_TRANS40, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_4}, // S_CANARIVOREGAS_3
-	{SPR_CANG, 0|FF_TRANS50, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_5}, // S_CANARIVOREGAS_4
-	{SPR_CANG, 0|FF_TRANS60, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_6}, // S_CANARIVOREGAS_5
-	{SPR_CANG, 0|FF_TRANS70, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_7}, // S_CANARIVOREGAS_6
-	{SPR_CANG, 0|FF_TRANS80, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_8}, // S_CANARIVOREGAS_7
-	{SPR_CANG, 0|FF_TRANS90, 10,        {NULL},            0, 0,       S_NULL},            // S_CANARIVOREGAS_8
+	{SPR_CANA, 0, 5,  {A_Look},          1200*FRACUNIT+1,   1,                 S_CANARIVORE_LOOK, 0},      // S_CANARIVORE_LOOK
+	{SPR_CANA, 0, 3,  {A_PlaySound},     sfx_s3k76,         1,                 S_CANARIVORE_AWAKEN2, 0},   // S_CANARIVORE_AWAKEN1
+	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_AWAKEN3, 0},   // S_CANARIVORE_AWAKEN2
+	{SPR_CANA, 2, 8,  {NULL},            0,                 0,                 S_CANARIVORE_GAS1, 0},      // S_CANARIVORE_AWAKEN3
+	{SPR_CANA, 2, 15, {A_PlaySound},     sfx_s3k93,         1,                 S_CANARIVORE_GAS2, 0},      // S_CANARIVORE_GAS1
+	{SPR_CANA, 1, 4,  {NULL},            0,                 0,                 S_CANARIVORE_GAS3, 0},      // S_CANARIVORE_GAS2
+	{SPR_CANA, 2, 0,  {A_PlaySound},     sfx_s3k97,         1,                 S_CANARIVORE_GAS4, 0},      // S_CANARIVORE_GAS3
+	{SPR_CANA, 2, 5,  {A_CanarivoreGas}, MT_CANARIVORE_GAS, 0,                 S_CANARIVORE_GAS5, 0},      // S_CANARIVORE_GAS4
+	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_GASREPEAT, 0}, // S_CANARIVORE_GAS5
+	{SPR_CANA, 2, 0,  {A_Repeat},        6,                 S_CANARIVORE_GAS4, S_CANARIVORE_CLOSE1, 0},    // S_CANARIVORE_GASREPEAT
+	{SPR_CANA, 1, 8,  {NULL},            0,                 0,                 S_CANARIVORE_CLOSE2, 0},     // S_CANARIVORE_CLOSE1
+	{SPR_CANA, 0, 90, {NULL},            sfx_s3k5d,         1,                 S_CANARIVORE_LOOK, 0},      // S_CANARIVORE_CLOSE2
+
+	{SPR_CANG, 0|FF_TRANS90, 2,         {NULL},            0, 0,       S_CANARIVOREGAS_2, 0}, // S_CANARIVOREGAS_1
+	{SPR_CANG, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_CANARIVOREGAS_3, 0}, // S_CANARIVOREGAS_2
+	{SPR_CANG, 0|FF_TRANS40, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_4, 0}, // S_CANARIVOREGAS_3
+	{SPR_CANG, 0|FF_TRANS50, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_5, 0}, // S_CANARIVOREGAS_4
+	{SPR_CANG, 0|FF_TRANS60, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_6, 0}, // S_CANARIVOREGAS_5
+	{SPR_CANG, 0|FF_TRANS70, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_7, 0}, // S_CANARIVOREGAS_6
+	{SPR_CANG, 0|FF_TRANS80, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_8, 0}, // S_CANARIVOREGAS_7
+	{SPR_CANG, 0|FF_TRANS90, 10,        {NULL},            0, 0,       S_NULL, 0},            // S_CANARIVOREGAS_8
 
 	// Pyre Fly
-	{SPR_PYRE, FF_ANIMATE, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_FLY
-	{SPR_PYRE, 4|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_BURN
-	{SPR_FLAM, FF_FULLBRIGHT, 10, {NULL}, 0, 0, S_PYREFIRE2}, // S_PYREFIRE1
-	{SPR_FLAM, 1|FF_FULLBRIGHT, 10, {A_FireShrink}, 0, 16, S_NULL}, // S_PYREFIRE2
+	{SPR_PYRE, FF_ANIMATE, -1, {NULL}, 3, 2, S_NULL, 0}, // S_PYREFLY_FLY
+	{SPR_PYRE, 4|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 3, 2, S_NULL, 0}, // S_PYREFLY_BURN
+	{SPR_FLAM, FF_FULLBRIGHT, 10, {NULL}, 0, 0, S_PYREFIRE2, 0}, // S_PYREFIRE1
+	{SPR_FLAM, 1|FF_FULLBRIGHT, 10, {A_FireShrink}, 0, 16, S_NULL, 0}, // S_PYREFIRE2
 
 	// Pterabyte
-	{SPR_NULL, 0, -1, {A_SpawnPterabytes}, 0, 0, S_PTERABYTESPAWNER},    // S_PTERABYTESPAWNER
-	{SPR_NULL, 0,  1, {A_PterabyteHover},  0, 0, S_PTERABYTEWAYPOINT},   // S_PTERABYTEWAYPOINT
-	{SPR_PTER, 0,  6, {NULL},              0, 0, S_PTERABYTE_FLY2},      // S_PTERABYTE_FLY1
-	{SPR_PTER, 1,  2, {NULL},              0, 0, S_PTERABYTE_FLY3},      // S_PTERABYTE_FLY2
-	{SPR_PTER, 2,  6, {NULL},              0, 0, S_PTERABYTE_FLY4},      // S_PTERABYTE_FLY3
-	{SPR_PTER, 3,  2, {NULL},              0, 0, S_PTERABYTE_FLY1},      // S_PTERABYTE_FLY4
-	{SPR_PTER, 4,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPDOWN}, // S_PTERABYTE_SWOOPDOWN
-	{SPR_PTER, 0,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPUP},   // S_PTERABYTE_SWOOPUP
+	{SPR_NULL, 0, -1, {A_SpawnPterabytes}, 0, 0, S_PTERABYTESPAWNER, 0},    // S_PTERABYTESPAWNER
+	{SPR_NULL, 0,  1, {A_PterabyteHover},  0, 0, S_PTERABYTEWAYPOINT, 0},   // S_PTERABYTEWAYPOINT
+	{SPR_PTER, 0,  6, {NULL},              0, 0, S_PTERABYTE_FLY2, 0},      // S_PTERABYTE_FLY1
+	{SPR_PTER, 1,  2, {NULL},              0, 0, S_PTERABYTE_FLY3, 0},      // S_PTERABYTE_FLY2
+	{SPR_PTER, 2,  6, {NULL},              0, 0, S_PTERABYTE_FLY4, 0},      // S_PTERABYTE_FLY3
+	{SPR_PTER, 3,  2, {NULL},              0, 0, S_PTERABYTE_FLY1, 0},      // S_PTERABYTE_FLY4
+	{SPR_PTER, 4,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPDOWN, 0}, // S_PTERABYTE_SWOOPDOWN
+	{SPR_PTER, 0,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPUP, 0},   // S_PTERABYTE_SWOOPUP
 
 	// Dragonbomber
-	{SPR_DRAB,                0, -1, {A_DragonbomberSpawn}, 6, 0, S_NULL},                          // S_DRAGONBOMBER
-	{SPR_DRAB, FF_PAPERSPRITE|7,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING2},                   // S_DRAGONWING1
-	{SPR_DRAB, FF_PAPERSPRITE|8,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING3},                   // S_DRAGONWING2
-	{SPR_DRAB, FF_PAPERSPRITE|9,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING4},                   // S_DRAGONWING3
-	{SPR_DRAB, FF_PAPERSPRITE|10, 1,        {A_DragonWing}, 0, 0, S_DRAGONWING1},                   // S_DRAGONWING4
-	{SPR_DRAB,                1,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_LOADED},             // S_DRAGONTAIL_LOADED
-	{SPR_DRAB,                2,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_EMPTYLOOP},          // S_DRAGONTAIL_EMPTY
-	{SPR_DRAB,                2,  0,            {A_Repeat}, 3*TICRATE, S_DRAGONTAIL_EMPTY, S_DRAGONTAIL_RELOAD}, // S_DRAGONTAIL_EMPTYLOOP
-	{SPR_DRAB,                1,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONTAIL_LOADED},             // S_DRAGONTAIL_RELOAD
-	{SPR_DRAB,                3,  1,        {A_MinusCheck}, S_DRAGONMINE_LAND1, 0, S_DRAGONMINE},   // S_DRAGONMINE
-	{SPR_DRAB,                4,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONMINE_LAND2},              // S_DRAGONMINE_LAND1
-	{SPR_DRAB,                4,  2,            {A_Thrust}, 0, 1, S_DRAGONMINE_SLOWFLASH1},         // S_DRAGONMINE_LAND2
-	{SPR_DRAB,                5, 11,                {NULL}, 0, 0, S_DRAGONMINE_SLOWFLASH2},         // S_DRAGONMINE_SLOWFLASH1
-	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_SLOWLOOP},           // S_DRAGONMINE_SLOWFLASH2
-	{SPR_DRAB,                5,  0,            {A_Repeat}, 4, S_DRAGONMINE_SLOWFLASH1, S_DRAGONMINE_FASTFLASH1}, // S_DRAGONMINE_SLOWLOOP
-	{SPR_DRAB,                5,  3,                {NULL}, 0, 0, S_DRAGONMINE_FASTFLASH2},         // S_DRAGONMINE_FASTFLASH1
-	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_FASTLOOP},           // S_DRAGONMINE_FASTFLASH2
-	{SPR_DRAB,                5,  0,            {A_Repeat}, 5, S_DRAGONMINE_FASTFLASH1, S_DEATHSTATE}, // S_DRAGONMINE_FASTLOOP
+	{SPR_DRAB,                0, -1, {A_DragonbomberSpawn}, 6, 0, S_NULL, 0},                          // S_DRAGONBOMBER
+	{SPR_DRAB, FF_PAPERSPRITE|7,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING2, 0},                   // S_DRAGONWING1
+	{SPR_DRAB, FF_PAPERSPRITE|8,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING3, 0},                   // S_DRAGONWING2
+	{SPR_DRAB, FF_PAPERSPRITE|9,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING4, 0},                   // S_DRAGONWING3
+	{SPR_DRAB, FF_PAPERSPRITE|10, 1,        {A_DragonWing}, 0, 0, S_DRAGONWING1, 0},                   // S_DRAGONWING4
+	{SPR_DRAB,                1,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_LOADED, 0},             // S_DRAGONTAIL_LOADED
+	{SPR_DRAB,                2,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_EMPTYLOOP, 0},          // S_DRAGONTAIL_EMPTY
+	{SPR_DRAB,                2,  0,            {A_Repeat}, 3*TICRATE, S_DRAGONTAIL_EMPTY, S_DRAGONTAIL_RELOAD, 0}, // S_DRAGONTAIL_EMPTYLOOP
+	{SPR_DRAB,                1,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONTAIL_LOADED, 0},             // S_DRAGONTAIL_RELOAD
+	{SPR_DRAB,                3,  1,        {A_MinusCheck}, S_DRAGONMINE_LAND1, 0, S_DRAGONMINE, 0},   // S_DRAGONMINE
+	{SPR_DRAB,                4,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONMINE_LAND2, 0},              // S_DRAGONMINE_LAND1
+	{SPR_DRAB,                4,  2,            {A_Thrust}, 0, 1, S_DRAGONMINE_SLOWFLASH1, 0},         // S_DRAGONMINE_LAND2
+	{SPR_DRAB,                5, 11,                {NULL}, 0, 0, S_DRAGONMINE_SLOWFLASH2, 0},         // S_DRAGONMINE_SLOWFLASH1
+	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_SLOWLOOP, 0},           // S_DRAGONMINE_SLOWFLASH2
+	{SPR_DRAB,                5,  0,            {A_Repeat}, 4, S_DRAGONMINE_SLOWFLASH1, S_DRAGONMINE_FASTFLASH1, 0}, // S_DRAGONMINE_SLOWLOOP
+	{SPR_DRAB,                5,  3,                {NULL}, 0, 0, S_DRAGONMINE_FASTFLASH2, 0},         // S_DRAGONMINE_FASTFLASH1
+	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_FASTLOOP, 0},           // S_DRAGONMINE_FASTFLASH2
+	{SPR_DRAB,                5,  0,            {A_Repeat}, 5, S_DRAGONMINE_FASTFLASH1, S_DEATHSTATE, 0}, // S_DRAGONMINE_FASTLOOP
 
 	// Boss Explosion
-	{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE
+	{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL, 0}, // S_BOSSEXPLODE
 
 	// 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, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION2, 0}, // S_SONIC3KBOSSEXPLOSION1
+	{SPR_BOM3, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION3, 0}, // S_SONIC3KBOSSEXPLOSION2
+	{SPR_BOM3, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION4, 0}, // S_SONIC3KBOSSEXPLOSION3
+	{SPR_BOM3, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION5, 0}, // S_SONIC3KBOSSEXPLOSION4
+	{SPR_BOM3, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION6, 0}, // S_SONIC3KBOSSEXPLOSION5
+	{SPR_BOM3, FF_FULLBRIGHT|5, 4, {NULL}, 0, 0, S_NULL, 0}, // S_SONIC3KBOSSEXPLOSION6
 
-	{SPR_JETF, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 2, 1, S_NULL}, // S_JETFUME1
+	{SPR_JETF, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 2, 1, S_NULL, 0}, // S_JETFUME1
 
 	// Boss 1
-	{SPR_EGGM,  0,   1, {A_Boss1Chase},            0, 0, S_EGGMOBILE_STND},   // S_EGGMOBILE_STND
-	{SPR_EGGM, FF_ANIMATE|17, 35, {A_FaceTarget},  1, 2, S_EGGMOBILE_STND},   // S_EGGMOBILE_ROFL
-	{SPR_EGGM,  1,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK2},  // S_EGGMOBILE_LATK1
-	{SPR_EGGM,  2,  15, {NULL},                    0, 0, S_EGGMOBILE_LATK3},  // S_EGGMOBILE_LATK2
-	{SPR_EGGM,  3,   2, {NULL},                    0, 0, S_EGGMOBILE_LATK4},  // S_EGGMOBILE_LATK3
-	{SPR_EGGM,  4,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK5},  // S_EGGMOBILE_LATK4
-	{SPR_EGGM,  6,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_LATK6},  // S_EGGMOBILE_LATK5
-	{SPR_EGGM,  5,   1, {A_Boss1Laser},     MT_LASER, 0, S_EGGMOBILE_LATK7},  // S_EGGMOBILE_LATK6
-	{SPR_EGGM,  6,   1, {A_Boss1Laser},     MT_LASER, (1<<16), S_EGGMOBILE_LATK8},  // S_EGGMOBILE_LATK7
-	{SPR_EGGM,  5,   0, {A_Repeat}, 45, S_EGGMOBILE_LATK6, S_EGGMOBILE_LATK9},  // S_EGGMOBILE_LATK8
-	{SPR_EGGM,  8,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_LATK9
-	{SPR_EGGM,  9,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK2},  // S_EGGMOBILE_RATK1
-	{SPR_EGGM, 10,  15, {NULL},                    0, 0, S_EGGMOBILE_RATK3},  // S_EGGMOBILE_RATK2
-	{SPR_EGGM, 11,   2, {NULL},                    0, 0, S_EGGMOBILE_RATK4},  // S_EGGMOBILE_RATK3
-	{SPR_EGGM, 12,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK5},  // S_EGGMOBILE_RATK4
-	{SPR_EGGM, 14,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_RATK6},  // S_EGGMOBILE_RATK5
-	{SPR_EGGM, 13,   1, {A_Boss1Laser},     MT_LASER, 1, S_EGGMOBILE_RATK7},  // S_EGGMOBILE_RATK6
-	{SPR_EGGM, 14,   1, {A_Boss1Laser},     MT_LASER, 1|(1<<16), S_EGGMOBILE_RATK8},  // S_EGGMOBILE_RATK7
-	{SPR_EGGM, 13,   0, {A_Repeat}, 45, S_EGGMOBILE_RATK6, S_EGGMOBILE_RATK9},  // S_EGGMOBILE_RATK8
-	{SPR_EGGM, 16,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_RATK9
-	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC2},  // S_EGGMOBILE_PANIC1
-	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC3},  // S_EGGMOBILE_PANIC2
-	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC4},  // S_EGGMOBILE_PANIC3
-	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC5},  // S_EGGMOBILE_PANIC4
-	{SPR_EGGM,  6,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC3, S_EGGMOBILE_PANIC6},  // S_EGGMOBILE_PANIC5
-	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC7},  // S_EGGMOBILE_PANIC6
-	{SPR_EGGM, FF_ANIMATE|9, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC8},  // S_EGGMOBILE_PANIC7
-	{SPR_EGGM, 15,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC9},  // S_EGGMOBILE_PANIC8
-	{SPR_EGGM, 14,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC10},  // S_EGGMOBILE_PANIC9
-	{SPR_EGGM, 14,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC8, S_EGGMOBILE_PANIC11}, // S_EGGMOBILE_PANIC10
-	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC12}, // S_EGGMOBILE_PANIC11
-	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC13}, // S_EGGMOBILE_PANIC12
-	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC14}, // S_EGGMOBILE_PANIC13
-	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC15}, // S_EGGMOBILE_PANIC14
-	{SPR_EGGM,  6,  0, {A_Repeat}, 45,    S_EGGMOBILE_PANIC13, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_PANIC15
-	{SPR_EGGM, 19,  24, {A_Pain},                  0, 0, S_EGGMOBILE_PAIN2},  // S_EGGMOBILE_PAIN
-	{SPR_EGGM, 19,  16, {A_SkullAttack},           3, 1, S_EGGMOBILE_STND},   // S_EGGMOBILE_PAIN2
-	{SPR_EGGM, 20,  2, {A_Fall},                  17, 0, S_EGGMOBILE_DIE2},   // S_EGGMOBILE_DIE1
-	{SPR_EGGM, 20,  2, {A_BossScream},             0, 0, S_EGGMOBILE_DIE3},   // S_EGGMOBILE_DIE2
-	{SPR_EGGM, 20,  0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4},   // S_EGGMOBILE_DIE3
-	{SPR_EGGM, 20,  -1, {A_BossDeath},             0, 0, S_NULL},             // S_EGGMOBILE_DIE4
-	{SPR_EGGM, 21,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE2},  // S_EGGMOBILE_FLEE1
-	{SPR_EGGM, 22,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE1},  // S_EGGMOBILE_FLEE2
-	{SPR_UNID,  1,  1, {A_UnidusBall},             2, 0, S_EGGMOBILE_BALL},   // S_EGGMOBILE_BALL
-	{SPR_NULL,  0,  1, {A_FocusTarget},            0, 0, S_EGGMOBILE_TARGET}, // S_EGGMOBILE_TARGET
-
-	{SPR_EGLZ, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSEGLZ1
-	{SPR_EGLZ, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSEGLZ2
+	{SPR_EGGM,  0,   1, {A_Boss1Chase},            0, 0, S_EGGMOBILE_STND, 0},   // S_EGGMOBILE_STND
+	{SPR_EGGM, FF_ANIMATE|17, 35, {A_FaceTarget},  1, 2, S_EGGMOBILE_STND, 0},   // S_EGGMOBILE_ROFL
+	{SPR_EGGM,  1,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK2, 0},  // S_EGGMOBILE_LATK1
+	{SPR_EGGM,  2,  15, {NULL},                    0, 0, S_EGGMOBILE_LATK3, 0},  // S_EGGMOBILE_LATK2
+	{SPR_EGGM,  3,   2, {NULL},                    0, 0, S_EGGMOBILE_LATK4, 0},  // S_EGGMOBILE_LATK3
+	{SPR_EGGM,  4,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK5, 0},  // S_EGGMOBILE_LATK4
+	{SPR_EGGM,  6,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_LATK6, 0},  // S_EGGMOBILE_LATK5
+	{SPR_EGGM,  5,   1, {A_Boss1Laser},     MT_LASER, 0, S_EGGMOBILE_LATK7, 0},  // S_EGGMOBILE_LATK6
+	{SPR_EGGM,  6,   1, {A_Boss1Laser},     MT_LASER, (1<<16), S_EGGMOBILE_LATK8, 0},  // S_EGGMOBILE_LATK7
+	{SPR_EGGM,  5,   0, {A_Repeat}, 45, S_EGGMOBILE_LATK6, S_EGGMOBILE_LATK9, 0},  // S_EGGMOBILE_LATK8
+	{SPR_EGGM,  8,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL, 0}, // S_EGGMOBILE_LATK9
+	{SPR_EGGM,  9,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK2, 0},  // S_EGGMOBILE_RATK1
+	{SPR_EGGM, 10,  15, {NULL},                    0, 0, S_EGGMOBILE_RATK3, 0},  // S_EGGMOBILE_RATK2
+	{SPR_EGGM, 11,   2, {NULL},                    0, 0, S_EGGMOBILE_RATK4, 0},  // S_EGGMOBILE_RATK3
+	{SPR_EGGM, 12,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK5, 0},  // S_EGGMOBILE_RATK4
+	{SPR_EGGM, 14,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_RATK6, 0},  // S_EGGMOBILE_RATK5
+	{SPR_EGGM, 13,   1, {A_Boss1Laser},     MT_LASER, 1, S_EGGMOBILE_RATK7, 0},  // S_EGGMOBILE_RATK6
+	{SPR_EGGM, 14,   1, {A_Boss1Laser},     MT_LASER, 1|(1<<16), S_EGGMOBILE_RATK8, 0},  // S_EGGMOBILE_RATK7
+	{SPR_EGGM, 13,   0, {A_Repeat}, 45, S_EGGMOBILE_RATK6, S_EGGMOBILE_RATK9, 0},  // S_EGGMOBILE_RATK8
+	{SPR_EGGM, 16,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL, 0}, // S_EGGMOBILE_RATK9
+	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC2, 0},  // S_EGGMOBILE_PANIC1
+	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC3, 0},  // S_EGGMOBILE_PANIC2
+	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC4, 0},  // S_EGGMOBILE_PANIC3
+	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC5, 0},  // S_EGGMOBILE_PANIC4
+	{SPR_EGGM,  6,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC3, S_EGGMOBILE_PANIC6, 0},  // S_EGGMOBILE_PANIC5
+	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC7, 0},  // S_EGGMOBILE_PANIC6
+	{SPR_EGGM, FF_ANIMATE|9, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC8, 0},  // S_EGGMOBILE_PANIC7
+	{SPR_EGGM, 15,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC9, 0},  // S_EGGMOBILE_PANIC8
+	{SPR_EGGM, 14,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC10, 0},  // S_EGGMOBILE_PANIC9
+	{SPR_EGGM, 14,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC8, S_EGGMOBILE_PANIC11, 0}, // S_EGGMOBILE_PANIC10
+	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC12, 0}, // S_EGGMOBILE_PANIC11
+	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC13, 0}, // S_EGGMOBILE_PANIC12
+	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC14, 0}, // S_EGGMOBILE_PANIC13
+	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC15, 0}, // S_EGGMOBILE_PANIC14
+	{SPR_EGGM,  6,  0, {A_Repeat}, 45,    S_EGGMOBILE_PANIC13, S_EGGMOBILE_ROFL, 0}, // S_EGGMOBILE_PANIC15
+	{SPR_EGGM, 19,  24, {A_Pain},                  0, 0, S_EGGMOBILE_PAIN2, 0},  // S_EGGMOBILE_PAIN
+	{SPR_EGGM, 19,  16, {A_SkullAttack},           3, 1, S_EGGMOBILE_STND, 0},   // S_EGGMOBILE_PAIN2
+	{SPR_EGGM, 20,  2, {A_Fall},                  17, 0, S_EGGMOBILE_DIE2, 0},   // S_EGGMOBILE_DIE1
+	{SPR_EGGM, 20,  2, {A_BossScream},             0, 0, S_EGGMOBILE_DIE3, 0},   // S_EGGMOBILE_DIE2
+	{SPR_EGGM, 20,  0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4, 0},   // S_EGGMOBILE_DIE3
+	{SPR_EGGM, 20,  -1, {A_BossDeath},             0, 0, S_NULL, 0},             // S_EGGMOBILE_DIE4
+	{SPR_EGGM, 21,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE2, 0},  // S_EGGMOBILE_FLEE1
+	{SPR_EGGM, 22,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE1, 0},  // S_EGGMOBILE_FLEE2
+	{SPR_UNID,  1,  1, {A_UnidusBall},             2, 0, S_EGGMOBILE_BALL, 0},   // S_EGGMOBILE_BALL
+	{SPR_NULL,  0,  1, {A_FocusTarget},            0, 0, S_EGGMOBILE_TARGET, 0}, // S_EGGMOBILE_TARGET
+
+	{SPR_EGLZ, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSEGLZ1
+	{SPR_EGLZ, 1, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSEGLZ2
 
 	// Boss 2
-	{SPR_EGGN, 0, -1,              {NULL},           0,          0, S_NULL},             // S_EGGMOBILE2_STND
-	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO2}, // S_EGGMOBILE2_POGO1
-	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  9*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO3}, // S_EGGMOBILE2_POGO2
-	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_POGO3
-	{SPR_EGGN, 2, -1,              {NULL},           0,          0, S_NULL},             // S_EGGMOBILE2_POGO4
-	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO6}, // S_EGGMOBILE2_POGO5
-	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  7*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO7}, // S_EGGMOBILE2_POGO6
-	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_POGO7
-	{SPR_EGGN, 3, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_STND},  // S_EGGMOBILE2_PAIN
-	{SPR_EGGN, 4, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_PAIN2
-	{SPR_EGGN, 5, 2,             {A_Fall},           0,          0, S_EGGMOBILE2_DIE2},  // S_EGGMOBILE2_DIE1
-	{SPR_EGGN, 5, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_DIE3},  // S_EGGMOBILE2_DIE2
-	{SPR_EGGN, 5, 0,       {A_Repeat}, 17, S_EGGMOBILE2_DIE2, S_EGGMOBILE2_DIE4},  // S_EGGMOBILE2_DIE3
-	{SPR_EGGN, 5, -1,       {A_BossDeath},           0,          0, S_NULL},             // S_EGGMOBILE2_DIE4
-	{SPR_EGGN, 6, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE2}, // S_EGGMOBILE2_FLEE1
-	{SPR_EGGN, 7, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE1}, // S_EGGMOBILE2_FLEE2
-
-	{SPR_TANK, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK1
-	{SPR_TANK, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK2
-	{SPR_TANK, 2, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSPIGOT
+	{SPR_EGGN, 0, -1,              {NULL},           0,          0, S_NULL, 0},             // S_EGGMOBILE2_STND
+	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO2, 0}, // S_EGGMOBILE2_POGO1
+	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  9*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO3, 0}, // S_EGGMOBILE2_POGO2
+	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4, 0}, // S_EGGMOBILE2_POGO3
+	{SPR_EGGN, 2, -1,              {NULL},           0,          0, S_NULL, 0},             // S_EGGMOBILE2_POGO4
+	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO6, 0}, // S_EGGMOBILE2_POGO5
+	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  7*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO7, 0}, // S_EGGMOBILE2_POGO6
+	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4, 0}, // S_EGGMOBILE2_POGO7
+	{SPR_EGGN, 3, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_STND, 0},  // S_EGGMOBILE2_PAIN
+	{SPR_EGGN, 4, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_POGO4, 0}, // S_EGGMOBILE2_PAIN2
+	{SPR_EGGN, 5, 2,             {A_Fall},           0,          0, S_EGGMOBILE2_DIE2, 0},  // S_EGGMOBILE2_DIE1
+	{SPR_EGGN, 5, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_DIE3, 0},  // S_EGGMOBILE2_DIE2
+	{SPR_EGGN, 5, 0,       {A_Repeat}, 17, S_EGGMOBILE2_DIE2, S_EGGMOBILE2_DIE4, 0},  // S_EGGMOBILE2_DIE3
+	{SPR_EGGN, 5, -1,       {A_BossDeath},           0,          0, S_NULL, 0},             // S_EGGMOBILE2_DIE4
+	{SPR_EGGN, 6, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE2, 0}, // S_EGGMOBILE2_FLEE1
+	{SPR_EGGN, 7, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE1, 0}, // S_EGGMOBILE2_FLEE2
+
+	{SPR_TANK, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSTANK1
+	{SPR_TANK, 1, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSTANK2
+	{SPR_TANK, 2, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSSPIGOT
 
 	// Boss 2 Goop
-	{SPR_GOOP,            0,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP2}, // S_GOOP1
-	{SPR_GOOP,            1,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP1}, // S_GOOP2
-	{SPR_GOOP,            2, -1,                  {NULL}, 0,            0, S_NULL},  // S_GOOP3
-	{SPR_GOOP, FF_ANIMATE|3, 11,                  {NULL}, 2,            6, S_NULL},  // S_GOOPTRAIL
+	{SPR_GOOP,            0,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP2, 0}, // S_GOOP1
+	{SPR_GOOP,            1,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP1, 0}, // S_GOOP2
+	{SPR_GOOP,            2, -1,                  {NULL}, 0,            0, S_NULL, 0},  // S_GOOP3
+	{SPR_GOOP, FF_ANIMATE|3, 11,                  {NULL}, 2,            6, S_NULL, 0},  // S_GOOPTRAIL
 
 	// Boss 3
-	{SPR_EGGO,  0,   1, {NULL},                    0, 0, S_EGGMOBILE3_STND},    // S_EGGMOBILE3_STND
-	{SPR_EGGO,   FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2},  // S_EGGMOBILE3_SHOCK
-	{SPR_EGGO, 6|FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_ATK1
-	{SPR_EGGO,  2,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK3A},   // S_EGGMOBILE3_ATK2
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B},   // S_EGGMOBILE3_ATK3A
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 4, S_EGGMOBILE3_ATK3C},   // S_EGGMOBILE3_ATK3B
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D},   // S_EGGMOBILE3_ATK3C
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4},    // S_EGGMOBILE3_ATK3D
-	{SPR_EGGO,  4,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK5},    // S_EGGMOBILE3_ATK4
-	{SPR_EGGO,  5,   2, {NULL},                    0, 0, S_EGGMOBILE3_ROFL},  // S_EGGMOBILE3_ATK5
-	{SPR_EGGO,  6|FF_ANIMATE, 60, {NULL}, 1, 2, S_EGGMOBILE3_STND},  // S_EGGMOBILE3_ROFL
-	{SPR_EGGO,  8,   1, {A_Boss3TakeDamage},       0, 0, S_EGGMOBILE3_PAIN2},   // S_EGGMOBILE3_PAIN
-	{SPR_EGGO,  8,  23, {A_Pain},                  0, 0, S_EGGMOBILE3_STND},    // S_EGGMOBILE3_PAIN2
-	{SPR_EGGO,  9,   2, {A_Fall},                  0, 0, S_EGGMOBILE3_DIE2},    // S_EGGMOBILE3_DIE1
-	{SPR_EGGO,  9,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_DIE3},    // S_EGGMOBILE3_DIE2
-	{SPR_EGGO,  9,   0, {A_Repeat}, 17, S_EGGMOBILE3_DIE2, S_EGGMOBILE3_DIE4},  // S_EGGMOBILE3_DIE3
-	{SPR_EGGO,  9,  -1, {A_BossDeath},             0, 0, S_NULL},               // S_EGGMOBILE3_DIE4
-	{SPR_EGGO, 10,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE2},   // S_EGGMOBILE3_FLEE1
-	{SPR_EGGO, 11,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE1},   // S_EGGMOBILE3_FLEE2
+	{SPR_EGGO,  0,   1, {NULL},                    0, 0, S_EGGMOBILE3_STND, 0},    // S_EGGMOBILE3_STND
+	{SPR_EGGO,   FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2, 0},  // S_EGGMOBILE3_SHOCK
+	{SPR_EGGO, 6|FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2, 0}, // S_EGGMOBILE3_ATK1
+	{SPR_EGGO,  2,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK3A, 0},   // S_EGGMOBILE3_ATK2
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B, 0},   // S_EGGMOBILE3_ATK3A
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 4, S_EGGMOBILE3_ATK3C, 0},   // S_EGGMOBILE3_ATK3B
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D, 0},   // S_EGGMOBILE3_ATK3C
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4, 0},    // S_EGGMOBILE3_ATK3D
+	{SPR_EGGO,  4,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK5, 0},    // S_EGGMOBILE3_ATK4
+	{SPR_EGGO,  5,   2, {NULL},                    0, 0, S_EGGMOBILE3_ROFL, 0},  // S_EGGMOBILE3_ATK5
+	{SPR_EGGO,  6|FF_ANIMATE, 60, {NULL}, 1, 2, S_EGGMOBILE3_STND, 0},  // S_EGGMOBILE3_ROFL
+	{SPR_EGGO,  8,   1, {A_Boss3TakeDamage},       0, 0, S_EGGMOBILE3_PAIN2, 0},   // S_EGGMOBILE3_PAIN
+	{SPR_EGGO,  8,  23, {A_Pain},                  0, 0, S_EGGMOBILE3_STND, 0},    // S_EGGMOBILE3_PAIN2
+	{SPR_EGGO,  9,   2, {A_Fall},                  0, 0, S_EGGMOBILE3_DIE2, 0},    // S_EGGMOBILE3_DIE1
+	{SPR_EGGO,  9,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_DIE3, 0},    // S_EGGMOBILE3_DIE2
+	{SPR_EGGO,  9,   0, {A_Repeat}, 17, S_EGGMOBILE3_DIE2, S_EGGMOBILE3_DIE4, 0},  // S_EGGMOBILE3_DIE3
+	{SPR_EGGO,  9,  -1, {A_BossDeath},             0, 0, S_NULL, 0},               // S_EGGMOBILE3_DIE4
+	{SPR_EGGO, 10,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE2, 0},   // S_EGGMOBILE3_FLEE1
+	{SPR_EGGO, 11,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE1, 0},   // S_EGGMOBILE3_FLEE2
 
 	// Boss 3 Pinch
-	{SPR_FAKE, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE},       // S_FAKEMOBILE_INIT
-	{SPR_FAKE, 0,  1, {A_Boss3Path},              0, 0, S_FAKEMOBILE},       // S_FAKEMOBILE
-	{SPR_FAKE, 0, 22, {NULL},                     0, 0, S_FAKEMOBILE_ATK2},  // S_FAKEMOBILE_ATK1
-	{SPR_FAKE, 0,  2, {NULL},                     0, 0, S_FAKEMOBILE_ATK3A}, // S_FAKEMOBILE_ATK2
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 2, S_FAKEMOBILE_ATK3B}, // S_FAKEMOBILE_ATK3A
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C}, // S_FAKEMOBILE_ATK3B
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D}, // S_FAKEMOBILE_ATK3C
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE},       // S_FAKEMOBILE_ATK3D
-	{SPR_FAKE, 1,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE2},  // S_FAKEMOBILE_DIE1
-	{SPR_NULL, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE1},  // S_FAKEMOBILE_DIE2
-
-	{SPR_SEBH, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH1
-	{SPR_SEBH, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH2
+	{SPR_FAKE, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE, 0},       // S_FAKEMOBILE_INIT
+	{SPR_FAKE, 0,  1, {A_Boss3Path},              0, 0, S_FAKEMOBILE, 0},       // S_FAKEMOBILE
+	{SPR_FAKE, 0, 22, {NULL},                     0, 0, S_FAKEMOBILE_ATK2, 0},  // S_FAKEMOBILE_ATK1
+	{SPR_FAKE, 0,  2, {NULL},                     0, 0, S_FAKEMOBILE_ATK3A, 0}, // S_FAKEMOBILE_ATK2
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 2, S_FAKEMOBILE_ATK3B, 0}, // S_FAKEMOBILE_ATK3A
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C, 0}, // S_FAKEMOBILE_ATK3B
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D, 0}, // S_FAKEMOBILE_ATK3C
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE, 0},       // S_FAKEMOBILE_ATK3D
+	{SPR_FAKE, 1,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE2, 0},  // S_FAKEMOBILE_DIE1
+	{SPR_NULL, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE1, 0},  // S_FAKEMOBILE_DIE2
+
+	{SPR_SEBH, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSSEBH1
+	{SPR_SEBH, 1, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSSEBH2
 
 	// Boss 3 Shockwave
 
-	{SPR_SHCK,   FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE2}, // S_SHOCKWAVE1
-	{SPR_SHCK, 3|FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE1}, // S_SHOCKWAVE2
+	{SPR_SHCK,   FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE2, 0}, // S_SHOCKWAVE1
+	{SPR_SHCK, 3|FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE1, 0}, // S_SHOCKWAVE2
 
 	// Boss 4
-	{SPR_EGGP, 0, -1, {NULL},           0,          0, S_NULL},              // S_EGGMOBILE4_STND
-	{SPR_EGGP, 1,  3, {NULL},           0,          0, S_EGGMOBILE4_LATK2},  // S_EGGMOBILE4_LATK1
-	{SPR_EGGP, 2, 15, {NULL},           0,          0, S_EGGMOBILE4_LATK3},  // S_EGGMOBILE4_LATK2
-	{SPR_EGGP, 3,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK4},  // S_EGGMOBILE4_LATK3
-	{SPR_EGGP, 4,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK5},  // S_EGGMOBILE4_LATK4
-	{SPR_EGGP, 5, 50, {A_Boss4Reverse}, sfx_mswing, 0, S_EGGMOBILE4_LATK6},  // S_EGGMOBILE4_LATK5
-	{SPR_EGGP, 6,  2, {NULL},           0,          0, S_EGGMOBILE4_STND},   // S_EGGMOBILE4_LATK6
-	{SPR_EGGP, 7,  3, {NULL},           0,          0, S_EGGMOBILE4_RATK2},  // S_EGGMOBILE4_RATK1
-	{SPR_EGGP, 8, 15, {NULL},           0,          0, S_EGGMOBILE4_RATK3},  // S_EGGMOBILE4_RATK2
-	{SPR_EGGP, 9,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK4},  // S_EGGMOBILE4_RATK3
-	{SPR_EGGP,10,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK5},  // S_EGGMOBILE4_RATK4
-	{SPR_EGGP,11,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6},  // S_EGGMOBILE4_RATK5
-	{SPR_EGGP,12,  2, {NULL},           0,          0, S_EGGMOBILE4_STND},   // S_EGGMOBILE4_RATK6
-	{SPR_EGGP,13, 20, {A_Boss4Raise},   sfx_doord1, 0, S_EGGMOBILE4_RAISE2}, // S_EGGMOBILE4_RAISE1
-	{SPR_EGGP,15|FF_ANIMATE, -1, {NULL},        1,        10, S_NULL},             // S_EGGMOBILE4_RAISE2
-	{SPR_EGGP,13,  0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1
-	{SPR_EGGP,13, 24, {A_Pain},                 0,         0, S_EGGMOBILE4_STND},  // S_EGGMOBILE4_PAIN2
-	{SPR_EGGP,14,  2, {A_Fall},         0,          0, S_EGGMOBILE4_DIE2},   // S_EGGMOBILE4_DIE1
-	{SPR_EGGP,14,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_DIE3},   // S_EGGMOBILE4_DIE2
-	{SPR_EGGP,14,  0, {A_Repeat},   17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4},   // S_EGGMOBILE4_DIE3
-	{SPR_EGGP,14, -1, {A_BossDeath},    0,          0, S_NULL},              // S_EGGMOBILE4_DIE4
-	{SPR_EGGP,15,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE2},  // S_EGGMOBILE4_FLEE1
-	{SPR_EGGP,16,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE1},  // S_EGGMOBILE4_FLEE2
-	{SPR_BMCE, 0, -1, {NULL},           0,          0, S_NULL},              // S_EGGMOBILE4_MACE
-	{SPR_BMCE, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE2},  // S_EGGMOBILE4_MACE_DIE1
-	{SPR_NULL, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE3},  // S_EGGMOBILE4_MACE_DIE2
-	{SPR_NULL, 0,  0, {A_Repeat},       7, S_EGGMOBILE4_MACE_DIE1, S_SONIC3KBOSSEXPLOSION1}, // S_EGGMOBILE4_MACE_DIE3
+	{SPR_EGGP, 0, -1, {NULL},           0,          0, S_NULL, 0},              // S_EGGMOBILE4_STND
+	{SPR_EGGP, 1,  3, {NULL},           0,          0, S_EGGMOBILE4_LATK2, 0},  // S_EGGMOBILE4_LATK1
+	{SPR_EGGP, 2, 15, {NULL},           0,          0, S_EGGMOBILE4_LATK3, 0},  // S_EGGMOBILE4_LATK2
+	{SPR_EGGP, 3,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK4, 0},  // S_EGGMOBILE4_LATK3
+	{SPR_EGGP, 4,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK5, 0},  // S_EGGMOBILE4_LATK4
+	{SPR_EGGP, 5, 50, {A_Boss4Reverse}, sfx_mswing, 0, S_EGGMOBILE4_LATK6, 0},  // S_EGGMOBILE4_LATK5
+	{SPR_EGGP, 6,  2, {NULL},           0,          0, S_EGGMOBILE4_STND, 0},   // S_EGGMOBILE4_LATK6
+	{SPR_EGGP, 7,  3, {NULL},           0,          0, S_EGGMOBILE4_RATK2, 0},  // S_EGGMOBILE4_RATK1
+	{SPR_EGGP, 8, 15, {NULL},           0,          0, S_EGGMOBILE4_RATK3, 0},  // S_EGGMOBILE4_RATK2
+	{SPR_EGGP, 9,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK4, 0},  // S_EGGMOBILE4_RATK3
+	{SPR_EGGP,10,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK5, 0},  // S_EGGMOBILE4_RATK4
+	{SPR_EGGP,11,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6, 0},  // S_EGGMOBILE4_RATK5
+	{SPR_EGGP,12,  2, {NULL},           0,          0, S_EGGMOBILE4_STND, 0},   // S_EGGMOBILE4_RATK6
+	{SPR_EGGP,13, 20, {A_Boss4Raise},   sfx_doord1, 0, S_EGGMOBILE4_RAISE2, 0}, // S_EGGMOBILE4_RAISE1
+	{SPR_EGGP,15|FF_ANIMATE, -1, {NULL},        1,        10, S_NULL, 0},             // S_EGGMOBILE4_RAISE2
+	{SPR_EGGP,13,  0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2, 0}, // S_EGGMOBILE4_PAIN1
+	{SPR_EGGP,13, 24, {A_Pain},                 0,         0, S_EGGMOBILE4_STND, 0},  // S_EGGMOBILE4_PAIN2
+	{SPR_EGGP,14,  2, {A_Fall},         0,          0, S_EGGMOBILE4_DIE2, 0},   // S_EGGMOBILE4_DIE1
+	{SPR_EGGP,14,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_DIE3, 0},   // S_EGGMOBILE4_DIE2
+	{SPR_EGGP,14,  0, {A_Repeat},   17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4, 0},   // S_EGGMOBILE4_DIE3
+	{SPR_EGGP,14, -1, {A_BossDeath},    0,          0, S_NULL, 0},              // S_EGGMOBILE4_DIE4
+	{SPR_EGGP,15,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE2, 0},  // S_EGGMOBILE4_FLEE1
+	{SPR_EGGP,16,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE1, 0},  // S_EGGMOBILE4_FLEE2
+	{SPR_BMCE, 0, -1, {NULL},           0,          0, S_NULL, 0},              // S_EGGMOBILE4_MACE
+	{SPR_BMCE, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE2, 0},  // S_EGGMOBILE4_MACE_DIE1
+	{SPR_NULL, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE3, 0},  // S_EGGMOBILE4_MACE_DIE2
+	{SPR_NULL, 0,  0, {A_Repeat},       7, S_EGGMOBILE4_MACE_DIE1, S_SONIC3KBOSSEXPLOSION1, 0}, // S_EGGMOBILE4_MACE_DIE3
 
 	// Boss 4 jet flame
-	{SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_JETFLAME
+	{SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL, 0}, // S_JETFLAME
 
 	// Boss 4 Spectator Eggrobo
-	{SPR_EGR1,            0, -1, {NULL}, 0, 0, S_NULL},            // S_EGGROBO1_STND
-	{SPR_EGR1,            5,  2, {NULL}, 0, 0, S_EGGROBO1_BSLAP2}, // S_EGGROBO1_BSLAP1
-	{SPR_EGR1, FF_ANIMATE|6, 35, {NULL}, 1, 2, S_EGGROBO1_STND},   // S_EGGROBO1_BSLAP2
-	{SPR_EGR1, FF_ANIMATE|3, -1, {NULL}, 1, 2, S_NULL},            // S_EGGROBO1_PISSED
+	{SPR_EGR1,            0, -1, {NULL}, 0, 0, S_NULL, 0},            // S_EGGROBO1_STND
+	{SPR_EGR1,            5,  2, {NULL}, 0, 0, S_EGGROBO1_BSLAP2, 0}, // S_EGGROBO1_BSLAP1
+	{SPR_EGR1, FF_ANIMATE|6, 35, {NULL}, 1, 2, S_EGGROBO1_STND, 0},   // S_EGGROBO1_BSLAP2
+	{SPR_EGR1, FF_ANIMATE|3, -1, {NULL}, 1, 2, S_NULL, 0},            // S_EGGROBO1_PISSED
 
 	// Boss 4 Spectator Eggrobo jet flame
-	{SPR_EFIR, FF_FULLBRIGHT|2,          -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBOJET
+	{SPR_EFIR, FF_FULLBRIGHT|2,          -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGROBOJET
 
 	// Boss 5
-	{SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0}, // S_FANG_SETUP
-
-	{SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1}, // S_FANG_INTRO0
-	{SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2}, // S_FANG_INTRO1
-	{SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3}, // S_FANG_INTRO2
-	{SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4}, // S_FANG_INTRO3
-	{SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5}, // S_FANG_INTRO4
-	{SPR_FANG, 27, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6}, // S_FANG_INTRO5
-	{SPR_FANG, 28, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7}, // S_FANG_INTRO6
-	{SPR_FANG, 29, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8}, // S_FANG_INTRO7
-	{SPR_FANG, 30, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5}, // S_FANG_INTRO8
-	{SPR_FANG, 23|FF_ANIMATE, 50, {NULL}, 1, 4, S_FANG_INTRO10}, // S_FANG_INTRO9
-	{SPR_FANG, 25, 5, {NULL}, 0, 0, S_FANG_INTRO11}, // S_FANG_INTRO10
-	{SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12}, // S_FANG_INTRO11
-	{SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1}, // S_FANG_INTRO12
-
-	{SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2}, // S_FANG_CLONE1
-	{SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3}, // S_FANG_INTRO2
-	{SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4}, // S_FANG_CLONE3
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4}, // S_FANG_CLONE4
-
-	{SPR_FANG, 0,  0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1}, // S_FANG_IDLE0
-	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1
-	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3}, // S_FANG_IDLE2
-	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4}, // S_FANG_IDLE3
-	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE5}, // S_FANG_IDLE4
-	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE6}, // S_FANG_IDLE5
-	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE7}, // S_FANG_IDLE6
-	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE8}, // S_FANG_IDLE7
-	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE1}, // S_FANG_IDLE8
-
-	{SPR_FANG, 14, 0, {A_DoNPCPain}, FRACUNIT, 0, S_FANG_PAIN2}, // S_FANG_PAIN1
-	{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART1, S_FANG_PINCHPATHINGSTART1, S_FANG_PAIN2}, // S_FANG_PAIN2
-
-	{SPR_FANG,  8, 0, {A_Boss5ExtraRepeat}, 5, 4, S_FANG_PATHINGSTART2}, // S_FANG_PATHINGSTART1
-	{SPR_FANG,  8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHING}, // S_FANG_PATHINGSTART2
-	{SPR_FANG,  8, 0, {A_Boss5FindWaypoint}, 0, 0, S_FANG_BOUNCE1}, // S_FANG_PATHING
-
-	{SPR_FANG,  8, 2, {A_Thrust}, 0, 1, S_FANG_BOUNCE2}, // S_FANG_BOUNCE1
-	{SPR_FANG,  9, 2, {NULL}, 0, 0, S_FANG_BOUNCE3}, // S_FANG_BOUNCE2
-	{SPR_FANG, 10, 1, {A_Boss5Jump}, 0, 0, S_FANG_BOUNCE4}, // S_FANG_BOUNCE3
-	{SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_CHECKPATH1, S_FANG_FALL1, S_FANG_BOUNCE4}, // S_FANG_BOUNCE4
-
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL2}, // S_FANG_FALL1
-	{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL1}, // S_FANG_FALL2
-
-	{SPR_FANG,  8, 0, {A_Boss5Calm}, 0, 0, S_FANG_CHECKPATH2}, // S_FANG_CHECKPATH1
-	{SPR_FANG,  8, 0, {A_Repeat}, 0, S_FANG_PATHINGCONT1, S_FANG_SKID1}, // S_FANG_CHECKPATH2
-
-	{SPR_FANG,  9, 0, {A_Boss5PinchShot}, MT_FBOMB, -16, S_FANG_PATHINGCONT2}, // S_FANG_PATHINGCONT1
-	{SPR_FANG,  9, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHINGCONT3}, // S_FANG_PATHINGCONT2
-	{SPR_FANG,  9, 2, {A_Thrust}, 0, 1, S_FANG_PATHING}, // S_FANG_PATHINGCONT3
-
-	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_SKID2}, // S_FANG_SKID1
-	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2}, // S_FANG_SKID2
-	{SPR_FANG,  4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK}, // S_FANG_SKID3
-
-	{SPR_FANG,  0, 0, {A_RandomState}, S_FANG_LOBSHOT0, S_FANG_FIRESTART1, S_NULL}, // S_FANG_CHOOSEATTACK
-
-	{SPR_FANG,  5,  0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2}, // S_FANG_FIRESTART1 // Reset loop
-	{SPR_FANG,  5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1}, // S_FANG_FIRESTART2
-	{SPR_FANG,  5,  5, {A_FireShot}, MT_CORK, -16, S_FANG_FIRE2}, // S_FANG_FIRE1 // Start of loop
-	{SPR_FANG,  6,  5, {NULL}, 0, 0, S_FANG_FIRE3}, // S_FANG_FIRE2
-	{SPR_FANG,  7,  5, {NULL}, 0, 0, S_FANG_FIRE4}, // S_FANG_FIRE3
-	{SPR_FANG,  5,  5, {NULL}, 2, 0, S_FANG_FIREREPEAT}, // S_FANG_FIRE4
-	{SPR_FANG,  5,  0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1}, // S_FANG_FIREREPEAT // End of loop
-
-	{SPR_FANG, 18, 16, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT1}, // S_FANG_LOBSHOT0
-	{SPR_FANG, 19,  2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2}, // S_FANG_LOBSHOT1
-	{SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1}, // S_FANG_LOBSHOT2
-
-	{SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2}, // S_FANG_WAIT1
-	{SPR_FANG,             0, 35, {A_Look}, 1, 0, S_FANG_IDLE1}, // S_FANG_WAIT2
-
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART2, S_FANG_PINCHPATHINGSTART1, S_FANG_WALLHIT}, // S_FANG_WALLHIT
-
-	{SPR_FANG,  8,  0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2}, // S_FANG_PINCHPATHINGSTART1
-	{SPR_FANG,  8,  0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING}, // S_FANG_PINCHPATHINGSTART2
-	{SPR_FANG,  8,  0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE0}, // S_FANG_PINCHPATHING
-	{SPR_FANG,  8,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_FANG_PINCHBOUNCE1}, // S_FANG_PINCHBOUNCE0
-	{SPR_FANG,  8,  2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2}, // S_FANG_PINCHBOUNCE1
-	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3}, // S_FANG_PINCHBOUNCE2
-	{SPR_FANG, 10,  2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE3
-	{SPR_FANG, 10,  1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE4
-	{SPR_FANG, 12,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 1, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL0
-	{SPR_FANG, 12,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2}, // S_FANG_PINCHFALL1
-	{SPR_FANG, 13,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL2
-	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID1
-	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID2
-	{SPR_FANG, 18, 16, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT1}, // S_FANG_PINCHLOBSHOT0
-	{SPR_FANG, 19,  2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2}, // S_FANG_PINCHLOBSHOT1
-	{SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3}, // S_FANG_PINCHLOBSHOT2
-	{SPR_FANG, 20, 18, {A_LinedefExecuteFromArg}, 4, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3
-	{SPR_FANG,  0,  0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1}, // S_FANG_PINCHLOBSHOT4
-
-	{SPR_FANG, 21, 0, {A_DoNPCPain},                    0, 0, S_FANG_DIE2}, // S_FANG_DIE1
-	{SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2
-
-	{SPR_FANG, 22,  0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3
-	{SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5}, // S_FANG_DIE4
-
-	{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5
-	{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6
-	{SPR_FANG, 11, 1, {A_Boss5CheckFalling}, S_FANG_FLEEPATHING1, S_FANG_DIE8, S_FANG_DIE7}, // S_FANG_DIE7
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_FLEEPATHING1, 0, S_FANG_DIE8}, // S_FANG_DIE8
-
-	{SPR_FANG,  9,  0, {A_PlayActiveSound}, 0, 0, S_FANG_FLEEPATHING2}, // S_FANG_FLEEPATHING1
-	{SPR_FANG,  8,  2, {A_Boss5FindWaypoint}, 2, 0, S_FANG_FLEEBOUNCE1}, // S_FANG_FLEEPATHING2
-	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2}, // S_FANG_FLEEBOUNCE1
-	{SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_FANG_FLEEBOUNCE2
-
-	{SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO
-
-	{SPR_NULL, 0, -1, {A_RandomStateRange}, S_BROKENROBOTA, S_BROKENROBOTF, S_NULL}, // S_BROKENROBOTRANDOM
-	{SPR_BRKN,    FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTA
-	{SPR_BRKN,  4|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTB
-	{SPR_BRKN,  8|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTC
-	{SPR_BRKN, 12|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTD
-	{SPR_BRKN, 16|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTE
-	{SPR_BRKN, 20|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTF
-
-	{SPR_WHAT,   FF_ANIMATE|FF_FULLBRIGHT,  4, {NULL}, 1, 2, S_ALART2}, // S_ALART1
-	{SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL},   // S_ALART2
-
-	{SPR_VWRE,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREF
-	{SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREB
-
-	{SPR_PROJ,   FF_TRANS20|FF_FULLBRIGHT,  4, {NULL}, 0, 0, S_PROJECTORLIGHT2}, // S_PROJECTORLIGHT1
-	{SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT3}, // S_PROJECTORLIGHT2
-	{SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT4}, // S_PROJECTORLIGHT3
-	{SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT,  2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5}, // S_PROJECTORLIGHT4
-	{SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT,  2, {NULL}, 0, 0, S_NULL}, // S_PROJECTORLIGHT5
-
-	{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1
-	{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2
-	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2}, // S_FBOMB_EXPL1
-	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_Boss5BombExplode}, MT_TNTDUST, 0, S_FBOMB_EXPL3}, // S_FBOMB_EXPL2
-	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_FBOMB_EXPL4}, // S_FBOMB_EXPL3
-	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL5}, // S_FBOMB_EXPL4
-	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL6}, // S_FBOMB_EXPL5
-	{SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FBOMB_EXPL6
-	{SPR_BARD, 0|FF_TRANS90, 2, {NULL}, 0, 0, S_TNTDUST_2}, // S_TNTDUST_1
-	{SPR_BARD, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_TNTDUST_3}, // S_TNTDUST_2
-	{SPR_BARD, 0|FF_TRANS40, 10, {NULL}, 0, 0, S_TNTDUST_4}, // S_TNTDUST_3
-	{SPR_BARD, 0|FF_TRANS50, 10, {NULL}, 0, 0, S_TNTDUST_5}, // S_TNTDUST_4
-	{SPR_BARD, 0|FF_TRANS60, 10, {NULL}, 0, 0, S_TNTDUST_6}, // S_TNTDUST_5
-	{SPR_BARD, 0|FF_TRANS70, 10, {NULL}, 0, 0, S_TNTDUST_7}, // S_TNTDUST_6
-	{SPR_BARD, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_TNTDUST_8}, // S_TNTDUST_7
-	{SPR_BARD, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL}, // S_TNTDUST_8
-	{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNA
-	{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNB
-	{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNC
-	{SPR_FSGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGND
+	{SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0, 0}, // S_FANG_SETUP
+
+	{SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1, 0}, // S_FANG_INTRO0
+	{SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2, 0}, // S_FANG_INTRO1
+	{SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3, 0}, // S_FANG_INTRO2
+	{SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4, 0}, // S_FANG_INTRO3
+	{SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5, 0}, // S_FANG_INTRO4
+	{SPR_FANG, 27, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6, 0}, // S_FANG_INTRO5
+	{SPR_FANG, 28, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7, 0}, // S_FANG_INTRO6
+	{SPR_FANG, 29, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8, 0}, // S_FANG_INTRO7
+	{SPR_FANG, 30, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5, 0}, // S_FANG_INTRO8
+	{SPR_FANG, 23|FF_ANIMATE, 50, {NULL}, 1, 4, S_FANG_INTRO10, 0}, // S_FANG_INTRO9
+	{SPR_FANG, 25, 5, {NULL}, 0, 0, S_FANG_INTRO11, 0}, // S_FANG_INTRO10
+	{SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12, 0}, // S_FANG_INTRO11
+	{SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1, 0}, // S_FANG_INTRO12
+
+	{SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2, 0}, // S_FANG_CLONE1
+	{SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3, 0}, // S_FANG_INTRO2
+	{SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4, 0}, // S_FANG_CLONE3
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4, 0}, // S_FANG_CLONE4
+
+	{SPR_FANG, 0,  0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1, 0}, // S_FANG_IDLE0
+	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2, 0}, // S_FANG_IDLE1
+	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3, 0}, // S_FANG_IDLE2
+	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4, 0}, // S_FANG_IDLE3
+	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE5, 0}, // S_FANG_IDLE4
+	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE6, 0}, // S_FANG_IDLE5
+	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE7, 0}, // S_FANG_IDLE6
+	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE8, 0}, // S_FANG_IDLE7
+	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE1, 0}, // S_FANG_IDLE8
+
+	{SPR_FANG, 14, 0, {A_DoNPCPain}, FRACUNIT, 0, S_FANG_PAIN2, 0}, // S_FANG_PAIN1
+	{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART1, S_FANG_PINCHPATHINGSTART1, S_FANG_PAIN2, 0}, // S_FANG_PAIN2
+
+	{SPR_FANG,  8, 0, {A_Boss5ExtraRepeat}, 5, 4, S_FANG_PATHINGSTART2, 0}, // S_FANG_PATHINGSTART1
+	{SPR_FANG,  8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHING, 0}, // S_FANG_PATHINGSTART2
+	{SPR_FANG,  8, 0, {A_Boss5FindWaypoint}, 0, 0, S_FANG_BOUNCE1, 0}, // S_FANG_PATHING
+
+	{SPR_FANG,  8, 2, {A_Thrust}, 0, 1, S_FANG_BOUNCE2, 0}, // S_FANG_BOUNCE1
+	{SPR_FANG,  9, 2, {NULL}, 0, 0, S_FANG_BOUNCE3, 0}, // S_FANG_BOUNCE2
+	{SPR_FANG, 10, 1, {A_Boss5Jump}, 0, 0, S_FANG_BOUNCE4, 0}, // S_FANG_BOUNCE3
+	{SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_CHECKPATH1, S_FANG_FALL1, S_FANG_BOUNCE4, 0}, // S_FANG_BOUNCE4
+
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL2, 0}, // S_FANG_FALL1
+	{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL1, 0}, // S_FANG_FALL2
+
+	{SPR_FANG,  8, 0, {A_Boss5Calm}, 0, 0, S_FANG_CHECKPATH2, 0}, // S_FANG_CHECKPATH1
+	{SPR_FANG,  8, 0, {A_Repeat}, 0, S_FANG_PATHINGCONT1, S_FANG_SKID1, 0}, // S_FANG_CHECKPATH2
+
+	{SPR_FANG,  9, 0, {A_Boss5PinchShot}, MT_FBOMB, -16, S_FANG_PATHINGCONT2, 0}, // S_FANG_PATHINGCONT1
+	{SPR_FANG,  9, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHINGCONT3, 0}, // S_FANG_PATHINGCONT2
+	{SPR_FANG,  9, 2, {A_Thrust}, 0, 1, S_FANG_PATHING, 0}, // S_FANG_PATHINGCONT3
+
+	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_SKID2, 0}, // S_FANG_SKID1
+	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2, 0}, // S_FANG_SKID2
+	{SPR_FANG,  4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK, 0}, // S_FANG_SKID3
+
+	{SPR_FANG,  0, 0, {A_RandomState}, S_FANG_LOBSHOT0, S_FANG_FIRESTART1, S_NULL, 0}, // S_FANG_CHOOSEATTACK
+
+	{SPR_FANG,  5,  0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2, 0}, // S_FANG_FIRESTART1 // Reset loop
+	{SPR_FANG,  5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1, 0}, // S_FANG_FIRESTART2
+	{SPR_FANG,  5,  5, {A_FireShot}, MT_CORK, -16, S_FANG_FIRE2, 0}, // S_FANG_FIRE1 // Start of loop
+	{SPR_FANG,  6,  5, {NULL}, 0, 0, S_FANG_FIRE3, 0}, // S_FANG_FIRE2
+	{SPR_FANG,  7,  5, {NULL}, 0, 0, S_FANG_FIRE4, 0}, // S_FANG_FIRE3
+	{SPR_FANG,  5,  5, {NULL}, 2, 0, S_FANG_FIREREPEAT, 0}, // S_FANG_FIRE4
+	{SPR_FANG,  5,  0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1, 0}, // S_FANG_FIREREPEAT // End of loop
+
+	{SPR_FANG, 18, 16, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT1, 0}, // S_FANG_LOBSHOT0
+	{SPR_FANG, 19,  2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2, 0}, // S_FANG_LOBSHOT1
+	{SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1, 0}, // S_FANG_LOBSHOT2
+
+	{SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2, 0}, // S_FANG_WAIT1
+	{SPR_FANG,             0, 35, {A_Look}, 1, 0, S_FANG_IDLE1, 0}, // S_FANG_WAIT2
+
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART2, S_FANG_PINCHPATHINGSTART1, S_FANG_WALLHIT, 0}, // S_FANG_WALLHIT
+
+	{SPR_FANG,  8,  0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2, 0}, // S_FANG_PINCHPATHINGSTART1
+	{SPR_FANG,  8,  0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING, 0}, // S_FANG_PINCHPATHINGSTART2
+	{SPR_FANG,  8,  0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE0, 0}, // S_FANG_PINCHPATHING
+	{SPR_FANG,  8,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_FANG_PINCHBOUNCE1, 0}, // S_FANG_PINCHBOUNCE0
+	{SPR_FANG,  8,  2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2, 0}, // S_FANG_PINCHBOUNCE1
+	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3, 0}, // S_FANG_PINCHBOUNCE2
+	{SPR_FANG, 10,  2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4, 0}, // S_FANG_PINCHBOUNCE3
+	{SPR_FANG, 10,  1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL0, S_FANG_PINCHBOUNCE4, 0}, // S_FANG_PINCHBOUNCE4
+	{SPR_FANG, 12,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 1, S_FANG_PINCHFALL1, 0}, // S_FANG_PINCHFALL0
+	{SPR_FANG, 12,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2, 0}, // S_FANG_PINCHFALL1
+	{SPR_FANG, 13,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1, 0}, // S_FANG_PINCHFALL2
+	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2, 0}, // S_FANG_PINCHSKID1
+	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT0, 0, S_FANG_PINCHSKID2, 0}, // S_FANG_PINCHSKID2
+	{SPR_FANG, 18, 16, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT1, 0}, // S_FANG_PINCHLOBSHOT0
+	{SPR_FANG, 19,  2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2, 0}, // S_FANG_PINCHLOBSHOT1
+	{SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3, 0}, // S_FANG_PINCHLOBSHOT2
+	{SPR_FANG, 20, 18, {A_LinedefExecuteFromArg}, 4, 0, S_FANG_PINCHLOBSHOT4, 0}, // S_FANG_PINCHLOBSHOT3
+	{SPR_FANG,  0,  0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1, 0}, // S_FANG_PINCHLOBSHOT4
+
+	{SPR_FANG, 21, 0, {A_DoNPCPain},                    0, 0, S_FANG_DIE2, 0}, // S_FANG_DIE1
+	{SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2, 0}, // S_FANG_DIE2
+
+	{SPR_FANG, 22,  0, {A_Scream}, 0, 0, S_FANG_DIE4, 0}, // S_FANG_DIE3
+	{SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5, 0}, // S_FANG_DIE4
+
+	{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6, 0}, // S_FANG_DIE5
+	{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7, 0}, // S_FANG_DIE6
+	{SPR_FANG, 11, 1, {A_Boss5CheckFalling}, S_FANG_FLEEPATHING1, S_FANG_DIE8, S_FANG_DIE7, 0}, // S_FANG_DIE7
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_FLEEPATHING1, 0, S_FANG_DIE8, 0}, // S_FANG_DIE8
+
+	{SPR_FANG,  9,  0, {A_PlayActiveSound}, 0, 0, S_FANG_FLEEPATHING2, 0}, // S_FANG_FLEEPATHING1
+	{SPR_FANG,  8,  2, {A_Boss5FindWaypoint}, 2, 0, S_FANG_FLEEBOUNCE1, 0}, // S_FANG_FLEEPATHING2
+	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2, 0}, // S_FANG_FLEEBOUNCE1
+	{SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL, 0}, // S_FANG_FLEEBOUNCE2
+
+	{SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL, 0}, // S_FANG_KO
+
+	{SPR_NULL, 0, -1, {A_RandomStateRange}, S_BROKENROBOTA, S_BROKENROBOTF, S_NULL, 0}, // S_BROKENROBOTRANDOM
+	{SPR_BRKN,    FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTA
+	{SPR_BRKN,  4|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTB
+	{SPR_BRKN,  8|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTC
+	{SPR_BRKN, 12|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTD
+	{SPR_BRKN, 16|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTE
+	{SPR_BRKN, 20|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTF
+
+	{SPR_WHAT,   FF_ANIMATE|FF_FULLBRIGHT,  4, {NULL}, 1, 2, S_ALART2, 0}, // S_ALART1
+	{SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL, 0},   // S_ALART2
+
+	{SPR_VWRE,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_VWREF
+	{SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_VWREB
+
+	{SPR_PROJ,   FF_TRANS20|FF_FULLBRIGHT,  4, {NULL}, 0, 0, S_PROJECTORLIGHT2, 0}, // S_PROJECTORLIGHT1
+	{SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT3, 0}, // S_PROJECTORLIGHT2
+	{SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT4, 0}, // S_PROJECTORLIGHT3
+	{SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT,  2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5, 0}, // S_PROJECTORLIGHT4
+	{SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT,  2, {NULL}, 0, 0, S_NULL, 0}, // S_PROJECTORLIGHT5
+
+	{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2, 0}, // S_FBOMB1
+	{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1, 0}, // S_FBOMB2
+	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2, 0}, // S_FBOMB_EXPL1
+	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_Boss5BombExplode}, MT_TNTDUST, 0, S_FBOMB_EXPL3, 0}, // S_FBOMB_EXPL2
+	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_FBOMB_EXPL4, 0}, // S_FBOMB_EXPL3
+	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL5, 0}, // S_FBOMB_EXPL4
+	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL6, 0}, // S_FBOMB_EXPL5
+	{SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL, 0}, // S_FBOMB_EXPL6
+	{SPR_BARD, 0|FF_TRANS90, 2, {NULL}, 0, 0, S_TNTDUST_2, 0}, // S_TNTDUST_1
+	{SPR_BARD, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_TNTDUST_3, 0}, // S_TNTDUST_2
+	{SPR_BARD, 0|FF_TRANS40, 10, {NULL}, 0, 0, S_TNTDUST_4, 0}, // S_TNTDUST_3
+	{SPR_BARD, 0|FF_TRANS50, 10, {NULL}, 0, 0, S_TNTDUST_5, 0}, // S_TNTDUST_4
+	{SPR_BARD, 0|FF_TRANS60, 10, {NULL}, 0, 0, S_TNTDUST_6, 0}, // S_TNTDUST_5
+	{SPR_BARD, 0|FF_TRANS70, 10, {NULL}, 0, 0, S_TNTDUST_7, 0}, // S_TNTDUST_6
+	{SPR_BARD, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_TNTDUST_8, 0}, // S_TNTDUST_7
+	{SPR_BARD, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL, 0}, // S_TNTDUST_8
+	{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGNA
+	{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGNB
+	{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGNC
+	{SPR_FSGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGND
 
 	// Black Eggman (Boss 7)
-	{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
-	{SPR_BRAK, 1, 7, {NULL}, 0, 0, S_BLACKEGG_WALK2}, // S_BLACKEGG_WALK1
-	{SPR_BRAK, 2, 7, {NULL}, 0, 0, S_BLACKEGG_WALK3}, // S_BLACKEGG_WALK2
-	{SPR_BRAK, 3, 7, {A_PlaySound}, sfx_bestep, 0, S_BLACKEGG_WALK4}, // S_BLACKEGG_WALK3
-	{SPR_BRAK, 4, 7, {NULL}, 0, 0, S_BLACKEGG_WALK5}, // S_BLACKEGG_WALK4
-	{SPR_BRAK, 5, 7, {NULL}, 0, 0, S_BLACKEGG_WALK6}, // S_BLACKEGG_WALK5
-	{SPR_BRAK, 6, 7, {A_PlaySound}, sfx_bestp2, 0, S_BLACKEGG_WALK1}, // S_BLACKEGG_WALK6
-	{SPR_BRAK, 7, 3, {NULL}, 0, 0, S_BLACKEGG_SHOOT2}, // S_BLACKEGG_SHOOT1
-	{SPR_BRAK, 24, 1, {A_PlaySound}, sfx_befire, 0, S_BLACKEGG_SHOOT1}, // S_BLACKEGG_SHOOT2
-
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN2}, // S_BLACKEGG_PAIN1
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN3}, // S_BLACKEGG_PAIN2
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN4}, // S_BLACKEGG_PAIN3
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN5}, // S_BLACKEGG_PAIN4
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN6}, // S_BLACKEGG_PAIN5
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN7}, // S_BLACKEGG_PAIN6
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN8}, // S_BLACKEGG_PAIN7
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN9}, // S_BLACKEGG_PAIN8
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN10}, // S_BLACKEGG_PAIN9
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN11}, // S_BLACKEGG_PAIN10
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN12}, // S_BLACKEGG_PAIN11
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN13}, // S_BLACKEGG_PAIN12
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN14}, // S_BLACKEGG_PAIN13
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN15}, // S_BLACKEGG_PAIN14
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN16}, // S_BLACKEGG_PAIN15
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN17}, // S_BLACKEGG_PAIN16
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN18}, // S_BLACKEGG_PAIN17
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN19}, // S_BLACKEGG_PAIN18
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN20}, // S_BLACKEGG_PAIN19
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN21}, // S_BLACKEGG_PAIN20
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN22}, // S_BLACKEGG_PAIN21
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN23}, // S_BLACKEGG_PAIN22
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN24}, // S_BLACKEGG_PAIN23
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN25}, // S_BLACKEGG_PAIN24
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN26}, // S_BLACKEGG_PAIN25
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN27}, // S_BLACKEGG_PAIN26
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN28}, // S_BLACKEGG_PAIN27
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN29}, // S_BLACKEGG_PAIN28
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN30}, // S_BLACKEGG_PAIN29
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN31}, // S_BLACKEGG_PAIN30
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN32}, // S_BLACKEGG_PAIN31
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN33}, // S_BLACKEGG_PAIN32
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN34}, // S_BLACKEGG_PAIN33
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN35}, // S_BLACKEGG_PAIN34
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_WALK1}, // S_BLACKEGG_PAIN35
-
-	{SPR_BRAK, 9, 20, {NULL}, 0, 0, S_BLACKEGG_HITFACE2}, // S_BLACKEGG_HITFACE1
-	{SPR_BRAK, 10, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE3}, // S_BLACKEGG_HITFACE2
-	{SPR_BRAK, 11, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE4}, // S_BLACKEGG_HITFACE3
-	{SPR_BRAK, 12,14, {NULL}, 0, 0, S_BLACKEGG_PAIN1}, // S_BLACKEGG_HITFACE4
-
-	{SPR_BRAK, 13, 14, {NULL}, 0, 0, S_BLACKEGG_DIE2}, // S_BLACKEGG_DIE1
-	{SPR_BRAK, 14, 7, {NULL}, 0, 0, S_BLACKEGG_DIE3}, // S_BLACKEGG_DIE2
-	{SPR_BRAK, 15, 5, {NULL}, 0, 0, S_BLACKEGG_DIE4}, // S_BLACKEGG_DIE3
-	{SPR_BRAK, 16, 3, {A_PlaySound}, sfx_bgxpld, 0, S_BLACKEGG_DIE5}, // S_BLACKEGG_DIE4
-	{SPR_BRAK, 17, -1, {NULL}, 0, 0, S_BLACKEGG_DIE5}, // S_BLACKEGG_DIE5
-
-	{SPR_BRAK, 18, 14, {NULL}, 0, 0, S_BLACKEGG_MISSILE2}, // S_BLACKEGG_MISSILE1
-	{SPR_BRAK, 19, 5, {NULL}, 0, 0, S_BLACKEGG_MISSILE3}, // S_BLACKEGG_MISSILE2
-	{SPR_BRAK, 20, 35, {A_Boss7FireMissiles}, MT_BLACKEGGMAN_MISSILE, sfx_beshot, S_BLACKEGG_JUMP1}, // S_BLACKEGG_MISSILE3
-
-	{SPR_BRAK, 21, -1, {NULL}, 0, 0, S_BLACKEGG_STND}, // S_BLACKEGG_GOOP
-
-	{SPR_BRAK, 22, 14, {A_PlaySound}, sfx_belnch, 0, S_BLACKEGG_JUMP2}, // S_BLACKEGG_JUMP1
-	{SPR_BRAK, 23, -1, {NULL}, 0, 0, S_BLACKEGG_WALK1}, // S_BLACKEGG_JUMP2
-
-	{SPR_BRAK, 21, 3*TICRATE, {NULL}, 0, 0, S_BLACKEGG_DESTROYPLAT2}, // S_BLACKEGG_DESTROYPLAT1
-	{SPR_BRAK, 21, 1, {A_PlaySound}, sfx_s3k54, 0, S_BLACKEGG_DESTROYPLAT3}, // S_BLACKEGG_DESTROYPLAT2
-	{SPR_BRAK, 21, 14, {A_LinedefExecuteFromArg}, 5, 0, S_BLACKEGG_STND}, // S_BLACKEGG_DESTROYPLAT3
-
-	{SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER}, // S_BLACKEGG_HELPER
-
-	{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
+	{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2, 0}, // S_BLACKEGG_STND
+	{SPR_BRAK, 0, 7, {A_Look}, 1, 0, S_BLACKEGG_STND2, 0}, // S_BLACKEGG_STND2
+	{SPR_BRAK, 1, 7, {NULL}, 0, 0, S_BLACKEGG_WALK2, 0}, // S_BLACKEGG_WALK1
+	{SPR_BRAK, 2, 7, {NULL}, 0, 0, S_BLACKEGG_WALK3, 0}, // S_BLACKEGG_WALK2
+	{SPR_BRAK, 3, 7, {A_PlaySound}, sfx_bestep, 0, S_BLACKEGG_WALK4, 0}, // S_BLACKEGG_WALK3
+	{SPR_BRAK, 4, 7, {NULL}, 0, 0, S_BLACKEGG_WALK5, 0}, // S_BLACKEGG_WALK4
+	{SPR_BRAK, 5, 7, {NULL}, 0, 0, S_BLACKEGG_WALK6, 0}, // S_BLACKEGG_WALK5
+	{SPR_BRAK, 6, 7, {A_PlaySound}, sfx_bestp2, 0, S_BLACKEGG_WALK1, 0}, // S_BLACKEGG_WALK6
+	{SPR_BRAK, 7, 3, {NULL}, 0, 0, S_BLACKEGG_SHOOT2, 0}, // S_BLACKEGG_SHOOT1
+	{SPR_BRAK, 24, 1, {A_PlaySound}, sfx_befire, 0, S_BLACKEGG_SHOOT1, 0}, // S_BLACKEGG_SHOOT2
+
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN2, 0}, // S_BLACKEGG_PAIN1
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN3, 0}, // S_BLACKEGG_PAIN2
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN4, 0}, // S_BLACKEGG_PAIN3
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN5, 0}, // S_BLACKEGG_PAIN4
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN6, 0}, // S_BLACKEGG_PAIN5
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN7, 0}, // S_BLACKEGG_PAIN6
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN8, 0}, // S_BLACKEGG_PAIN7
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN9, 0}, // S_BLACKEGG_PAIN8
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN10, 0}, // S_BLACKEGG_PAIN9
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN11, 0}, // S_BLACKEGG_PAIN10
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN12, 0}, // S_BLACKEGG_PAIN11
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN13, 0}, // S_BLACKEGG_PAIN12
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN14, 0}, // S_BLACKEGG_PAIN13
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN15, 0}, // S_BLACKEGG_PAIN14
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN16, 0}, // S_BLACKEGG_PAIN15
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN17, 0}, // S_BLACKEGG_PAIN16
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN18, 0}, // S_BLACKEGG_PAIN17
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN19, 0}, // S_BLACKEGG_PAIN18
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN20, 0}, // S_BLACKEGG_PAIN19
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN21, 0}, // S_BLACKEGG_PAIN20
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN22, 0}, // S_BLACKEGG_PAIN21
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN23, 0}, // S_BLACKEGG_PAIN22
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN24, 0}, // S_BLACKEGG_PAIN23
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN25, 0}, // S_BLACKEGG_PAIN24
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN26, 0}, // S_BLACKEGG_PAIN25
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN27, 0}, // S_BLACKEGG_PAIN26
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN28, 0}, // S_BLACKEGG_PAIN27
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN29, 0}, // S_BLACKEGG_PAIN28
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN30, 0}, // S_BLACKEGG_PAIN29
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN31, 0}, // S_BLACKEGG_PAIN30
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN32, 0}, // S_BLACKEGG_PAIN31
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN33, 0}, // S_BLACKEGG_PAIN32
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN34, 0}, // S_BLACKEGG_PAIN33
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN35, 0}, // S_BLACKEGG_PAIN34
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_WALK1, 0}, // S_BLACKEGG_PAIN35
+
+	{SPR_BRAK, 9, 20, {NULL}, 0, 0, S_BLACKEGG_HITFACE2, 0}, // S_BLACKEGG_HITFACE1
+	{SPR_BRAK, 10, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE3, 0}, // S_BLACKEGG_HITFACE2
+	{SPR_BRAK, 11, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE4, 0}, // S_BLACKEGG_HITFACE3
+	{SPR_BRAK, 12,14, {NULL}, 0, 0, S_BLACKEGG_PAIN1, 0}, // S_BLACKEGG_HITFACE4
+
+	{SPR_BRAK, 13, 14, {NULL}, 0, 0, S_BLACKEGG_DIE2, 0}, // S_BLACKEGG_DIE1
+	{SPR_BRAK, 14, 7, {NULL}, 0, 0, S_BLACKEGG_DIE3, 0}, // S_BLACKEGG_DIE2
+	{SPR_BRAK, 15, 5, {NULL}, 0, 0, S_BLACKEGG_DIE4, 0}, // S_BLACKEGG_DIE3
+	{SPR_BRAK, 16, 3, {A_PlaySound}, sfx_bgxpld, 0, S_BLACKEGG_DIE5, 0}, // S_BLACKEGG_DIE4
+	{SPR_BRAK, 17, -1, {NULL}, 0, 0, S_BLACKEGG_DIE5, 0}, // S_BLACKEGG_DIE5
+
+	{SPR_BRAK, 18, 14, {NULL}, 0, 0, S_BLACKEGG_MISSILE2, 0}, // S_BLACKEGG_MISSILE1
+	{SPR_BRAK, 19, 5, {NULL}, 0, 0, S_BLACKEGG_MISSILE3, 0}, // S_BLACKEGG_MISSILE2
+	{SPR_BRAK, 20, 35, {A_Boss7FireMissiles}, MT_BLACKEGGMAN_MISSILE, sfx_beshot, S_BLACKEGG_JUMP1, 0}, // S_BLACKEGG_MISSILE3
+
+	{SPR_BRAK, 21, -1, {NULL}, 0, 0, S_BLACKEGG_STND, 0}, // S_BLACKEGG_GOOP
+
+	{SPR_BRAK, 22, 14, {A_PlaySound}, sfx_belnch, 0, S_BLACKEGG_JUMP2, 0}, // S_BLACKEGG_JUMP1
+	{SPR_BRAK, 23, -1, {NULL}, 0, 0, S_BLACKEGG_WALK1, 0}, // S_BLACKEGG_JUMP2
+
+	{SPR_BRAK, 21, 3*TICRATE, {NULL}, 0, 0, S_BLACKEGG_DESTROYPLAT2, 0}, // S_BLACKEGG_DESTROYPLAT1
+	{SPR_BRAK, 21, 1, {A_PlaySound}, sfx_s3k54, 0, S_BLACKEGG_DESTROYPLAT3, 0}, // S_BLACKEGG_DESTROYPLAT2
+	{SPR_BRAK, 21, 14, {A_LinedefExecuteFromArg}, 5, 0, S_BLACKEGG_STND, 0}, // S_BLACKEGG_DESTROYPLAT3
+
+	{SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER, 0}, // S_BLACKEGG_HELPER
+
+	{SPR_BGOO, FF_TRANS50  , 2, {NULL}, 0, 0, S_BLACKEGG_GOOP2, 0}, // S_BLACKEGG_GOOP1
+	{SPR_BGOO, FF_TRANS50|1, 2, {NULL}, 0, 0, S_BLACKEGG_GOOP1, 0}, // S_BLACKEGG_GOOP2
+	{SPR_BGOO, FF_TRANS50|2, 6*TICRATE, {A_GoopSplat}, 0, 0, S_BLACKEGG_GOOP4, 0}, // S_BLACKEGG_GOOP3
+	{SPR_BGOO, FF_TRANS60|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP5, 0}, // S_BLACKEGG_GOOP4
+	{SPR_BGOO, FF_TRANS70|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP6, 0}, // S_BLACKEGG_GOOP5
+	{SPR_BGOO, FF_TRANS80|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP7, 0}, // S_BLACKEGG_GOOP6
+	{SPR_BGOO, FF_TRANS90|2, 4, {NULL}, 0, 0, S_NULL, 0}, // S_BLACKEGG_GOOP7
+
+	{SPR_BMSL, 0, 1, {NULL}, 0, 0, S_BLACKEGG_MISSILE, 0}, // S_BLACKEGG_MISSILE
 
 	// New Very-Last-Minute 2.1 Brak Eggman (Cy-Brak-demon)
-	{SPR_BRAK, 0, 10, {A_Look}, 0, 0, S_CYBRAKDEMON_IDLE}, // S_CYBRAKDEMON_IDLE
-	{SPR_BRAK, 1, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK2}, // S_CYBRAKDEMON_WALK1
-	{SPR_BRAK, 2, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK3}, // S_CYBRAKDEMON_WALK2
-	{SPR_BRAK, 3, 8, {A_BrakChase}, 3, sfx_bestep, S_CYBRAKDEMON_WALK4}, // S_CYBRAKDEMON_WALK3
-	{SPR_BRAK, 4, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK5}, // S_CYBRAKDEMON_WALK4
-	{SPR_BRAK, 5, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK6}, // S_CYBRAKDEMON_WALK5
-	{SPR_BRAK, 6, 8, {A_BrakChase}, 3, sfx_bestp2, S_CYBRAKDEMON_WALK1}, // S_CYBRAKDEMON_WALK6
-	{SPR_BRAK, 7, 6, {A_RandomState}, S_CYBRAKDEMON_MISSILE_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1}, // S_CYBRAKDEMON_CHOOSE_ATTACK1
-	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK2}, // S_CYBRAKDEMON_MISSILE_ATTACK1 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK3}, // S_CYBRAKDEMON_MISSILE_ATTACK2 // Fire
-	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK4}, // S_CYBRAKDEMON_MISSILE_ATTACK3 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK5}, // S_CYBRAKDEMON_MISSILE_ATTACK4 // Fire
-	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK6}, // S_CYBRAKDEMON_MISSILE_ATTACK5 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_MISSILE_ATTACK6 // Fire
-	{SPR_BRAK, 7, 1, {A_Repeat}, 1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK2}, // S_CYBRAKDEMON_FLAME_ATTACK1 // Reset
-	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FLAME_ATTACK3}, // S_CYBRAKDEMON_FLAME_ATTACK2 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 2, {A_BrakFireShot}, MT_CYBRAKDEMON_FLAMESHOT, 128, S_CYBRAKDEMON_FLAME_ATTACK4}, // S_CYBRAKDEMON_FLAME_ATTACK3 // Fire
-	{SPR_BRAK, 7, 1, {A_Repeat}, 30, S_CYBRAKDEMON_FLAME_ATTACK3, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_FLAME_ATTACK4 // Loop
-	{SPR_BRAK, 0, 6, {A_RandomState}, S_CYBRAKDEMON_VILE_ATTACK1, S_CYBRAKDEMON_NAPALM_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1}, // S_CYBRAKDEMON_CHOOSE_ATTACK2
-	{SPR_BRAK, 20, 0, {A_LinedefExecuteFromArg}, 5, 0, S_CYBRAKDEMON_VILE_ATTACK2}, // S_CYBRAKDEMON_VILE_ATTACK1
-	{SPR_BRAK, 20, 24, {A_VileTarget}, MT_CYBRAKDEMON_TARGET_RETICULE, 1, S_CYBRAKDEMON_VILE_ATTACK3}, // S_CYBRAKDEMON_VILE_ATTACK2
-	{SPR_BRAK, 19, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK4}, // S_CYBRAKDEMON_VILE_ATTACK3
-	{SPR_BRAK, 18, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK5}, // S_CYBRAKDEMON_VILE_ATTACK4
-	{SPR_BRAK, 8, 32, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK6}, // S_CYBRAKDEMON_VILE_ATTACK5
-	{SPR_BRAK, 20 + FF_FULLBRIGHT, 28, {A_VileAttack}, sfx_brakrx, MT_CYBRAKDEMON_VILE_EXPLOSION + (1<<16), S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_VILE_ATTACK6
-	{SPR_BRAK, 0, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_NAPALM_ATTACK2}, // S_CYBRAKDEMON_NAPALM_ATTACK1
-	{SPR_BRAK, 21 + FF_FULLBRIGHT, 8, {A_BrakLobShot}, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, 96, S_CYBRAKDEMON_NAPALM_ATTACK3}, // S_CYBRAKDEMON_NAPALM_ATTACK2
-	{SPR_BRAK, 0, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_NAPALM_ATTACK3
-	{SPR_BRAK, 0, 0, {A_SetObjectFlags2}, MF2_FRET, 1, S_CYBRAKDEMON_FINISH_ATTACK2}, // S_CYBRAKDEMON_FINISH_ATTACK1 // If just attacked, remove MF2_FRET w/out going back to spawnstate
-	{SPR_BRAK, 0, 0, {A_SetReactionTime}, 0, 0, S_CYBRAKDEMON_WALK1}, // S_CYBRAKDEMON_FINISH_ATTACK2 // If just attacked, remove MF2_FRET w/out going back to spawnstate
-	{SPR_BRAK, 18, 24, {A_Pain}, 0, 0, S_CYBRAKDEMON_PAIN2}, // S_CYBRAKDEMON_PAIN1
-	{SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN2
-	{SPR_BRAK, 18, 0, {A_LinedefExecuteFromArg}, 4, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN3
-	{SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2}, // S_CYBRAKDEMON_DIE1
-	{SPR_BRAK, 18, 2, {A_BossScream}, 2, 0, S_CYBRAKDEMON_DIE3}, // S_CYBRAKDEMON_DIE2
-	{SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4}, // S_CYBRAKDEMON_DIE3
-	{SPR_BRAK, 13, 34, {A_BossDeath}, 0, 0, S_CYBRAKDEMON_DIE5}, // S_CYBRAKDEMON_DIE4
-	{SPR_BRAK, 14, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE6}, // S_CYBRAKDEMON_DIE5
-	{SPR_BRAK, 15, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE7}, // S_CYBRAKDEMON_DIE6
-	{SPR_BRAK, 16, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE8}, // S_CYBRAKDEMON_DIE7
-	{SPR_BRAK, 17, 34, {NULL}, sfx_befall, 0, S_CYBRAKDEMON_DIE8}, // S_CYBRAKDEMON_DIE8
-	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 2, S_CYBRAKDEMON_IDLE}, // S_CYBRAKDEMON_DEINVINCIBLERIZE
-	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 1, S_CYBRAKDEMON_IDLE}, // S_CYBRAKDEMON_INVINCIBLERIZE
-
-	{SPR_RCKT, 0 + FF_FULLBRIGHT, 1, {A_SetObjectFlags2}, MF2_RAILRING, 2, S_CYBRAKDEMONMISSILE}, // S_CYBRAKDEMONMISSILE
-	{SPR_RCKT, 1 + FF_FULLBRIGHT, 8, {A_Explode}, 0, 0, S_CYBRAKDEMONMISSILE_EXPLODE2}, // S_CYBRAKDEMONMISSILE_EXPLODE1 //TODO: set missile mobj's "damage" to an appropriate radius
-	{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, FF_FULLBRIGHT  , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1
-	{SPR_FLME, FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2
-	{SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3
-	{SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE
-
-	{SPR_FLAM, FF_FULLBRIGHT, 1, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // 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
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER1}, // S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER2}, // S_CYBRAKDEMONELECTRICBARRIER1
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER3}, // S_CYBRAKDEMONELECTRICBARRIER2
-	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER4}, // S_CYBRAKDEMONELECTRICBARRIER3
-	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER5}, // S_CYBRAKDEMONELECTRICBARRIER4
-	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER6}, // S_CYBRAKDEMONELECTRICBARRIER5
-	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER7}, // S_CYBRAKDEMONELECTRICBARRIER6
-	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER8}, // S_CYBRAKDEMONELECTRICBARRIER7
-	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER9}, // S_CYBRAKDEMONELECTRICBARRIER8
-	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER10}, // S_CYBRAKDEMONELECTRICBARRIER9
-	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER11}, // S_CYBRAKDEMONELECTRICBARRIER10
-	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER12}, // S_CYBRAKDEMONELECTRICBARRIER11
-	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER13}, // S_CYBRAKDEMONELECTRICBARRIER12
-	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER14}, // S_CYBRAKDEMONELECTRICBARRIER13
-	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER15}, // S_CYBRAKDEMONELECTRICBARRIER14
-	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER16}, // S_CYBRAKDEMONELECTRICBARRIER15
-	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER17}, // S_CYBRAKDEMONELECTRICBARRIER16
-	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER18}, // S_CYBRAKDEMONELECTRICBARRIER17
-	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER19}, // S_CYBRAKDEMONELECTRICBARRIER18
-	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER20}, // S_CYBRAKDEMONELECTRICBARRIER19
-	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER21}, // S_CYBRAKDEMONELECTRICBARRIER20
-	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER22}, // S_CYBRAKDEMONELECTRICBARRIER21
-	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER23}, // S_CYBRAKDEMONELECTRICBARRIER22
-	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER24}, // S_CYBRAKDEMONELECTRICBARRIER23
-	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER24
-	{SPR_NULL, 0, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_DEINVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_DIE2}, // S_CYBRAKDEMONELECTRICBARRIER_DIE1
-	{SPR_NULL, 0, 0, {A_SetObjectFlags}, MF_PUSHABLE|MF_FIRE|MF_PAIN, 1, S_CYBRAKDEMONELECTRICBARRIER_DIE3}, // S_CYBRAKDEMONELECTRICBARRIER_DIE2
-	{SPR_NULL, 0, 20*TICRATE, {A_Scream}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS}, // S_CYBRAKDEMONELECTRICBARRIER_DIE3
-	{SPR_NULL, 0, 0, {A_CheckRandom}, 10, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK,
-	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS,
-	{SPR_NULL, 0, 0, {A_RandomStateRange}, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE,
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1,
-	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM2,
-	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM3,
-	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM4,
-	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM5,
-	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM6,
-	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM7,
-	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM8,
-	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM9,
-	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM10,
-	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM11,
-	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12,
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL,
-	{SPR_NULL, 0, 0, {A_Repeat}, 5*TICRATE, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK, S_CYBRAKDEMONELECTRICBARRIER_REVIVE1}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP,
-	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE2}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE1
-	{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, 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,
-	{SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
-	{SPR_NPLM, 3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4,
-	{SPR_NPLM, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE1, // Explode
-	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (6<<16), 256 + (48<<16), S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2, // Outer ring
-	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (1<<16), 32<<16, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3, // Center
-	{SPR_NULL, 0, 81, {A_Scream}, 0, 0, S_NULL}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4, // Sound
-
-	{SPR_MNPL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL}, //S_CYBRAKDEMONNAPALMBOMBSMALL,
-	{SPR_MNPL, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE1, // Explode
-	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (12<<16), 128 + (40<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2, // Outer ring
-	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (8<<16), 64 + (32<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3, // Inner ring
-	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (1<<16), 24<<16, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4, // Center
-	{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,   0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, //S_CYBRAKDEMONNAPALMFLAME_DIE,
-
-	{SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2}, //S_CYBRAKDEMONVILEEXPLOSION1,
-	{SPR_NULL, 0, 0, {A_ScoreRise}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION3}, //S_CYBRAKDEMONVILEEXPLOSION2,
-	{SPR_NULL, 0, 1, {A_BossScream}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION1}, //S_CYBRAKDEMONVILEEXPLOSION3,
+	{SPR_BRAK, 0, 10, {A_Look}, 0, 0, S_CYBRAKDEMON_IDLE, 0}, // S_CYBRAKDEMON_IDLE
+	{SPR_BRAK, 1, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK2, 0}, // S_CYBRAKDEMON_WALK1
+	{SPR_BRAK, 2, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK3, 0}, // S_CYBRAKDEMON_WALK2
+	{SPR_BRAK, 3, 8, {A_BrakChase}, 3, sfx_bestep, S_CYBRAKDEMON_WALK4, 0}, // S_CYBRAKDEMON_WALK3
+	{SPR_BRAK, 4, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK5, 0}, // S_CYBRAKDEMON_WALK4
+	{SPR_BRAK, 5, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK6, 0}, // S_CYBRAKDEMON_WALK5
+	{SPR_BRAK, 6, 8, {A_BrakChase}, 3, sfx_bestp2, S_CYBRAKDEMON_WALK1, 0}, // S_CYBRAKDEMON_WALK6
+	{SPR_BRAK, 7, 6, {A_RandomState}, S_CYBRAKDEMON_MISSILE_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1, 0}, // S_CYBRAKDEMON_CHOOSE_ATTACK1
+	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK2, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK1 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK3, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK2 // Fire
+	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK4, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK3 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK5, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK4 // Fire
+	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK6, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK5 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK6 // Fire
+	{SPR_BRAK, 7, 1, {A_Repeat}, 1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK2, 0}, // S_CYBRAKDEMON_FLAME_ATTACK1 // Reset
+	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FLAME_ATTACK3, 0}, // S_CYBRAKDEMON_FLAME_ATTACK2 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 2, {A_BrakFireShot}, MT_CYBRAKDEMON_FLAMESHOT, 128, S_CYBRAKDEMON_FLAME_ATTACK4, 0}, // S_CYBRAKDEMON_FLAME_ATTACK3 // Fire
+	{SPR_BRAK, 7, 1, {A_Repeat}, 30, S_CYBRAKDEMON_FLAME_ATTACK3, S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_FLAME_ATTACK4 // Loop
+	{SPR_BRAK, 0, 6, {A_RandomState}, S_CYBRAKDEMON_VILE_ATTACK1, S_CYBRAKDEMON_NAPALM_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1, 0}, // S_CYBRAKDEMON_CHOOSE_ATTACK2
+	{SPR_BRAK, 20, 0, {A_LinedefExecuteFromArg}, 5, 0, S_CYBRAKDEMON_VILE_ATTACK2, 0}, // S_CYBRAKDEMON_VILE_ATTACK1
+	{SPR_BRAK, 20, 24, {A_VileTarget}, MT_CYBRAKDEMON_TARGET_RETICULE, 1, S_CYBRAKDEMON_VILE_ATTACK3, 0}, // S_CYBRAKDEMON_VILE_ATTACK2
+	{SPR_BRAK, 19, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK4, 0}, // S_CYBRAKDEMON_VILE_ATTACK3
+	{SPR_BRAK, 18, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK5, 0}, // S_CYBRAKDEMON_VILE_ATTACK4
+	{SPR_BRAK, 8, 32, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK6, 0}, // S_CYBRAKDEMON_VILE_ATTACK5
+	{SPR_BRAK, 20 + FF_FULLBRIGHT, 28, {A_VileAttack}, sfx_brakrx, MT_CYBRAKDEMON_VILE_EXPLOSION + (1<<16), S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_VILE_ATTACK6
+	{SPR_BRAK, 0, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_NAPALM_ATTACK2, 0}, // S_CYBRAKDEMON_NAPALM_ATTACK1
+	{SPR_BRAK, 21 + FF_FULLBRIGHT, 8, {A_BrakLobShot}, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, 96, S_CYBRAKDEMON_NAPALM_ATTACK3, 0}, // S_CYBRAKDEMON_NAPALM_ATTACK2
+	{SPR_BRAK, 0, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_NAPALM_ATTACK3
+	{SPR_BRAK, 0, 0, {A_SetObjectFlags2}, MF2_FRET, 1, S_CYBRAKDEMON_FINISH_ATTACK2, 0}, // S_CYBRAKDEMON_FINISH_ATTACK1 // If just attacked, remove MF2_FRET w/out going back to spawnstate
+	{SPR_BRAK, 0, 0, {A_SetReactionTime}, 0, 0, S_CYBRAKDEMON_WALK1, 0}, // S_CYBRAKDEMON_FINISH_ATTACK2 // If just attacked, remove MF2_FRET w/out going back to spawnstate
+	{SPR_BRAK, 18, 24, {A_Pain}, 0, 0, S_CYBRAKDEMON_PAIN2, 0}, // S_CYBRAKDEMON_PAIN1
+	{SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1, 0}, // S_CYBRAKDEMON_PAIN2
+	{SPR_BRAK, 18, 0, {A_LinedefExecuteFromArg}, 4, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1, 0}, // S_CYBRAKDEMON_PAIN3
+	{SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2, 0}, // S_CYBRAKDEMON_DIE1
+	{SPR_BRAK, 18, 2, {A_BossScream}, 2, 0, S_CYBRAKDEMON_DIE3, 0}, // S_CYBRAKDEMON_DIE2
+	{SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4, 0}, // S_CYBRAKDEMON_DIE3
+	{SPR_BRAK, 13, 34, {A_BossDeath}, 0, 0, S_CYBRAKDEMON_DIE5, 0}, // S_CYBRAKDEMON_DIE4
+	{SPR_BRAK, 14, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE6, 0}, // S_CYBRAKDEMON_DIE5
+	{SPR_BRAK, 15, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE7, 0}, // S_CYBRAKDEMON_DIE6
+	{SPR_BRAK, 16, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE8, 0}, // S_CYBRAKDEMON_DIE7
+	{SPR_BRAK, 17, 34, {NULL}, sfx_befall, 0, S_CYBRAKDEMON_DIE8, 0}, // S_CYBRAKDEMON_DIE8
+	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 2, S_CYBRAKDEMON_IDLE, 0}, // S_CYBRAKDEMON_DEINVINCIBLERIZE
+	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 1, S_CYBRAKDEMON_IDLE, 0}, // S_CYBRAKDEMON_INVINCIBLERIZE
+
+	{SPR_RCKT, 0 + FF_FULLBRIGHT, 1, {A_SetObjectFlags2}, MF2_RAILRING, 2, S_CYBRAKDEMONMISSILE, 0}, // S_CYBRAKDEMONMISSILE
+	{SPR_RCKT, 1 + FF_FULLBRIGHT, 8, {A_Explode}, 0, 0, S_CYBRAKDEMONMISSILE_EXPLODE2, 0}, // S_CYBRAKDEMONMISSILE_EXPLODE1 //TODO: set missile mobj's "damage" to an appropriate radius
+	{SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3, 0}, // S_CYBRAKDEMONMISSILE_EXPLODE2
+	{SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL, 0}, // S_CYBRAKDEMONMISSILE_EXPLODE3
+
+	{SPR_FLME, FF_FULLBRIGHT  , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2, 0}, // S_CYBRAKDEMONFLAMESHOT_FLY1
+	{SPR_FLME, FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3, 0}, // S_CYBRAKDEMONFLAMESHOT_FLY2
+	{SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3, 0}, // S_CYBRAKDEMONFLAMESHOT_FLY3
+	{SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL, 0}, // S_CYBRAKDEMONFLAMESHOT_DIE
+
+	{SPR_FLAM, FF_FULLBRIGHT, 1, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST, 0}, // S_CYBRAKDEMONFLAMEREST
+
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2, 0}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND, 0}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER1, 0}, // S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER2, 0}, // S_CYBRAKDEMONELECTRICBARRIER1
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER3, 0}, // S_CYBRAKDEMONELECTRICBARRIER2
+	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER4, 0}, // S_CYBRAKDEMONELECTRICBARRIER3
+	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER5, 0}, // S_CYBRAKDEMONELECTRICBARRIER4
+	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER6, 0}, // S_CYBRAKDEMONELECTRICBARRIER5
+	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER7, 0}, // S_CYBRAKDEMONELECTRICBARRIER6
+	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER8, 0}, // S_CYBRAKDEMONELECTRICBARRIER7
+	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER9, 0}, // S_CYBRAKDEMONELECTRICBARRIER8
+	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER10, 0}, // S_CYBRAKDEMONELECTRICBARRIER9
+	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER11, 0}, // S_CYBRAKDEMONELECTRICBARRIER10
+	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER12, 0}, // S_CYBRAKDEMONELECTRICBARRIER11
+	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER13, 0}, // S_CYBRAKDEMONELECTRICBARRIER12
+	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER14, 0}, // S_CYBRAKDEMONELECTRICBARRIER13
+	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER15, 0}, // S_CYBRAKDEMONELECTRICBARRIER14
+	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER16, 0}, // S_CYBRAKDEMONELECTRICBARRIER15
+	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER17, 0}, // S_CYBRAKDEMONELECTRICBARRIER16
+	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER18, 0}, // S_CYBRAKDEMONELECTRICBARRIER17
+	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER19, 0}, // S_CYBRAKDEMONELECTRICBARRIER18
+	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER20, 0}, // S_CYBRAKDEMONELECTRICBARRIER19
+	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER21, 0}, // S_CYBRAKDEMONELECTRICBARRIER20
+	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER22, 0}, // S_CYBRAKDEMONELECTRICBARRIER21
+	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER23, 0}, // S_CYBRAKDEMONELECTRICBARRIER22
+	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER24, 0}, // S_CYBRAKDEMONELECTRICBARRIER23
+	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND, 0}, // S_CYBRAKDEMONELECTRICBARRIER24
+	{SPR_NULL, 0, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_DEINVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_DIE2, 0}, // S_CYBRAKDEMONELECTRICBARRIER_DIE1
+	{SPR_NULL, 0, 0, {A_SetObjectFlags}, MF_PUSHABLE|MF_FIRE|MF_PAIN, 1, S_CYBRAKDEMONELECTRICBARRIER_DIE3, 0}, // S_CYBRAKDEMONELECTRICBARRIER_DIE2
+	{SPR_NULL, 0, 20*TICRATE, {A_Scream}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS, 0}, // S_CYBRAKDEMONELECTRICBARRIER_DIE3
+	{SPR_NULL, 0, 0, {A_CheckRandom}, 10, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK,
+	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS,
+	{SPR_NULL, 0, 0, {A_RandomStateRange}, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE,
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1,
+	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM2,
+	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM3,
+	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM4,
+	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM5,
+	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM6,
+	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM7,
+	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM8,
+	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM9,
+	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM10,
+	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM11,
+	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12,
+	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL,
+	{SPR_NULL, 0, 0, {A_Repeat}, 5*TICRATE, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK, S_CYBRAKDEMONELECTRICBARRIER_REVIVE1, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP,
+	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE2, 0}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE1
+	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE3, 0}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE2
+	{SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL, 0}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE3
+
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2, 0}, // S_CYBRAKDEMONTARGETRETICULE1
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3, 0}, // S_CYBRAKDEMONTARGETRETICULE2
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|1, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4, 0}, // S_CYBRAKDEMONTARGETRETICULE3
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5, 0}, // S_CYBRAKDEMONTARGETRETICULE4
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|2, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6, 0}, // S_CYBRAKDEMONTARGETRETICULE5
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7, 0}, // S_CYBRAKDEMONTARGETRETICULE6
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|3, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8, 0}, // S_CYBRAKDEMONTARGETRETICULE7
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9, 0}, // S_CYBRAKDEMONTARGETRETICULE8
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|4, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10, 0}, // S_CYBRAKDEMONTARGETRETICULE9
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11, 0}, // S_CYBRAKDEMONTARGETRETICULE10
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|5, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12, 0}, // S_CYBRAKDEMONTARGETRETICULE11
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13, 0}, // S_CYBRAKDEMONTARGETRETICULE12
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14, 0}, // S_CYBRAKDEMONTARGETRETICULE13
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL, 0}, // S_CYBRAKDEMONTARGETRETICULE14
+
+	{SPR_HOOP, FF_TRANS50|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_CYBRAKDEMONTARGETDOT
+
+	{SPR_NPLM, 0, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1,
+	{SPR_NPLM, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
+	{SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
+	{SPR_NPLM, 3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4,
+	{SPR_NPLM, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE1, // Explode
+	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (6<<16), 256 + (48<<16), S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2, // Outer ring
+	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (1<<16), 32<<16, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3, // Center
+	{SPR_NULL, 0, 81, {A_Scream}, 0, 0, S_NULL, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4, // Sound
+
+	{SPR_MNPL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL,
+	{SPR_MNPL, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE1, // Explode
+	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (12<<16), 128 + (40<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2, // Outer ring
+	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (8<<16), 64 + (32<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3, // Inner ring
+	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (1<<16), 24<<16, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4, // Center
+	{SPR_NULL, 0, 24, {A_Scream}, 0, 0, S_NULL, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5, // Sound
+
+	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY2, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY1,
+	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY3, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY2,
+	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY4, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY3,
+	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY5, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY4,
+	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY6, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY5,
+	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY1, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY6,
+	{SPR_SFLM, FF_FULLBRIGHT,   0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL, 0}, //S_CYBRAKDEMONNAPALMFLAME_DIE,
+
+	{SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2, 0}, //S_CYBRAKDEMONVILEEXPLOSION1,
+	{SPR_NULL, 0, 0, {A_ScoreRise}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION3, 0}, //S_CYBRAKDEMONVILEEXPLOSION2,
+	{SPR_NULL, 0, 1, {A_BossScream}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION1, 0}, //S_CYBRAKDEMONVILEEXPLOSION3,
 
 	// Metal Sonic
-	{SPR_PLAY, SPR2_STND, -1, {NULL}, 0, 0, S_METALSONIC_RACE}, // S_METALSONIC_RACE
-
-	{SPR_METL,  4, -1, {NULL},         0, 0, S_METALSONIC_FLOAT},             // S_METALSONIC_FLOAT
-	{SPR_METL, 16|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
-	{SPR_METL, 15, -1, {NULL},         0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
-	{SPR_METL, 17, 20, {NULL},         0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
-	{SPR_METL, 18, -1, {NULL},         0, 0, S_METALSONIC_FLOAT},             // S_METALSONIC_GATHER
-	{SPR_METL,  6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH
-	{SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_FLOAT},             // S_METALSONIC_BOUNCE
-	{SPR_METL, 14, -1, {NULL},         0, 0, S_METALSONIC_FLOAT},             // S_METALSONIC_BADBOUNCE
-	{SPR_METL, 17, -1, {NULL},         0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
-	{SPR_METL, 15, 40, {A_Pain},       0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
-	{SPR_METL, 17,  2, {A_Fall},       0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
-	{SPR_METL, 17,  4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
-	{SPR_METL, 17,  0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
-	{SPR_METL, 17, -1, {A_BossDeath},  0, 0, S_NULL},             // S_METALSONIC_DEATH4
-	{SPR_METL, 15,  1, {A_BossScream},         0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
-	{SPR_METL, 15,  7, {NULL},                 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE2
-
-	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL},  // S_MSSHIELD_F1
-	{SPR_MSCF, FF_FULLBRIGHT|FF_ANIMATE|12, -1, {NULL}, 8, 2, S_NULL},  // S_MSSHIELD_F2
+	{SPR_PLAY, SPR2_STND, -1, {NULL}, 0, 0, S_METALSONIC_RACE, 0}, // S_METALSONIC_RACE
+
+	{SPR_METL,  4, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_FLOAT
+	{SPR_METL, 16|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN, 0}, // S_METALSONIC_VECTOR
+	{SPR_METL, 15, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_STUN
+	{SPR_METL, 17, 20, {NULL},         0, 0, S_METALSONIC_GATHER, 0},// S_METALSONIC_RAISE
+	{SPR_METL, 18, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_GATHER
+	{SPR_METL,  6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE, 0},// S_METALSONIC_DASH
+	{SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_BOUNCE
+	{SPR_METL, 14, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_BADBOUNCE
+	{SPR_METL, 17, -1, {NULL},         0, 0, S_METALSONIC_GATHER, 0},// S_METALSONIC_SHOOT
+	{SPR_METL, 15, 40, {A_Pain},       0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_PAIN
+	{SPR_METL, 17,  2, {A_Fall},       0, 0, S_METALSONIC_DEATH2, 0},// S_METALSONIC_DEATH1
+	{SPR_METL, 17,  4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3, 0},// S_METALSONIC_DEATH2
+	{SPR_METL, 17,  0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4, 0}, // S_METALSONIC_DEATH3
+	{SPR_METL, 17, -1, {A_BossDeath},  0, 0, S_NULL, 0},             // S_METALSONIC_DEATH4
+	{SPR_METL, 15,  1, {A_BossScream},         0, 0, S_METALSONIC_FLEE2, 0}, // S_METALSONIC_FLEE1
+	{SPR_METL, 15,  7, {NULL},                 0, 0, S_METALSONIC_FLEE1, 0}, // S_METALSONIC_FLEE2
+
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL, 0},  // S_MSSHIELD_F1
+	{SPR_MSCF, FF_FULLBRIGHT|FF_ANIMATE|12, -1, {NULL}, 8, 2, S_NULL, 0},  // S_MSSHIELD_F2
 
 	// Ring
-	{SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING}, // S_RING
+	{SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING, 0}, // S_RING
 
 	// Blue Sphere for special stages
-	{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE
+	{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUESPHERE
 	{SPR_SPHR, FF_FULLBRIGHT
 #ifdef MANIASPHERES
 							|FF_ANIMATE|FF_RANDOMANIM
 #endif
-													, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS
-	{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK
+													, -1, {NULL}, 1, 4, S_NULL, 0}, // S_BLUESPHEREBONUS
+	{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL, 0}, // S_BLUESPHERESPARK
 
 	// Bomb Sphere
-	{SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1
-	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2
-	{SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3
-	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4
+	{SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2, 0}, // S_BOMBSPHERE1
+	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3, 0}, // S_BOMBSPHERE2
+	{SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4, 0}, // S_BOMBSPHERE3
+	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1, 0}, // S_BOMBSPHERE4
 
 	// NiGHTS Chip
-	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE,    -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIP
-	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIPBONUS
+	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE,    -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIP
+	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIPBONUS
 
 	// NiGHTS Star
-	{SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_NIGHTSSTAR
-	{SPR_NSTR, 15, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSTARXMAS
+	{SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL, 0}, // S_NIGHTSSTAR
+	{SPR_NSTR, 15, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSSTARXMAS
 
 	// Gravity Well sprites for Egg Rock's Special Stage
-	{SPR_GWLG, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_GRAVWELLGREEN
-	{SPR_GWLR, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_GRAVWELLRED
+	{SPR_GWLG, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_GRAVWELLGREEN
+	{SPR_GWLR, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_GRAVWELLRED
 
 	// Individual Team Rings (now with shield attracting action! =P)
-	{SPR_TRNG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_TEAMRING},  // S_TEAMRING
+	{SPR_TRNG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_TEAMRING, 0},  // S_TEAMRING
 
 	// Special Stage Token
-	{SPR_TOKE, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_TOKEN}, // S_TOKEN
+	{SPR_TOKE, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_TOKEN, 0}, // S_TOKEN
 
 	// CTF Flags
-	{SPR_RFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REDFLAG
-	{SPR_BFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEFLAG
+	{SPR_RFLG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_REDFLAG
+	{SPR_BFLG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUEFLAG
 
 	// Emblem
-	{SPR_EMBM,  0, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM1
-	{SPR_EMBM,  1, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM2
-	{SPR_EMBM,  2, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM3
-	{SPR_EMBM,  3, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM4
-	{SPR_EMBM,  4, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM5
-	{SPR_EMBM,  5, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM6
-	{SPR_EMBM,  6, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM7
-	{SPR_EMBM,  7, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM8
-	{SPR_EMBM,  8, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM9
-	{SPR_EMBM,  9, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM10
-	{SPR_EMBM, 10, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM11
-	{SPR_EMBM, 11, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM12
-	{SPR_EMBM, 12, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM13
-	{SPR_EMBM, 13, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM14
-	{SPR_EMBM, 14, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM15
-	{SPR_EMBM, 15, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM16
-	{SPR_EMBM, 16, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM17
-	{SPR_EMBM, 17, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM18
-	{SPR_EMBM, 18, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM19
-	{SPR_EMBM, 19, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM20
-	{SPR_EMBM, 20, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM21
-	{SPR_EMBM, 21, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM22
-	{SPR_EMBM, 22, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM23
-	{SPR_EMBM, 23, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM24
-	{SPR_EMBM, 24, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM25
-	{SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM26
+	{SPR_EMBM,  0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM1
+	{SPR_EMBM,  1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM2
+	{SPR_EMBM,  2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM3
+	{SPR_EMBM,  3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM4
+	{SPR_EMBM,  4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM5
+	{SPR_EMBM,  5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM6
+	{SPR_EMBM,  6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM7
+	{SPR_EMBM,  7, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM8
+	{SPR_EMBM,  8, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM9
+	{SPR_EMBM,  9, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM10
+	{SPR_EMBM, 10, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM11
+	{SPR_EMBM, 11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM12
+	{SPR_EMBM, 12, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM13
+	{SPR_EMBM, 13, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM14
+	{SPR_EMBM, 14, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM15
+	{SPR_EMBM, 15, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM16
+	{SPR_EMBM, 16, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM17
+	{SPR_EMBM, 17, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM18
+	{SPR_EMBM, 18, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM19
+	{SPR_EMBM, 19, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM20
+	{SPR_EMBM, 20, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM21
+	{SPR_EMBM, 21, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM22
+	{SPR_EMBM, 22, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM23
+	{SPR_EMBM, 23, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM24
+	{SPR_EMBM, 24, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM25
+	{SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM26
 
 	// 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, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG1
+	{SPR_CEMG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG2
+	{SPR_CEMG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG3
+	{SPR_CEMG, FF_FULLBRIGHT|3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG4
+	{SPR_CEMG, FF_FULLBRIGHT|4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG5
+	{SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG6
+	{SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG7
 
 	// Emerald hunt shards
-	{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1
-	{SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD2
-	{SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD3
+	{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD1
+	{SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD2
+	{SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD3
 
 	// Bubble Source
-	{SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2}, // S_BUBBLES1
-	{SPR_BBLS, 1, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES3}, // S_BUBBLES2
-	{SPR_BBLS, 2, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES4}, // S_BUBBLES3
-	{SPR_BBLS, 3, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES1}, // S_BUBBLES4
+	{SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2, 0}, // S_BUBBLES1
+	{SPR_BBLS, 1, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES3, 0}, // S_BUBBLES2
+	{SPR_BBLS, 2, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES4, 0}, // S_BUBBLES3
+	{SPR_BBLS, 3, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES1, 0}, // S_BUBBLES4
 
 	// Level End Sign
-	{SPR_SIGN,                 0, -1, {A_SignPlayer}, -3, 0, S_NULL},                // S_SIGN
-	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN2},           // S_SIGNSPIN1
-	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN1, S_SIGNSPIN3}, // S_SIGNSPIN2
-	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -2, 0, S_SIGNSPIN4},           // S_SIGNSPIN3
-	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN5},           // S_SIGNSPIN4
-	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN4, S_SIGNSPIN6}, // S_SIGNSPIN5
-	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -3, 0, S_SIGNSPIN1},           // S_SIGNSPIN6
-	{SPR_SIGN,                 0,  1, {A_SignPlayer}, -1, 0, S_SIGNSLOW},            // S_SIGNPLAYER
-	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSLOW},            // S_SIGNSLOW
-	{SPR_SIGN,                 0, -1,         {NULL},  0, 0, S_NULL},                // S_SIGNSTOP
-	{SPR_SIGN, FF_PAPERSPRITE| 2, -1,         {NULL},  0, 0, S_NULL},                // S_SIGNBOARD
-	{SPR_SIGN, FF_PAPERSPRITE| 1, -1,         {NULL},  0, 29, S_NULL},               // S_EGGMANSIGN
-	{SPR_SIGN, FF_PAPERSPRITE|18, -1,         {NULL},  0, 29, S_NULL},               // S_CLEARSIGN
+	{SPR_SIGN,                 0, -1, {A_SignPlayer}, -3, 0, S_NULL, 0},                // S_SIGN
+	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN2, 0},           // S_SIGNSPIN1
+	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN1, S_SIGNSPIN3, 0}, // S_SIGNSPIN2
+	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -2, 0, S_SIGNSPIN4, 0},           // S_SIGNSPIN3
+	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN5, 0},           // S_SIGNSPIN4
+	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN4, S_SIGNSPIN6, 0}, // S_SIGNSPIN5
+	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -3, 0, S_SIGNSPIN1, 0},           // S_SIGNSPIN6
+	{SPR_SIGN,                 0,  1, {A_SignPlayer}, -1, 0, S_SIGNSLOW, 0},            // S_SIGNPLAYER
+	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSLOW, 0},            // S_SIGNSLOW
+	{SPR_SIGN,                 0, -1,         {NULL},  0, 0, S_NULL, 0},                // S_SIGNSTOP
+	{SPR_SIGN, FF_PAPERSPRITE| 2, -1,         {NULL},  0, 0, S_NULL, 0},                // S_SIGNBOARD
+	{SPR_SIGN, FF_PAPERSPRITE| 1, -1,         {NULL},  0, 29, S_NULL, 0},               // S_EGGMANSIGN
+	{SPR_SIGN, FF_PAPERSPRITE|18, -1,         {NULL},  0, 29, S_NULL, 0},               // S_CLEARSIGN
 
 	// Spike Ball
-	{SPR_SPIK, 0, 1, {NULL}, 0, 0, S_SPIKEBALL2}, // S_SPIKEBALL1
-	{SPR_SPIK, 1, 1, {NULL}, 0, 0, S_SPIKEBALL3}, // S_SPIKEBALL2
-	{SPR_SPIK, 2, 1, {NULL}, 0, 0, S_SPIKEBALL4}, // S_SPIKEBALL3
-	{SPR_SPIK, 3, 1, {NULL}, 0, 0, S_SPIKEBALL5}, // S_SPIKEBALL4
-	{SPR_SPIK, 4, 1, {NULL}, 0, 0, S_SPIKEBALL6}, // S_SPIKEBALL5
-	{SPR_SPIK, 5, 1, {NULL}, 0, 0, S_SPIKEBALL7}, // S_SPIKEBALL6
-	{SPR_SPIK, 6, 1, {NULL}, 0, 0, S_SPIKEBALL8}, // S_SPIKEBALL7
-	{SPR_SPIK, 7, 1, {NULL}, 0, 0, S_SPIKEBALL1}, // S_SPIKEBALL8
+	{SPR_SPIK, 0, 1, {NULL}, 0, 0, S_SPIKEBALL2, 0}, // S_SPIKEBALL1
+	{SPR_SPIK, 1, 1, {NULL}, 0, 0, S_SPIKEBALL3, 0}, // S_SPIKEBALL2
+	{SPR_SPIK, 2, 1, {NULL}, 0, 0, S_SPIKEBALL4, 0}, // S_SPIKEBALL3
+	{SPR_SPIK, 3, 1, {NULL}, 0, 0, S_SPIKEBALL5, 0}, // S_SPIKEBALL4
+	{SPR_SPIK, 4, 1, {NULL}, 0, 0, S_SPIKEBALL6, 0}, // S_SPIKEBALL5
+	{SPR_SPIK, 5, 1, {NULL}, 0, 0, S_SPIKEBALL7, 0}, // S_SPIKEBALL6
+	{SPR_SPIK, 6, 1, {NULL}, 0, 0, S_SPIKEBALL8, 0}, // S_SPIKEBALL7
+	{SPR_SPIK, 7, 1, {NULL}, 0, 0, S_SPIKEBALL1, 0}, // S_SPIKEBALL8
 
 	// Elemental 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_TFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_TEAM_SPINFIRE2}, // S_TEAM_SPINFIRE1
-	{SPR_TFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE3}, // S_TEAM_SPINFIRE2
-	{SPR_TFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE4}, // S_TEAM_SPINFIRE3
-	{SPR_TFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE5}, // S_TEAM_SPINFIRE4
-	{SPR_TFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE6}, // S_TEAM_SPINFIRE5
-	{SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1}, // S_TEAM_SPINFIRE6
+	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_SPINFIRE2, 0}, // S_SPINFIRE1
+	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_SPINFIRE3, 0}, // S_SPINFIRE2
+	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SPINFIRE4, 0}, // S_SPINFIRE3
+	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SPINFIRE5, 0}, // S_SPINFIRE4
+	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_SPINFIRE6, 0}, // S_SPINFIRE5
+	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_SPINFIRE1, 0}, // S_SPINFIRE6
+
+	{SPR_TFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_TEAM_SPINFIRE2, 0}, // S_TEAM_SPINFIRE1
+	{SPR_TFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE3, 0}, // S_TEAM_SPINFIRE2
+	{SPR_TFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE4, 0}, // S_TEAM_SPINFIRE3
+	{SPR_TFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE5, 0}, // S_TEAM_SPINFIRE4
+	{SPR_TFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE6, 0}, // S_TEAM_SPINFIRE5
+	{SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1, 0}, // S_TEAM_SPINFIRE6
 
 	// Floor Spike
-	{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended
-	{SPR_USPK, 1, 2, {A_Pain},         0, 0, S_SPIKE3}, // S_SPIKE2
-	{SPR_USPK, 2, 2, {NULL},           0, 0, S_SPIKE4}, // S_SPIKE3
-	{SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5}, // S_SPIKE4 -- Fully retracted
-	{SPR_USPK, 2, 2, {A_Pain},         0, 0, S_SPIKE6}, // S_SPIKE5
-	{SPR_USPK, 1, 2, {NULL},           0, 0, S_SPIKE1}, // S_SPIKE6
-	{SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles
-	{SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
+	{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2, 0}, // S_SPIKE1 -- Fully extended
+	{SPR_USPK, 1, 2, {A_Pain},         0, 0, S_SPIKE3, 0}, // S_SPIKE2
+	{SPR_USPK, 2, 2, {NULL},           0, 0, S_SPIKE4, 0}, // S_SPIKE3
+	{SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5, 0}, // S_SPIKE4 -- Fully retracted
+	{SPR_USPK, 2, 2, {A_Pain},         0, 0, S_SPIKE6, 0}, // S_SPIKE5
+	{SPR_USPK, 1, 2, {NULL},           0, 0, S_SPIKE1, 0}, // S_SPIKE6
+	{SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL, 0}, // S_SPIKED1 -- Busted spike particles
+	{SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL, 0}, // S_SPIKED2
 
 	// Wall Spike
-	{SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2}, // S_WALLSPIKE1 -- Fully extended
-	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE3}, // S_WALLSPIKE2
-	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE4}, // S_WALLSPIKE3
-	{SPR_WSPK, 3|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 0, 0, S_WALLSPIKE5}, // S_WALLSPIKE4 -- Fully retracted
-	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE6}, // S_WALLSPIKE5
-	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE1}, // S_WALLSPIKE6
-	{SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKEBASE -- Base
-	{SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED1 -- Busted spike particles
-	{SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED2
+	{SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2, 0}, // S_WALLSPIKE1 -- Fully extended
+	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE3, 0}, // S_WALLSPIKE2
+	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE4, 0}, // S_WALLSPIKE3
+	{SPR_WSPK, 3|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 0, 0, S_WALLSPIKE5, 0}, // S_WALLSPIKE4 -- Fully retracted
+	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE6, 0}, // S_WALLSPIKE5
+	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE1, 0}, // S_WALLSPIKE6
+	{SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLSPIKEBASE -- Base
+	{SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLSPIKED1 -- Busted spike particles
+	{SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLSPIKED2
 
 	// Starpost
-	{SPR_STPT, 0            , -1, {NULL},  0, 0, S_NULL},           // S_STARPOST_IDLE
-	{SPR_STPT, FF_ANIMATE|17, -1, {NULL},  5, 1, S_NULL},           // S_STARPOST_FLASH
-	{SPR_STPT, FF_ANIMATE|13,  2, {NULL},  1, 1, S_STARPOST_SPIN},  // S_STARPOST_STARTSPIN
-	{SPR_STPT, FF_ANIMATE|1 , 23, {NULL}, 11, 1, S_STARPOST_ENDSPIN}, // S_STARPOST_SPIN
-	{SPR_STPT, FF_ANIMATE|15,  2, {NULL},  1, 1, S_STARPOST_FLASH}, // S_STARPOST_ENDSPIN
+	{SPR_STPT, 0            , -1, {NULL},  0, 0, S_NULL, 0},           // S_STARPOST_IDLE
+	{SPR_STPT, FF_ANIMATE|17, -1, {NULL},  5, 1, S_NULL, 0},           // S_STARPOST_FLASH
+	{SPR_STPT, FF_ANIMATE|13,  2, {NULL},  1, 1, S_STARPOST_SPIN, 0},  // S_STARPOST_STARTSPIN
+	{SPR_STPT, FF_ANIMATE|1 , 23, {NULL}, 11, 1, S_STARPOST_ENDSPIN, 0}, // S_STARPOST_SPIN
+	{SPR_STPT, FF_ANIMATE|15,  2, {NULL},  1, 1, S_STARPOST_FLASH, 0}, // S_STARPOST_ENDSPIN
 
 	// Big floating mine
-	{SPR_BMNE, 0,  2, {A_Look},      ((224<<FRACBITS)|1), 0, S_BIGMINE_IDLE},   // S_BIGMINE_IDLE
-	{SPR_BMNE, 1,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT2}, // S_BIGMINE_ALERT1
-	{SPR_BMNE, 2,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT3}, // S_BIGMINE_ALERT2
-	{SPR_BMNE, 0,  1, {A_Look},      ((224<<FRACBITS)|1), 1, S_BIGMINE_IDLE},   // S_BIGMINE_ALERT3
-	{SPR_BMNE, 3, 25, {A_Pain},           0,            0, S_BIGMINE_SET2},   // S_BIGMINE_SET1
-	{SPR_BMNE, 3, 10, {A_SetObjectFlags}, MF_SHOOTABLE, 1, S_BIGMINE_SET3},   // S_BIGMINE_SET1
-	{SPR_BMNE, 3,  1, {A_MineExplode},    0,            0, S_BIGMINE_BLAST1}, // S_BIGMINE_SET3
-	{SPR_BMNB,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST2}, // S_BIGMINE_BLAST1
-	{SPR_BMNB, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST3}, // S_BIGMINE_BLAST2
-	{SPR_BMNB, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST4}, // S_BIGMINE_BLAST3
-	{SPR_BMNB, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST5}, // S_BIGMINE_BLAST4
-	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BIGMINE_BLAST5
+	{SPR_BMNE, 0,  2, {A_Look},      ((224<<FRACBITS)|1), 0, S_BIGMINE_IDLE, 0},   // S_BIGMINE_IDLE
+	{SPR_BMNE, 1,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT2, 0}, // S_BIGMINE_ALERT1
+	{SPR_BMNE, 2,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT3, 0}, // S_BIGMINE_ALERT2
+	{SPR_BMNE, 0,  1, {A_Look},      ((224<<FRACBITS)|1), 1, S_BIGMINE_IDLE, 0},   // S_BIGMINE_ALERT3
+	{SPR_BMNE, 3, 25, {A_Pain},           0,            0, S_BIGMINE_SET2, 0},   // S_BIGMINE_SET1
+	{SPR_BMNE, 3, 10, {A_SetObjectFlags}, MF_SHOOTABLE, 1, S_BIGMINE_SET3, 0},   // S_BIGMINE_SET1
+	{SPR_BMNE, 3,  1, {A_MineExplode},    0,            0, S_BIGMINE_BLAST1, 0}, // S_BIGMINE_SET3
+	{SPR_BMNB,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST2, 0}, // S_BIGMINE_BLAST1
+	{SPR_BMNB, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST3, 0}, // S_BIGMINE_BLAST2
+	{SPR_BMNB, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST4, 0}, // S_BIGMINE_BLAST3
+	{SPR_BMNB, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST5, 0}, // S_BIGMINE_BLAST4
+	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BIGMINE_BLAST5
 
 	// Cannon launcher
-	{SPR_NULL, 0, 1,    {A_FindTarget},     MT_PLAYER,         0, S_CANNONLAUNCHER2}, // S_CANNONLAUNCHER1
-	{SPR_NULL, 0, 1,       {A_LobShot}, MT_CANNONBALL, 4*TICRATE, S_CANNONLAUNCHER3}, // S_CANNONLAUNCHER2
-	{SPR_NULL, 0, 2, {A_SetRandomTics},     TICRATE/2, 3*TICRATE, S_CANNONLAUNCHER1}, // S_CANNONLAUNCHER3
+	{SPR_NULL, 0, 1,    {A_FindTarget},     MT_PLAYER,         0, S_CANNONLAUNCHER2, 0}, // S_CANNONLAUNCHER1
+	{SPR_NULL, 0, 1,       {A_LobShot}, MT_CANNONBALL, 4*TICRATE, S_CANNONLAUNCHER3, 0}, // S_CANNONLAUNCHER2
+	{SPR_NULL, 0, 2, {A_SetRandomTics},     TICRATE/2, 3*TICRATE, S_CANNONLAUNCHER1, 0}, // S_CANNONLAUNCHER3
 
 	// Monitor Miscellany
-	{SPR_NSPK, 0, 16, {NULL}, 0, 0, S_BOXSPARKLE2}, // S_BOXSPARKLE1
-	{SPR_NSPK, 1, 12, {NULL}, 0, 0, S_BOXSPARKLE3}, // S_BOXSPARKLE2
-	{SPR_NSPK, 2,  8, {NULL}, 0, 0, S_BOXSPARKLE4}, // S_BOXSPARKLE3
-	{SPR_NSPK, 3,  4, {NULL}, 0, 0, S_NULL},        // S_BOXSPARKLE4
-
-	{SPR_MSTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE},  // S_BOX_FLICKER
-	{SPR_MSTV, 0,  4, {A_MonitorPop}, 0, 0, S_BOX_POP2}, // S_BOX_POP1
-	{SPR_MSTV, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BOX_POP2
-
-	{SPR_XLTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE},  // S_GOLDBOX_FLICKER
-	{SPR_XLTV, 1, 89, {A_GoldMonitorPop}, 0, 0, S_GOLDBOX_OFF2}, // S_GOLDBOX_OFF1
-	{SPR_XLTV, 2,  4, {A_PlayAttackSound}, 0, 0, S_GOLDBOX_OFF3}, // S_GOLDBOX_OFF2
-	{SPR_XLTV, 3,  4, {NULL}, 0, 0, S_GOLDBOX_OFF4}, // S_GOLDBOX_OFF3
-	{SPR_XLTV, 4,  4, {NULL}, 0, 0, S_GOLDBOX_OFF5}, // S_GOLDBOX_OFF4
-	{SPR_XLTV, 5,  2, {NULL}, 0, 0, S_GOLDBOX_OFF6}, // S_GOLDBOX_OFF5
-	{SPR_XLTV, 6,  2, {NULL}, 0, 0, S_GOLDBOX_OFF7}, // S_GOLDBOX_OFF6
-	{SPR_XLTV, 6,  0, {A_GoldMonitorRestore}, 0, 0, S_SPAWNSTATE}, // S_GOLDBOX_OFF7
+	{SPR_NSPK, 0, 16, {NULL}, 0, 0, S_BOXSPARKLE2, 0}, // S_BOXSPARKLE1
+	{SPR_NSPK, 1, 12, {NULL}, 0, 0, S_BOXSPARKLE3, 0}, // S_BOXSPARKLE2
+	{SPR_NSPK, 2,  8, {NULL}, 0, 0, S_BOXSPARKLE4, 0}, // S_BOXSPARKLE3
+	{SPR_NSPK, 3,  4, {NULL}, 0, 0, S_NULL, 0},        // S_BOXSPARKLE4
+
+	{SPR_MSTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE, 0},  // S_BOX_FLICKER
+	{SPR_MSTV, 0,  4, {A_MonitorPop}, 0, 0, S_BOX_POP2, 0}, // S_BOX_POP1
+	{SPR_MSTV, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BOX_POP2
+
+	{SPR_XLTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE, 0},  // S_GOLDBOX_FLICKER
+	{SPR_XLTV, 1, 89, {A_GoldMonitorPop}, 0, 0, S_GOLDBOX_OFF2, 0}, // S_GOLDBOX_OFF1
+	{SPR_XLTV, 2,  4, {A_PlayAttackSound}, 0, 0, S_GOLDBOX_OFF3, 0}, // S_GOLDBOX_OFF2
+	{SPR_XLTV, 3,  4, {NULL}, 0, 0, S_GOLDBOX_OFF4, 0}, // S_GOLDBOX_OFF3
+	{SPR_XLTV, 4,  4, {NULL}, 0, 0, S_GOLDBOX_OFF5, 0}, // S_GOLDBOX_OFF4
+	{SPR_XLTV, 5,  2, {NULL}, 0, 0, S_GOLDBOX_OFF6, 0}, // S_GOLDBOX_OFF5
+	{SPR_XLTV, 6,  2, {NULL}, 0, 0, S_GOLDBOX_OFF7, 0}, // S_GOLDBOX_OFF6
+	{SPR_XLTV, 6,  0, {A_GoldMonitorRestore}, 0, 0, S_SPAWNSTATE, 0}, // S_GOLDBOX_OFF7
 
 	// Monitor States (one per box)
-	{SPR_TVMY, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_MYSTERY_BOX
-	{SPR_TVRI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_RING_BOX
-	{SPR_TVPI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_PITY_BOX
-	{SPR_TVAT, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_ATTRACT_BOX
-	{SPR_TVFO, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_FORCE_BOX
-	{SPR_TVAR, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_ARMAGEDDON_BOX
-	{SPR_TVWW, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_WHIRLWIND_BOX
-	{SPR_TVEL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_ELEMENTAL_BOX
-	{SPR_TVSS, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SNEAKERS_BOX
-	{SPR_TVIV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_INVULN_BOX
-	{SPR_TV1U, 0, 2, {A_1upThinker}, 0, 0, S_BOX_FLICKER}, // S_1UP_BOX
-	{SPR_TVEG, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_EGGMAN_BOX
-	{SPR_TVMX, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_MIXUP_BOX
-	{SPR_TVGV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_GRAVITY_BOX
-	{SPR_TVRC, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_RECYCLER_BOX
-	{SPR_TV1K, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SCORE1K_BOX
-	{SPR_TVTK, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SCORE10K_BOX
-	{SPR_TVFL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_FLAMEAURA_BOX
-	{SPR_TVBB, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_BUBBLEWRAP_BOX
-	{SPR_TVZP, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_THUNDERCOIN_BOX
+	{SPR_TVMY, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_MYSTERY_BOX
+	{SPR_TVRI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_RING_BOX
+	{SPR_TVPI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_PITY_BOX
+	{SPR_TVAT, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_ATTRACT_BOX
+	{SPR_TVFO, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_FORCE_BOX
+	{SPR_TVAR, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_ARMAGEDDON_BOX
+	{SPR_TVWW, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_WHIRLWIND_BOX
+	{SPR_TVEL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_ELEMENTAL_BOX
+	{SPR_TVSS, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_SNEAKERS_BOX
+	{SPR_TVIV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_INVULN_BOX
+	{SPR_TV1U, 0, 2, {A_1upThinker}, 0, 0, S_BOX_FLICKER, 0}, // S_1UP_BOX
+	{SPR_TVEG, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_EGGMAN_BOX
+	{SPR_TVMX, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_MIXUP_BOX
+	{SPR_TVGV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_GRAVITY_BOX
+	{SPR_TVRC, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_RECYCLER_BOX
+	{SPR_TV1K, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_SCORE1K_BOX
+	{SPR_TVTK, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_SCORE10K_BOX
+	{SPR_TVFL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_FLAMEAURA_BOX
+	{SPR_TVBB, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_BUBBLEWRAP_BOX
+	{SPR_TVZP, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_THUNDERCOIN_BOX
 
 	// Gold Repeat Monitor States (one per box)
-	{SPR_TVPI, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_PITY_GOLDBOX
-	{SPR_TVAT, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_ATTRACT_GOLDBOX
-	{SPR_TVFO, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_FORCE_GOLDBOX
-	{SPR_TVAR, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_ARMAGEDDON_GOLDBOX
-	{SPR_TVWW, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_WHIRLWIND_GOLDBOX
-	{SPR_TVEL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_ELEMENTAL_GOLDBOX
-	{SPR_TVSS, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_SNEAKERS_GOLDBOX
-	{SPR_TVIV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_INVULN_GOLDBOX
-	{SPR_TVEG, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_EGGMAN_GOLDBOX
-	{SPR_TVGV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_GRAVITY_GOLDBOX
-	{SPR_TVFL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_FLAMEAURA_GOLDBOX
-	{SPR_TVBB, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_BUBBLEWRAP_GOLDBOX
-	{SPR_TVZP, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_THUNDERCOIN_GOLDBOX
+	{SPR_TVPI, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_PITY_GOLDBOX
+	{SPR_TVAT, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_ATTRACT_GOLDBOX
+	{SPR_TVFO, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_FORCE_GOLDBOX
+	{SPR_TVAR, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_ARMAGEDDON_GOLDBOX
+	{SPR_TVWW, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_WHIRLWIND_GOLDBOX
+	{SPR_TVEL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_ELEMENTAL_GOLDBOX
+	{SPR_TVSS, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_SNEAKERS_GOLDBOX
+	{SPR_TVIV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_INVULN_GOLDBOX
+	{SPR_TVEG, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_EGGMAN_GOLDBOX
+	{SPR_TVGV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_GRAVITY_GOLDBOX
+	{SPR_TVFL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_FLAMEAURA_GOLDBOX
+	{SPR_TVBB, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_BUBBLEWRAP_GOLDBOX
+	{SPR_TVZP, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_THUNDERCOIN_GOLDBOX
 
 	// Team Ring Boxes (these are special)
-	{SPR_TRRI, 0, 2, {NULL}, 0, 0, S_RING_REDBOX2}, // S_RING_REDBOX1
-	{SPR_TRRI, 1, 1, {NULL}, 0, 0, S_RING_REDBOX1}, // S_RING_REDBOX2
-	{SPR_TRRI, 1, 4, {A_MonitorPop}, 0, 0, S_REDBOX_POP2},  // S_REDBOX_POP1
-	{SPR_TRRI, 2, -1, {NULL}, 0, 0, S_NULL},        // S_REDBOX_POP2
+	{SPR_TRRI, 0, 2, {NULL}, 0, 0, S_RING_REDBOX2, 0}, // S_RING_REDBOX1
+	{SPR_TRRI, 1, 1, {NULL}, 0, 0, S_RING_REDBOX1, 0}, // S_RING_REDBOX2
+	{SPR_TRRI, 1, 4, {A_MonitorPop}, 0, 0, S_REDBOX_POP2, 0},  // S_REDBOX_POP1
+	{SPR_TRRI, 2, -1, {NULL}, 0, 0, S_NULL, 0},        // S_REDBOX_POP2
 
-	{SPR_TBRI, 0, 2, {NULL}, 0, 0, S_RING_BLUEBOX2}, // S_RING_BLUEBOX1
-	{SPR_TBRI, 1, 1, {NULL}, 0, 0, S_RING_BLUEBOX1}, // S_RING_BLUEBOX2
-	{SPR_TBRI, 1, 4, {A_MonitorPop}, 0, 0, S_BLUEBOX_POP2},  // S_BLUEBOX_POP1
-	{SPR_TBRI, 2, -1, {NULL}, 0, 0, S_NULL},         // S_BLUEBOX_POP2
+	{SPR_TBRI, 0, 2, {NULL}, 0, 0, S_RING_BLUEBOX2, 0}, // S_RING_BLUEBOX1
+	{SPR_TBRI, 1, 1, {NULL}, 0, 0, S_RING_BLUEBOX1, 0}, // S_RING_BLUEBOX2
+	{SPR_TBRI, 1, 4, {A_MonitorPop}, 0, 0, S_BLUEBOX_POP2, 0},  // S_BLUEBOX_POP1
+	{SPR_TBRI, 2, -1, {NULL}, 0, 0, S_NULL, 0},         // S_BLUEBOX_POP2
 
 	// Box Icons -- 2 states each, animation and action
-	{SPR_TVRI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RING_ICON2}, // S_RING_ICON1
-	{SPR_TVRI, 2, 18, {A_RingBox}, 0, 0, S_NULL}, // S_RING_ICON2
+	{SPR_TVRI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RING_ICON2, 0}, // S_RING_ICON1
+	{SPR_TVRI, 2, 18, {A_RingBox}, 0, 0, S_NULL, 0}, // S_RING_ICON2
 
-	{SPR_TVPI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_PITY_ICON2}, // S_PITY_ICON1
-	{SPR_TVPI, 2, 18, {A_GiveShield}, SH_PITY, 0, S_NULL},  // S_PITY_ICON2
+	{SPR_TVPI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_PITY_ICON2, 0}, // S_PITY_ICON1
+	{SPR_TVPI, 2, 18, {A_GiveShield}, SH_PITY, 0, S_NULL, 0},  // S_PITY_ICON2
 
-	{SPR_TVAT, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ATTRACT_ICON2}, // S_ATTRACT_ICON1
-	{SPR_TVAT, 2, 18, {A_GiveShield}, SH_ATTRACT, 0, S_NULL}, // S_ATTRACT_ICON2
+	{SPR_TVAT, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ATTRACT_ICON2, 0}, // S_ATTRACT_ICON1
+	{SPR_TVAT, 2, 18, {A_GiveShield}, SH_ATTRACT, 0, S_NULL, 0}, // S_ATTRACT_ICON2
 
-	{SPR_TVFO, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FORCE_ICON2}, // S_FORCE_ICON1
-	{SPR_TVFO, 2, 18, {A_GiveShield}, SH_FORCE|1, 0, S_NULL}, // S_FORCE_ICON2
+	{SPR_TVFO, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FORCE_ICON2, 0}, // S_FORCE_ICON1
+	{SPR_TVFO, 2, 18, {A_GiveShield}, SH_FORCE|1, 0, S_NULL, 0}, // S_FORCE_ICON2
 
-	{SPR_TVAR, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ARMAGEDDON_ICON2}, // S_ARMAGEDDON_ICON1
-	{SPR_TVAR, 2, 18, {A_GiveShield}, SH_ARMAGEDDON, 0, S_NULL}, // S_ARMAGEDDON_ICON2
+	{SPR_TVAR, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ARMAGEDDON_ICON2, 0}, // S_ARMAGEDDON_ICON1
+	{SPR_TVAR, 2, 18, {A_GiveShield}, SH_ARMAGEDDON, 0, S_NULL, 0}, // S_ARMAGEDDON_ICON2
 
-	{SPR_TVWW, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_WHIRLWIND_ICON2}, // S_WHIRLWIND_ICON1
-	{SPR_TVWW, 2, 18, {A_GiveShield}, SH_WHIRLWIND, 0, S_NULL}, // S_WHIRLWIND_ICON2
+	{SPR_TVWW, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_WHIRLWIND_ICON2, 0}, // S_WHIRLWIND_ICON1
+	{SPR_TVWW, 2, 18, {A_GiveShield}, SH_WHIRLWIND, 0, S_NULL, 0}, // S_WHIRLWIND_ICON2
 
-	{SPR_TVEL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ELEMENTAL_ICON2}, // S_ELEMENTAL_ICON1
-	{SPR_TVEL, 2, 18, {A_GiveShield}, SH_ELEMENTAL, 0, S_NULL}, // S_ELEMENTAL_ICON2
+	{SPR_TVEL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ELEMENTAL_ICON2, 0}, // S_ELEMENTAL_ICON1
+	{SPR_TVEL, 2, 18, {A_GiveShield}, SH_ELEMENTAL, 0, S_NULL, 0}, // S_ELEMENTAL_ICON2
 
-	{SPR_TVSS, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SNEAKERS_ICON2}, // S_SNEAKERS_ICON1
-	{SPR_TVSS, 2, 18, {A_SuperSneakers}, 0, 0, S_NULL}, // S_SNEAKERS_ICON2
+	{SPR_TVSS, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SNEAKERS_ICON2, 0}, // S_SNEAKERS_ICON1
+	{SPR_TVSS, 2, 18, {A_SuperSneakers}, 0, 0, S_NULL, 0}, // S_SNEAKERS_ICON2
 
-	{SPR_TVIV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_INVULN_ICON2}, // S_INVULN_ICON1
-	{SPR_TVIV, 2, 18, {A_Invincibility}, 0, 0, S_NULL}, // S_INVULN_ICON2
+	{SPR_TVIV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_INVULN_ICON2, 0}, // S_INVULN_ICON1
+	{SPR_TVIV, 2, 18, {A_Invincibility}, 0, 0, S_NULL, 0}, // S_INVULN_ICON2
 
-	{SPR_TV1U, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_1UP_ICON2}, // S_1UP_ICON1
-	{SPR_TV1U, 2, 18, {A_ExtraLife},  0, 0, S_NULL},  // S_1UP_ICON2
+	{SPR_TV1U, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_1UP_ICON2, 0}, // S_1UP_ICON1
+	{SPR_TV1U, 2, 18, {A_ExtraLife},  0, 0, S_NULL, 0},  // S_1UP_ICON2
 
-	{SPR_TVEG, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_EGGMAN_ICON2}, // S_EGGMAN_ICON1
-	{SPR_TVEG, 2, 18, {A_EggmanBox}, 0, 0, S_NULL}, // S_EGGMAN_ICON2
+	{SPR_TVEG, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_EGGMAN_ICON2, 0}, // S_EGGMAN_ICON1
+	{SPR_TVEG, 2, 18, {A_EggmanBox}, 0, 0, S_NULL, 0}, // S_EGGMAN_ICON2
 
-	{SPR_TVMX, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_MIXUP_ICON2}, // S_MIXUP_ICON1
-	{SPR_TVMX, 2, 18, {A_MixUp}, 0, 0, S_NULL}, // S_MIXUP_ICON2
+	{SPR_TVMX, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_MIXUP_ICON2, 0}, // S_MIXUP_ICON1
+	{SPR_TVMX, 2, 18, {A_MixUp}, 0, 0, S_NULL, 0}, // S_MIXUP_ICON2
 
-	{SPR_TVGV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_GRAVITY_ICON2}, // S_GRAVITY_ICON1
-	{SPR_TVGV, 2, 18, {A_GravityBox}, 0, 0, S_NULL}, // S_GRAVITY_ICON2
+	{SPR_TVGV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_GRAVITY_ICON2, 0}, // S_GRAVITY_ICON1
+	{SPR_TVGV, 2, 18, {A_GravityBox}, 0, 0, S_NULL, 0}, // S_GRAVITY_ICON2
 
-	{SPR_TVRC, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RECYCLER_ICON2}, // S_RECYCLER_ICON1
-	{SPR_TVRC, 2, 18, {A_RecyclePowers}, 0, 0, S_NULL}, // S_RECYCLER_ICON2
+	{SPR_TVRC, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RECYCLER_ICON2, 0}, // S_RECYCLER_ICON1
+	{SPR_TVRC, 2, 18, {A_RecyclePowers}, 0, 0, S_NULL, 0}, // S_RECYCLER_ICON2
 
-	{SPR_TV1K, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE1K_ICON2}, // S_SCORE1K_ICON1
-	{SPR_TV1K, 2, 18, {A_AwardScore}, 0, 0, S_NULL}, // S_SCORE1K_ICON2
+	{SPR_TV1K, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE1K_ICON2, 0}, // S_SCORE1K_ICON1
+	{SPR_TV1K, 2, 18, {A_AwardScore}, 0, 0, S_NULL, 0}, // S_SCORE1K_ICON2
 
-	{SPR_TVTK, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE10K_ICON2}, // S_SCORE10K_ICON1
-	{SPR_TVTK, 2, 18, {A_AwardScore}, 0, 0, S_NULL}, // S_SCORE10K_ICON2
+	{SPR_TVTK, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE10K_ICON2, 0}, // S_SCORE10K_ICON1
+	{SPR_TVTK, 2, 18, {A_AwardScore}, 0, 0, S_NULL, 0}, // S_SCORE10K_ICON2
 
-	{SPR_TVFL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FLAMEAURA_ICON2}, // S_FLAMEAURA_ICON1
-	{SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL}, // S_FLAMEAURA_ICON2
+	{SPR_TVFL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FLAMEAURA_ICON2, 0}, // S_FLAMEAURA_ICON1
+	{SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL, 0}, // S_FLAMEAURA_ICON2
 
-	{SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2}, // S_BUBBLEWRAP_ICON1
-	{SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLEWRAP_ICON2
+	{SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2, 0}, // S_BUBBLEWRAP_ICON1
+	{SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL, 0}, // S_BUBBLEWRAP_ICON2
 
-	{SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2}, // S_THUNDERCOIN_ICON1
-	{SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL}, // S_THUNDERCOIN_ICON2
+	{SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2, 0}, // S_THUNDERCOIN_ICON1
+	{SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL, 0}, // S_THUNDERCOIN_ICON2
 
 	// ---
 
-	{SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET}, // S_ROCKET
+	{SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET, 0}, // S_ROCKET
 
-	{SPR_LASR, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_NULL}, // S_LASER
-	{SPR_LASR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_LASER2
-	{SPR_LASR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL}, // S_LASERFLASH
+	{SPR_LASR, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LASER
+	{SPR_LASR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LASER2
+	{SPR_LASR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LASERFLASH
 
-	{SPR_LASF,                           FF_FULLBRIGHT|0,       2,           {NULL}, 0, 0, S_LASERFLAME2}, // S_LASERFLAME1
-	{SPR_LASF,                           FF_FULLBRIGHT|1,       1, {A_ChangeHeight}, 156*FRACUNIT, 3, S_LASERFLAME3}, // S_LASERFLAME2
-	{SPR_LASF,                           FF_FULLBRIGHT|2,       0, {A_ChangeHeight}, 32*FRACUNIT, 3, S_LASERFLAME4}, // S_LASERFLAME3
-	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|2,       4,           {NULL}, 1, 2, S_LASERFLAME5}, // S_LASERFLAME4
-	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|4,      28,           {NULL}, 2, 2, S_NULL}, // S_LASERFLAME5
+	{SPR_LASF,                           FF_FULLBRIGHT|0,       2,           {NULL}, 0, 0, S_LASERFLAME2, 0}, // S_LASERFLAME1
+	{SPR_LASF,                           FF_FULLBRIGHT|1,       1, {A_ChangeHeight}, 156*FRACUNIT, 3, S_LASERFLAME3, 0}, // S_LASERFLAME2
+	{SPR_LASF,                           FF_FULLBRIGHT|2,       0, {A_ChangeHeight}, 32*FRACUNIT, 3, S_LASERFLAME4, 0}, // S_LASERFLAME3
+	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|2,       4,           {NULL}, 1, 2, S_LASERFLAME5, 0}, // S_LASERFLAME4
+	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|4,      28,           {NULL}, 2, 2, S_NULL, 0}, // S_LASERFLAME5
 
-	{SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO}, // S_TORPEDO
+	{SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO, 0}, // S_TORPEDO
 
-	{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
+	{SPR_ENRG, FF_FULLBRIGHT|FF_TRANS30, 1, {NULL}, 0, 0, S_ENERGYBALL2, 0}, // S_ENERGYBALL1
+	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ENERGYBALL1, 0}, // S_ENERGYBALL2
 
 	// Skim Mine (also dropped by Jetty-Syn bomber)
-	{SPR_MINE, 0, -1, {NULL}, 0, 0, S_NULL},           // S_MINE1
-	{SPR_MINE, 1, 1, {A_Fall}, 0, 0, S_MINE_BOOM2},    // S_MINE_BOOM1
-	{SPR_MINE, 2, 3, {A_Scream}, 0, 0, S_MINE_BOOM3},  // S_MINE_BOOM2
-	{SPR_MINE, 3, 3, {A_Explode}, 0, 0, S_MINE_BOOM4}, // S_MINE_BOOM3
-	{SPR_MINE, 4, 3, {NULL}, 0, 0, S_NULL},            // S_MINE_BOOM4
+	{SPR_MINE, 0, -1, {NULL}, 0, 0, S_NULL, 0},           // S_MINE1
+	{SPR_MINE, 1, 1, {A_Fall}, 0, 0, S_MINE_BOOM2, 0},    // S_MINE_BOOM1
+	{SPR_MINE, 2, 3, {A_Scream}, 0, 0, S_MINE_BOOM3, 0},  // S_MINE_BOOM2
+	{SPR_MINE, 3, 3, {A_Explode}, 0, 0, S_MINE_BOOM4, 0}, // S_MINE_BOOM3
+	{SPR_MINE, 4, 3, {NULL}, 0, 0, S_NULL, 0},            // S_MINE_BOOM4
 
 	// 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, {NULL}, 0, 0, S_JETBULLET2, 0}, // S_JETBULLET1
+	{SPR_JBUL, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETBULLET1, 0}, // 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, {NULL}, 0, 0, S_TURRETLASER, 0},          // S_TURRETLASER
+	{SPR_TRLS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TURRETLASEREXPLODE2, 0},  // S_TURRETLASEREXPLODE1
+	{SPR_TRLS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL, 0},                 // S_TURRETLASEREXPLODE2
 
-	{SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANNONBALL1
+	{SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANNONBALL1
 
-	{SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ARROW
-	{SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL}, // S_ARROWBONK
+	{SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARROW
+	{SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL, 0}, // S_ARROWBONK
 
-	{SPR_CFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 5, 2, S_NULL}, // S_DEMONFIRE
+	{SPR_CFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 5, 2, S_NULL, 0}, // S_DEMONFIRE
 
-	{SPR_LETR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_LETTER
+	{SPR_LETR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LETTER
 
 	// Tutorial scenery
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF2}, // S_TUTORIALLEAF1
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF3}, // S_TUTORIALLEAF2
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF4}, // S_TUTORIALLEAF3
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF5}, // S_TUTORIALLEAF4
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF6}, // S_TUTORIALLEAF5
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF7}, // S_TUTORIALLEAF6
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF8}, // S_TUTORIALLEAF7
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF9}, // S_TUTORIALLEAF8
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF10}, // S_TUTORIALLEAF9
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF11}, // S_TUTORIALLEAF10
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF12}, // S_TUTORIALLEAF11
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF13}, // S_TUTORIALLEAF12
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF14}, // S_TUTORIALLEAF13
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF15}, // S_TUTORIALLEAF14
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF16}, // S_TUTORIALLEAF15
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF1}, // S_TUTORIALLEAF16
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER2}, // S_TUTORIALFLOWER1
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER3}, // S_TUTORIALFLOWER2
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER4}, // S_TUTORIALFLOWER3
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER5}, // S_TUTORIALFLOWER4
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER6}, // S_TUTORIALFLOWER5
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER7}, // S_TUTORIALFLOWER6
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER8}, // S_TUTORIALFLOWER7
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER9}, // S_TUTORIALFLOWER8
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER10}, // S_TUTORIALFLOWER9
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER11}, // S_TUTORIALFLOWER10
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER12}, // S_TUTORIALFLOWER11
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER13}, // S_TUTORIALFLOWER12
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER14}, // S_TUTORIALFLOWER13
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER15}, // S_TUTORIALFLOWER14
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER16}, // S_TUTORIALFLOWER15
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER1}, // S_TUTORIALFLOWER16
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF2}, // S_TUTORIALFLOWERF1
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF3}, // S_TUTORIALFLOWERF2
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF4}, // S_TUTORIALFLOWERF3
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF5}, // S_TUTORIALFLOWERF4
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF6}, // S_TUTORIALFLOWERF5
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF7}, // S_TUTORIALFLOWERF6
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF8}, // S_TUTORIALFLOWERF7
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF9}, // S_TUTORIALFLOWERF8
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF10}, // S_TUTORIALFLOWERF9
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF11}, // S_TUTORIALFLOWERF10
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF12}, // S_TUTORIALFLOWERF11
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF13}, // S_TUTORIALFLOWERF12
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF14}, // S_TUTORIALFLOWERF13
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF15}, // S_TUTORIALFLOWERF14
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF16}, // S_TUTORIALFLOWERF15
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF1}, // S_TUTORIALFLOWERF16
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF2, 0}, // S_TUTORIALLEAF1
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF3, 0}, // S_TUTORIALLEAF2
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF4, 0}, // S_TUTORIALLEAF3
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF5, 0}, // S_TUTORIALLEAF4
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF6, 0}, // S_TUTORIALLEAF5
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF7, 0}, // S_TUTORIALLEAF6
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF8, 0}, // S_TUTORIALLEAF7
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF9, 0}, // S_TUTORIALLEAF8
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF10, 0}, // S_TUTORIALLEAF9
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF11, 0}, // S_TUTORIALLEAF10
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF12, 0}, // S_TUTORIALLEAF11
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF13, 0}, // S_TUTORIALLEAF12
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF14, 0}, // S_TUTORIALLEAF13
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF15, 0}, // S_TUTORIALLEAF14
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF16, 0}, // S_TUTORIALLEAF15
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF1, 0}, // S_TUTORIALLEAF16
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER2, 0}, // S_TUTORIALFLOWER1
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER3, 0}, // S_TUTORIALFLOWER2
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER4, 0}, // S_TUTORIALFLOWER3
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER5, 0}, // S_TUTORIALFLOWER4
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER6, 0}, // S_TUTORIALFLOWER5
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER7, 0}, // S_TUTORIALFLOWER6
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER8, 0}, // S_TUTORIALFLOWER7
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER9, 0}, // S_TUTORIALFLOWER8
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER10, 0}, // S_TUTORIALFLOWER9
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER11, 0}, // S_TUTORIALFLOWER10
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER12, 0}, // S_TUTORIALFLOWER11
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER13, 0}, // S_TUTORIALFLOWER12
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER14, 0}, // S_TUTORIALFLOWER13
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER15, 0}, // S_TUTORIALFLOWER14
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER16, 0}, // S_TUTORIALFLOWER15
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER1, 0}, // S_TUTORIALFLOWER16
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF2, 0}, // S_TUTORIALFLOWERF1
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF3, 0}, // S_TUTORIALFLOWERF2
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF4, 0}, // S_TUTORIALFLOWERF3
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF5, 0}, // S_TUTORIALFLOWERF4
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF6, 0}, // S_TUTORIALFLOWERF5
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF7, 0}, // S_TUTORIALFLOWERF6
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF8, 0}, // S_TUTORIALFLOWERF7
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF9, 0}, // S_TUTORIALFLOWERF8
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF10, 0}, // S_TUTORIALFLOWERF9
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF11, 0}, // S_TUTORIALFLOWERF10
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF12, 0}, // S_TUTORIALFLOWERF11
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF13, 0}, // S_TUTORIALFLOWERF12
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF14, 0}, // S_TUTORIALFLOWERF13
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF15, 0}, // S_TUTORIALFLOWERF14
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF16, 0}, // S_TUTORIALFLOWERF15
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF1, 0}, // S_TUTORIALFLOWERF16
 
 	// GFZ flowers
-	{SPR_FWR1, FF_ANIMATE, -1, {NULL},  7, 3, S_NULL}, // S_GFZFLOWERA
-	{SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL}, // S_GFZFLOWERB
-	{SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_GFZFLOWERC
+	{SPR_FWR1, FF_ANIMATE, -1, {NULL},  7, 3, S_NULL, 0}, // S_GFZFLOWERA
+	{SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL, 0}, // S_GFZFLOWERB
+	{SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_GFZFLOWERC
 
-	{SPR_BUS3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEBERRYBUSH
-	{SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH
-	{SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH
+	{SPR_BUS3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUEBERRYBUSH
+	{SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BERRYBUSH
+	{SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUSH
 
 	// Trees
-	{SPR_TRE1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GFZTREE
-	{SPR_TRE1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_GFZBERRYTREE
-	{SPR_TRE1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_GFZCHERRYTREE
-	{SPR_TRE2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CHECKERTREE
-	{SPR_TRE2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CHECKERSUNSETTREE
-	{SPR_TRE3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZTREE
-	{SPR_TRE3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZPINKTREE
-	{SPR_TRE4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POLYGONTREE
-	{SPR_TRE5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHTREE
-	{SPR_TRE5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHREDTREE
-	{SPR_TRE6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPRINGTREE
+	{SPR_TRE1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_GFZTREE
+	{SPR_TRE1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_GFZBERRYTREE
+	{SPR_TRE1, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_GFZCHERRYTREE
+	{SPR_TRE2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CHECKERTREE
+	{SPR_TRE2, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CHECKERSUNSETTREE
+	{SPR_TRE3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZTREE
+	{SPR_TRE3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZPINKTREE
+	{SPR_TRE4, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_POLYGONTREE
+	{SPR_TRE5, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUSHTREE
+	{SPR_TRE5, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUSHREDTREE
+	{SPR_TRE6, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SPRINGTREE
 
 	// THZ flowers
-	{SPR_THZP, FF_ANIMATE, -1, {NULL},  7, 4, S_NULL}, // S_THZFLOWERA
-	{SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB
-	{SPR_FWR6, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERC
+	{SPR_THZP, FF_ANIMATE, -1, {NULL},  7, 4, S_NULL, 0}, // S_THZFLOWERA
+	{SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL, 0}, // S_THZFLOWERB
+	{SPR_FWR6, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL, 0}, // S_THZFLOWERC
 
 	// THZ Steam Whistle tree/bush
-	{SPR_THZT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_THZTREE
-	{SPR_THZT,  1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2}, // S_THZTREEBRANCH1
-	{SPR_THZT,  2|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH3}, // S_THZTREEBRANCH2
-	{SPR_THZT,  3|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH4}, // S_THZTREEBRANCH3
-	{SPR_THZT,  4|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH5}, // S_THZTREEBRANCH4
-	{SPR_THZT,  5|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH6}, // S_THZTREEBRANCH5
-	{SPR_THZT,  6|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH7}, // S_THZTREEBRANCH6
-	{SPR_THZT,  7|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH8}, // S_THZTREEBRANCH7
-	{SPR_THZT,  8|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH9}, // S_THZTREEBRANCH8
-	{SPR_THZT,  9|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH10}, // S_THZTREEBRANCH9
-	{SPR_THZT, 10|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH11}, // S_THZTREEBRANCH10
-	{SPR_THZT, 11|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH12}, // S_THZTREEBRANCH11
-	{SPR_THZT, 12|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH13}, // S_THZTREEBRANCH12
-	{SPR_THZT, 13|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH1}, // S_THZTREEBRANCH13
+	{SPR_THZT, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_THZTREE
+	{SPR_THZT,  1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2, 0}, // S_THZTREEBRANCH1
+	{SPR_THZT,  2|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH3, 0}, // S_THZTREEBRANCH2
+	{SPR_THZT,  3|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH4, 0}, // S_THZTREEBRANCH3
+	{SPR_THZT,  4|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH5, 0}, // S_THZTREEBRANCH4
+	{SPR_THZT,  5|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH6, 0}, // S_THZTREEBRANCH5
+	{SPR_THZT,  6|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH7, 0}, // S_THZTREEBRANCH6
+	{SPR_THZT,  7|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH8, 0}, // S_THZTREEBRANCH7
+	{SPR_THZT,  8|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH9, 0}, // S_THZTREEBRANCH8
+	{SPR_THZT,  9|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH10, 0}, // S_THZTREEBRANCH9
+	{SPR_THZT, 10|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH11, 0}, // S_THZTREEBRANCH10
+	{SPR_THZT, 11|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH12, 0}, // S_THZTREEBRANCH11
+	{SPR_THZT, 12|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH13, 0}, // S_THZTREEBRANCH12
+	{SPR_THZT, 13|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH1, 0}, // S_THZTREEBRANCH13
 
 	// THZ Alarm
-	{SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1
+	{SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1, 0}, // S_ALARM1
 
 	// Deep Sea Gargoyle
-	{SPR_GARG, 0, -1, {NULL}, 0, 0, S_NULL},  // S_GARGOYLE
-	{SPR_GARG, 1, -1, {NULL}, 0, 0, S_NULL},  // S_BIGGARGOYLE
+	{SPR_GARG, 0, -1, {NULL}, 0, 0, S_NULL, 0},  // S_GARGOYLE
+	{SPR_GARG, 1, -1, {NULL}, 0, 0, S_NULL, 0},  // S_BIGGARGOYLE
 
 	// DSZ Seaweed
-	{SPR_SEWE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 26, 3, S_SEAWEED1}, // S_SEAWEED1
-	{SPR_SEWE, 1, 5, {NULL}, 0, 0, S_SEAWEED3}, // S_SEAWEED2
-	{SPR_SEWE, 2, 5, {NULL}, 0, 0, S_SEAWEED4}, // S_SEAWEED3
-	{SPR_SEWE, 3, 5, {NULL}, 0, 0, S_SEAWEED5}, // S_SEAWEED4
-	{SPR_SEWE, 4, 5, {NULL}, 0, 0, S_SEAWEED6}, // S_SEAWEED5
-	{SPR_SEWE, 5, 5, {NULL}, 0, 0, S_SEAWEED1}, // S_SEAWEED6
+	{SPR_SEWE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 26, 3, S_SEAWEED1, 0}, // S_SEAWEED1
+	{SPR_SEWE, 1, 5, {NULL}, 0, 0, S_SEAWEED3, 0}, // S_SEAWEED2
+	{SPR_SEWE, 2, 5, {NULL}, 0, 0, S_SEAWEED4, 0}, // S_SEAWEED3
+	{SPR_SEWE, 3, 5, {NULL}, 0, 0, S_SEAWEED5, 0}, // S_SEAWEED4
+	{SPR_SEWE, 4, 5, {NULL}, 0, 0, S_SEAWEED6, 0}, // S_SEAWEED5
+	{SPR_SEWE, 5, 5, {NULL}, 0, 0, S_SEAWEED1, 0}, // S_SEAWEED6
 
 	// Dripping water
-	{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
+	{SPR_NULL, FF_TRANS30  , 3*TICRATE, {NULL},                  0, 0, S_DRIPA2, 0}, // S_DRIPA1
+	{SPR_DRIP, FF_TRANS30  ,         2, {NULL},                  0, 0, S_DRIPA3, 0}, // S_DRIPA2
+	{SPR_DRIP, FF_TRANS30|1,         2, {NULL},                  0, 0, S_DRIPA4, 0}, // S_DRIPA3
+	{SPR_DRIP, FF_TRANS30|2,         2, {A_SpawnObjectRelative}, 0, MT_WATERDROP, S_DRIPA1, 0}, // S_DRIPA4
+	{SPR_DRIP, FF_TRANS30|3,        -1, {NULL},                  0, 0, S_DRIPB1, 0}, // S_DRIPB1
+	{SPR_DRIP, FF_TRANS30|4,         1, {NULL},                  0, 0, S_DRIPC2, 0}, // S_DRIPC1
+	{SPR_DRIP, FF_TRANS30|5,         1, {NULL},                  0, 0,   S_NULL, 0}, // S_DRIPC2
 
 	// Coral
-	{SPR_CORL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1
-	{SPR_CORL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL2
-	{SPR_CORL, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3
-	{SPR_CORL, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL4
-	{SPR_CORL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL5
+	{SPR_CORL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL1
+	{SPR_CORL, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL2
+	{SPR_CORL, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL3
+	{SPR_CORL, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL4
+	{SPR_CORL, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL5
 
 	// Blue Crystal
-	{SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1
+	{SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUECRYSTAL1
 
 	// Kelp
-	{SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KELP
+	{SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_KELP
 
 	// Animated algae
-	{SPR_ALGA, 0, 1, {A_ConnectToGround}, MT_ANIMALGAESEG, 0, S_ANIMALGAETOP2}, // S_ANIMALGAETOP1
-	{SPR_ALGA, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL},          // S_ANIMALGAETOP2
-	{SPR_ALGB, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL},          // S_ANIMALGAESEG
+	{SPR_ALGA, 0, 1, {A_ConnectToGround}, MT_ANIMALGAESEG, 0, S_ANIMALGAETOP2, 0}, // S_ANIMALGAETOP1
+	{SPR_ALGA, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL, 0},          // S_ANIMALGAETOP2
+	{SPR_ALGB, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL, 0},          // S_ANIMALGAESEG
 
 	// DSZ Stalagmites
-	{SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DSZSTALAGMITE
-	{SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE
+	{SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_DSZSTALAGMITE
+	{SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_DSZ2STALAGMITE
 
 	// DSZ Light beam
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM3},  // S_LIGHTBEAM2
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM4},  // S_LIGHTBEAM3
-	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5},  // S_LIGHTBEAM4
-	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6},  // S_LIGHTBEAM5
-	{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM7},  // S_LIGHTBEAM6
-	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8},  // S_LIGHTBEAM7
-	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9},  // S_LIGHTBEAM8
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11
-	{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM12
+	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2, 0}, // S_LIGHTBEAM1
+	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM3, 0},  // S_LIGHTBEAM2
+	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM4, 0},  // S_LIGHTBEAM3
+	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5, 0},  // S_LIGHTBEAM4
+	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6, 0},  // S_LIGHTBEAM5
+	{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM7, 0},  // S_LIGHTBEAM6
+	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8, 0},  // S_LIGHTBEAM7
+	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9, 0},  // S_LIGHTBEAM8
+	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM10, 0}, // S_LIGHTBEAM9
+	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM11, 0}, // S_LIGHTBEAM10
+	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM12, 0}, // S_LIGHTBEAM11
+	{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1, 0}, // S_LIGHTBEAM12
 
 	// CEZ Chain
-	{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN
+	{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZCHAIN
 
 	// Flame
-	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,       3*8, {A_FlameParticle}, 7, 3, S_FLAME}, // S_FLAME
-	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE|8, TICRATE,            {NULL}, 3, 3, S_NULL},  // S_FLAMEPARTICLE
-	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,        -1,            {NULL}, 7, 3, S_NULL},  // S_FLAMEREST
+	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,       3*8, {A_FlameParticle}, 7, 3, S_FLAME, 0}, // S_FLAME
+	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE|8, TICRATE,            {NULL}, 3, 3, S_NULL, 0},  // S_FLAMEPARTICLE
+	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,        -1,            {NULL}, 7, 3, S_NULL, 0},  // S_FLAMEREST
 
 	// Eggman statue
-	{SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE1
+	{SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGSTATUE1
 
 	// Hidden sling appears
-	{SPR_NULL, 0, -1, {NULL},          0, 0, S_SLING2}, // S_SLING1
-	{SPR_NULL, 0, -1, {A_SlingAppear}, 0, 0, S_NULL},   // S_SLING2
+	{SPR_NULL, 0, -1, {NULL},          0, 0, S_SLING2, 0}, // S_SLING1
+	{SPR_NULL, 0, -1, {A_SlingAppear}, 0, 0, S_NULL, 0},   // S_SLING2
 
 	// CEZ maces and chains
-	{SPR_SMCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLMACECHAIN
-	{SPR_BMCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGMACECHAIN
-	{SPR_SMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLMACE
-	{SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGMACE
-	{SPR_SMCH, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLGRABCHAIN
-	{SPR_BMCH, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGGRABCHAIN
+	{SPR_SMCH, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SMALLMACECHAIN
+	{SPR_BMCH, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGMACECHAIN
+	{SPR_SMCE, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SMALLMACE
+	{SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGMACE
+	{SPR_SMCH, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SMALLGRABCHAIN
+	{SPR_BMCH, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGGRABCHAIN
 
 	// Blue spring on a ball
-	{SPR_BSPB, 0, -1, {NULL},   0, 0, S_NULL},            // S_BLUESPRINGBALL
-	{SPR_BSPB, 4,  4, {A_Pain}, 0, 0, S_BLUESPRINGBALL3}, // S_BLUESPRINGBALL2
-	{SPR_BSPB, 3,  1, {NULL},   0, 0, S_BLUESPRINGBALL4}, // S_BLUESPRINGBALL3
-	{SPR_BSPB, 2,  1, {NULL},   0, 0, S_BLUESPRINGBALL5}, // S_BLUESPRINGBALL4
-	{SPR_BSPB, 1,  1, {NULL},   0, 0, S_BLUESPRINGBALL},  // S_BLUESPRINGBALL5
+	{SPR_BSPB, 0, -1, {NULL},   0, 0, S_NULL, 0},            // S_BLUESPRINGBALL
+	{SPR_BSPB, 4,  4, {A_Pain}, 0, 0, S_BLUESPRINGBALL3, 0}, // S_BLUESPRINGBALL2
+	{SPR_BSPB, 3,  1, {NULL},   0, 0, S_BLUESPRINGBALL4, 0}, // S_BLUESPRINGBALL3
+	{SPR_BSPB, 2,  1, {NULL},   0, 0, S_BLUESPRINGBALL5, 0}, // S_BLUESPRINGBALL4
+	{SPR_BSPB, 1,  1, {NULL},   0, 0, S_BLUESPRINGBALL, 0},  // S_BLUESPRINGBALL5
 
 	// Yellow spring on a ball
-	{SPR_YSPB, 0, -1, {NULL},   0, 0, S_NULL},              // S_YELLOWSPRINGBALL
-	{SPR_YSPB, 4,  4, {A_Pain}, 0, 0, S_YELLOWSPRINGBALL3}, // S_YELLOWSPRINGBALL2
-	{SPR_YSPB, 3,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL4}, // S_YELLOWSPRINGBALL3
-	{SPR_YSPB, 2,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL5}, // S_YELLOWSPRINGBALL4
-	{SPR_YSPB, 1,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL},  // S_YELLOWSPRINGBALL5
+	{SPR_YSPB, 0, -1, {NULL},   0, 0, S_NULL, 0},              // S_YELLOWSPRINGBALL
+	{SPR_YSPB, 4,  4, {A_Pain}, 0, 0, S_YELLOWSPRINGBALL3, 0}, // S_YELLOWSPRINGBALL2
+	{SPR_YSPB, 3,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL4, 0}, // S_YELLOWSPRINGBALL3
+	{SPR_YSPB, 2,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL5, 0}, // S_YELLOWSPRINGBALL4
+	{SPR_YSPB, 1,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL, 0},  // S_YELLOWSPRINGBALL5
 
 	// Red spring on a ball
-	{SPR_RSPB, 0, -1, {NULL},   0, 0, S_NULL},           // S_REDSPRINGBALL
-	{SPR_RSPB, 4,  4, {A_Pain}, 0, 0, S_REDSPRINGBALL3}, // S_REDSPRINGBALL2
-	{SPR_RSPB, 3,  1, {NULL},   0, 0, S_REDSPRINGBALL4}, // S_REDSPRINGBALL3
-	{SPR_RSPB, 2,  1, {NULL},   0, 0, S_REDSPRINGBALL5}, // S_REDSPRINGBALL4
-	{SPR_RSPB, 1,  1, {NULL},   0, 0, S_REDSPRINGBALL},  // S_REDSPRINGBALL5
+	{SPR_RSPB, 0, -1, {NULL},   0, 0, S_NULL, 0},           // S_REDSPRINGBALL
+	{SPR_RSPB, 4,  4, {A_Pain}, 0, 0, S_REDSPRINGBALL3, 0}, // S_REDSPRINGBALL2
+	{SPR_RSPB, 3,  1, {NULL},   0, 0, S_REDSPRINGBALL4, 0}, // S_REDSPRINGBALL3
+	{SPR_RSPB, 2,  1, {NULL},   0, 0, S_REDSPRINGBALL5, 0}, // S_REDSPRINGBALL4
+	{SPR_RSPB, 1,  1, {NULL},   0, 0, S_REDSPRINGBALL, 0},  // S_REDSPRINGBALL5
 
 	// Small Firebar
-	{SPR_SFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_SMALLFIREBAR2},  // S_SMALLFIREBAR1
-	{SPR_SFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_SMALLFIREBAR3},  // S_SMALLFIREBAR2
-	{SPR_SFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR4},  // S_SMALLFIREBAR3
-	{SPR_SFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_SMALLFIREBAR5},  // S_SMALLFIREBAR4
-	{SPR_SFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_SMALLFIREBAR6},  // S_SMALLFIREBAR5
-	{SPR_SFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_SMALLFIREBAR7},  // S_SMALLFIREBAR6
-	{SPR_SFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR8},  // S_SMALLFIREBAR7
-	{SPR_SFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_SMALLFIREBAR9},  // S_SMALLFIREBAR8
-	{SPR_SFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_SMALLFIREBAR10}, // S_SMALLFIREBAR9
-	{SPR_SFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_SMALLFIREBAR11}, // S_SMALLFIREBAR10
-	{SPR_SFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR12}, // S_SMALLFIREBAR11
-	{SPR_SFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_SMALLFIREBAR13}, // S_SMALLFIREBAR12
-	{SPR_SFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_SMALLFIREBAR14}, // S_SMALLFIREBAR13
-	{SPR_SFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_SMALLFIREBAR15}, // S_SMALLFIREBAR14
-	{SPR_SFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR16}, // S_SMALLFIREBAR15
-	{SPR_SFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_SMALLFIREBAR1},  // S_SMALLFIREBAR16
+	{SPR_SFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_SMALLFIREBAR2, 0},  // S_SMALLFIREBAR1
+	{SPR_SFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_SMALLFIREBAR3, 0},  // S_SMALLFIREBAR2
+	{SPR_SFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR4, 0},  // S_SMALLFIREBAR3
+	{SPR_SFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_SMALLFIREBAR5, 0},  // S_SMALLFIREBAR4
+	{SPR_SFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_SMALLFIREBAR6, 0},  // S_SMALLFIREBAR5
+	{SPR_SFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_SMALLFIREBAR7, 0},  // S_SMALLFIREBAR6
+	{SPR_SFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR8, 0},  // S_SMALLFIREBAR7
+	{SPR_SFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_SMALLFIREBAR9, 0},  // S_SMALLFIREBAR8
+	{SPR_SFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_SMALLFIREBAR10, 0}, // S_SMALLFIREBAR9
+	{SPR_SFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_SMALLFIREBAR11, 0}, // S_SMALLFIREBAR10
+	{SPR_SFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR12, 0}, // S_SMALLFIREBAR11
+	{SPR_SFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_SMALLFIREBAR13, 0}, // S_SMALLFIREBAR12
+	{SPR_SFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_SMALLFIREBAR14, 0}, // S_SMALLFIREBAR13
+	{SPR_SFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_SMALLFIREBAR15, 0}, // S_SMALLFIREBAR14
+	{SPR_SFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR16, 0}, // S_SMALLFIREBAR15
+	{SPR_SFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_SMALLFIREBAR1, 0},  // S_SMALLFIREBAR16
 
 	// Big Firebar
-	{SPR_BFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_BIGFIREBAR2},  // S_BIGFIREBAR1
-	{SPR_BFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_BIGFIREBAR3},  // S_BIGFIREBAR2
-	{SPR_BFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR4},  // S_BIGFIREBAR3
-	{SPR_BFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_BIGFIREBAR5},  // S_BIGFIREBAR4
-	{SPR_BFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_BIGFIREBAR6},  // S_BIGFIREBAR5
-	{SPR_BFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_BIGFIREBAR7},  // S_BIGFIREBAR6
-	{SPR_BFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR8},  // S_BIGFIREBAR7
-	{SPR_BFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_BIGFIREBAR9},  // S_BIGFIREBAR8
-	{SPR_BFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_BIGFIREBAR10}, // S_BIGFIREBAR9
-	{SPR_BFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_BIGFIREBAR11}, // S_BIGFIREBAR10
-	{SPR_BFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR12}, // S_BIGFIREBAR11
-	{SPR_BFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_BIGFIREBAR13}, // S_BIGFIREBAR12
-	{SPR_BFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_BIGFIREBAR14}, // S_BIGFIREBAR13
-	{SPR_BFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_BIGFIREBAR15}, // S_BIGFIREBAR14
-	{SPR_BFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR16}, // S_BIGFIREBAR15
-	{SPR_BFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_BIGFIREBAR1},  // S_BIGFIREBAR16
+	{SPR_BFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_BIGFIREBAR2, 0},  // S_BIGFIREBAR1
+	{SPR_BFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_BIGFIREBAR3, 0},  // S_BIGFIREBAR2
+	{SPR_BFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR4, 0},  // S_BIGFIREBAR3
+	{SPR_BFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_BIGFIREBAR5, 0},  // S_BIGFIREBAR4
+	{SPR_BFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_BIGFIREBAR6, 0},  // S_BIGFIREBAR5
+	{SPR_BFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_BIGFIREBAR7, 0},  // S_BIGFIREBAR6
+	{SPR_BFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR8, 0},  // S_BIGFIREBAR7
+	{SPR_BFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_BIGFIREBAR9, 0},  // S_BIGFIREBAR8
+	{SPR_BFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_BIGFIREBAR10, 0}, // S_BIGFIREBAR9
+	{SPR_BFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_BIGFIREBAR11, 0}, // S_BIGFIREBAR10
+	{SPR_BFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR12, 0}, // S_BIGFIREBAR11
+	{SPR_BFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_BIGFIREBAR13, 0}, // S_BIGFIREBAR12
+	{SPR_BFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_BIGFIREBAR14, 0}, // S_BIGFIREBAR13
+	{SPR_BFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_BIGFIREBAR15, 0}, // S_BIGFIREBAR14
+	{SPR_BFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR16, 0}, // S_BIGFIREBAR15
+	{SPR_BFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_BIGFIREBAR1, 0},  // S_BIGFIREBAR16
 
-	{SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER
-	{SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE
+	{SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZFLOWER
+	{SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZPOLE
 
-	{SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER1
-	{SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER2
+	{SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBANNER1
+	{SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBANNER2
 
-	{SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE
-	{SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1
-	{SPR_CEZB, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH2
+	{SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_PINETREE
+	{SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBUSH1
+	{SPR_CEZB, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBUSH2
 
-	{SPR_CNDL, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL}, // S_CANDLE
-	{SPR_CNDL, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CANDLEPRICKET
+	{SPR_CNDL, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANDLE
+	{SPR_CNDL, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANDLEPRICKET
 
-	{SPR_FLMH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FLAMEHOLDER
+	{SPR_FLMH, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FLAMEHOLDER
 
-	{SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH
+	{SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH, 0}, // S_FIRETORCH
 
-	{SPR_CFLG,                0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG
-	{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG1
-	{SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG2
+	{SPR_CFLG,                0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WAVINGFLAG
+	{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WAVINGFLAGSEG1
+	{SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WAVINGFLAGSEG2
 
-	{SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE
+	{SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CRAWLASTATUE
 
-	{SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSTATUE
+	{SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FACESTABBERSTATUE
 
-	{SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT},   // S_SUSPICIOUSFACESTABBERSTATUE_WAIT
-	{SPR_CBBS, FF_ANIMATE, 23, {NULL},    6, 1, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1
-	{SPR_NULL, 0, 40, {A_StatueBurst}, MT_FACESTABBER, S_FACESTABBER_CHARGE2, S_NULL}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2
+	{SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT, 0},   // S_SUSPICIOUSFACESTABBERSTATUE_WAIT
+	{SPR_CBBS, FF_ANIMATE, 23, {NULL},    6, 1, S_SUSPICIOUSFACESTABBERSTATUE_BURST2, 0}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1
+	{SPR_NULL, 0, 40, {A_StatueBurst}, MT_FACESTABBER, S_FACESTABBER_CHARGE2, S_NULL, 0}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2
 
-	{SPR_CABR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BRAMBLES
+	{SPR_CABR, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BRAMBLES
 
 	// Big Tumbleweed
-	{SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL},                // S_BIGTUMBLEWEED
-	{SPR_BTBL, 0,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL2}, // S_BIGTUMBLEWEED_ROLL1
-	{SPR_BTBL, 1,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL3}, // S_BIGTUMBLEWEED_ROLL2
-	{SPR_BTBL, 2,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL4}, // S_BIGTUMBLEWEED_ROLL3
-	{SPR_BTBL, 3,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL5}, // S_BIGTUMBLEWEED_ROLL4
-	{SPR_BTBL, 4,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL6}, // S_BIGTUMBLEWEED_ROLL5
-	{SPR_BTBL, 5,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL7}, // S_BIGTUMBLEWEED_ROLL6
-	{SPR_BTBL, 6,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL8}, // S_BIGTUMBLEWEED_ROLL7
-	{SPR_BTBL, 7,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL1}, // S_BIGTUMBLEWEED_ROLL8
+	{SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL, 0},                // S_BIGTUMBLEWEED
+	{SPR_BTBL, 0,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL2, 0}, // S_BIGTUMBLEWEED_ROLL1
+	{SPR_BTBL, 1,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL3, 0}, // S_BIGTUMBLEWEED_ROLL2
+	{SPR_BTBL, 2,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL4, 0}, // S_BIGTUMBLEWEED_ROLL3
+	{SPR_BTBL, 3,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL5, 0}, // S_BIGTUMBLEWEED_ROLL4
+	{SPR_BTBL, 4,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL6, 0}, // S_BIGTUMBLEWEED_ROLL5
+	{SPR_BTBL, 5,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL7, 0}, // S_BIGTUMBLEWEED_ROLL6
+	{SPR_BTBL, 6,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL8, 0}, // S_BIGTUMBLEWEED_ROLL7
+	{SPR_BTBL, 7,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL1, 0}, // S_BIGTUMBLEWEED_ROLL8
 
 	// Little Tumbleweed
-	{SPR_STBL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LITTLETUMBLEWEED
-	{SPR_STBL, 0, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL2}, // S_LITTLETUMBLEWEED_ROLL1
-	{SPR_STBL, 1, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL3}, // S_LITTLETUMBLEWEED_ROLL2
-	{SPR_STBL, 2, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL4}, // S_LITTLETUMBLEWEED_ROLL3
-	{SPR_STBL, 3, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL5}, // S_LITTLETUMBLEWEED_ROLL4
-	{SPR_STBL, 4, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL6}, // S_LITTLETUMBLEWEED_ROLL5
-	{SPR_STBL, 5, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL7}, // S_LITTLETUMBLEWEED_ROLL6
-	{SPR_STBL, 6, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL8}, // S_LITTLETUMBLEWEED_ROLL7
-	{SPR_STBL, 7, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL1}, // S_LITTLETUMBLEWEED_ROLL8
+	{SPR_STBL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LITTLETUMBLEWEED
+	{SPR_STBL, 0, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL2, 0}, // S_LITTLETUMBLEWEED_ROLL1
+	{SPR_STBL, 1, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL3, 0}, // S_LITTLETUMBLEWEED_ROLL2
+	{SPR_STBL, 2, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL4, 0}, // S_LITTLETUMBLEWEED_ROLL3
+	{SPR_STBL, 3, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL5, 0}, // S_LITTLETUMBLEWEED_ROLL4
+	{SPR_STBL, 4, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL6, 0}, // S_LITTLETUMBLEWEED_ROLL5
+	{SPR_STBL, 5, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL7, 0}, // S_LITTLETUMBLEWEED_ROLL6
+	{SPR_STBL, 6, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL8, 0}, // S_LITTLETUMBLEWEED_ROLL7
+	{SPR_STBL, 7, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL1, 0}, // S_LITTLETUMBLEWEED_ROLL8
 
 	// Cacti
-	{SPR_CACT, 0, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI1
-	{SPR_CACT, 1, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI2
-	{SPR_CACT, 2, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI3
-	{SPR_CACT, 3, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI4
-	{SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI5
-	{SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI6
-	{SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI7
-	{SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI8
-	{SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI9
-	{SPR_CACT, 9, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI10
-	{SPR_CACT, 10, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI11
-	{SPR_CACT, 11, -1, {NULL}, 0, 0, S_NULL}, // S_CACTITINYSEG
-	{SPR_CACT, 12, -1, {NULL}, 0, 0, S_NULL}, // S_CACTISMALLSEG
+	{SPR_CACT, 0, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL, 0}, // S_CACTI1
+	{SPR_CACT, 1, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL, 0}, // S_CACTI2
+	{SPR_CACT, 2, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL, 0}, // S_CACTI3
+	{SPR_CACT, 3, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL, 0}, // S_CACTI4
+	{SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI5
+	{SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI6
+	{SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI7
+	{SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI8
+	{SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI9
+	{SPR_CACT, 9, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL, 0}, // S_CACTI10
+	{SPR_CACT, 10, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL, 0}, // S_CACTI11
+	{SPR_CACT, 11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTITINYSEG
+	{SPR_CACT, 12, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTISMALLSEG
 
 	// Warning Signs
-	{SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CAUTION
-	{SPR_WWS2, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CACTI
-	{SPR_WWS3, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_SHARPTURN
+	{SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARIDSIGN_CAUTION
+	{SPR_WWS2, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARIDSIGN_CACTI
+	{SPR_WWS3, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARIDSIGN_SHARPTURN
 
 	// Oil lamp
-	{SPR_OILL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_OILLAMP
-	{SPR_OILF, FF_TRANS90|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_OILLAMPFLARE
+	{SPR_OILL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_OILLAMP
+	{SPR_OILF, FF_TRANS90|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_OILLAMPFLARE
 
 	// TNT barrel
-	{SPR_BARR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_STND1
-	{SPR_BARX, 0, 0, {A_RollAngle}, 0, 1, S_TNTBARREL_EXPL2}, // S_TNTBARREL_EXPL1
-	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_TNTBARREL_EXPL3}, // S_TNTBARREL_EXPL2
-	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_TNTExplode}, MT_TNTDUST, 0, S_TNTBARREL_EXPL4}, // S_TNTBARREL_EXPL3
-	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_TNTBARREL_EXPL5}, // S_TNTBARREL_EXPL4
-	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL6}, // S_TNTBARREL_EXPL5
-	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL7}, // S_TNTBARREL_EXPL6
-	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_EXPL7
+	{SPR_BARR, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TNTBARREL_STND1
+	{SPR_BARX, 0, 0, {A_RollAngle}, 0, 1, S_TNTBARREL_EXPL2, 0}, // S_TNTBARREL_EXPL1
+	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_TNTBARREL_EXPL3, 0}, // S_TNTBARREL_EXPL2
+	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_TNTExplode}, MT_TNTDUST, 0, S_TNTBARREL_EXPL4, 0}, // S_TNTBARREL_EXPL3
+	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_TNTBARREL_EXPL5, 0}, // S_TNTBARREL_EXPL4
+	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL6, 0}, // S_TNTBARREL_EXPL5
+	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL7, 0}, // S_TNTBARREL_EXPL6
+	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_TNTBARREL_EXPL7
 #ifndef ROTSPRITE
-	{SPR_BARR, 1|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_TNTBARREL_FLYING
+	{SPR_BARR, 1|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL, 0}, // S_TNTBARREL_FLYING
 #else
-	{SPR_BARR, 1, 1, {A_RollAngle}, 14, 0, S_TNTBARREL_FLYING}, // S_TNTBARREL_FLYING
+	{SPR_BARR, 1, 1, {A_RollAngle}, 14, 0, S_TNTBARREL_FLYING, 0}, // S_TNTBARREL_FLYING
 #endif
 
 	// TNT proximity shell
-	{SPR_REMT, 0, 10, {A_Look}, 33554433, 0, S_PROXIMITY_TNT}, // S_PROXIMITY_TNT
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER2}, // S_PROXIMITY_TNT_TRIGGER1
-	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER3}, // S_PROXIMITY_TNT_TRIGGER2
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER4}, // S_PROXIMITY_TNT_TRIGGER3
-	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER5}, // S_PROXIMITY_TNT_TRIGGER4
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER6}, // S_PROXIMITY_TNT_TRIGGER5
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER7}, // S_PROXIMITY_TNT_TRIGGER6
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER8}, // S_PROXIMITY_TNT_TRIGGER7
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER9}, // S_PROXIMITY_TNT_TRIGGER8
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER10}, // S_PROXIMITY_TNT_TRIGGER9
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER11}, // S_PROXIMITY_TNT_TRIGGER10
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER12}, // S_PROXIMITY_TNT_TRIGGER11
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER13}, // S_PROXIMITY_TNT_TRIGGER12
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER14}, // S_PROXIMITY_TNT_TRIGGER13
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER15}, // S_PROXIMITY_TNT_TRIGGER14
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER16}, // S_PROXIMITY_TNT_TRIGGER15
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER17}, // S_PROXIMITY_TNT_TRIGGER16
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER18}, // S_PROXIMITY_TNT_TRIGGER17
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER19}, // S_PROXIMITY_TNT_TRIGGER18
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER20}, // S_PROXIMITY_TNT_TRIGGER19
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER21}, // S_PROXIMITY_TNT_TRIGGER20
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER22}, // S_PROXIMITY_TNT_TRIGGER21
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER23}, // S_PROXIMITY_TNT_TRIGGER22
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_TNTBARREL_EXPL1}, // S_PROXIMITY_TNT_TRIGGER23
+	{SPR_REMT, 0, 10, {A_Look}, 33554433, 0, S_PROXIMITY_TNT, 0}, // S_PROXIMITY_TNT
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER2, 0}, // S_PROXIMITY_TNT_TRIGGER1
+	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER3, 0}, // S_PROXIMITY_TNT_TRIGGER2
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER4, 0}, // S_PROXIMITY_TNT_TRIGGER3
+	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER5, 0}, // S_PROXIMITY_TNT_TRIGGER4
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER6, 0}, // S_PROXIMITY_TNT_TRIGGER5
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER7, 0}, // S_PROXIMITY_TNT_TRIGGER6
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER8, 0}, // S_PROXIMITY_TNT_TRIGGER7
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER9, 0}, // S_PROXIMITY_TNT_TRIGGER8
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER10, 0}, // S_PROXIMITY_TNT_TRIGGER9
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER11, 0}, // S_PROXIMITY_TNT_TRIGGER10
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER12, 0}, // S_PROXIMITY_TNT_TRIGGER11
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER13, 0}, // S_PROXIMITY_TNT_TRIGGER12
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER14, 0}, // S_PROXIMITY_TNT_TRIGGER13
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER15, 0}, // S_PROXIMITY_TNT_TRIGGER14
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER16, 0}, // S_PROXIMITY_TNT_TRIGGER15
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER17, 0}, // S_PROXIMITY_TNT_TRIGGER16
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER18, 0}, // S_PROXIMITY_TNT_TRIGGER17
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER19, 0}, // S_PROXIMITY_TNT_TRIGGER18
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER20, 0}, // S_PROXIMITY_TNT_TRIGGER19
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER21, 0}, // S_PROXIMITY_TNT_TRIGGER20
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER22, 0}, // S_PROXIMITY_TNT_TRIGGER21
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER23, 0}, // S_PROXIMITY_TNT_TRIGGER22
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_TNTBARREL_EXPL1, 0}, // S_PROXIMITY_TNT_TRIGGER23
 
 	// Dust devil
-	{SPR_NULL, 0, 1, {A_DustDevilThink}, 0, 0, S_DUSTDEVIL}, //S_DUSTDEVIL
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 2 * TICRATE, {NULL}, 0, 0, S_DUSTLAYER2}, // S_DUSTLAYER1
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 5, {NULL}, 0, 0, S_DUSTLAYER3}, // S_DUSTLAYER2
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER4}, // S_DUSTLAYER3
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER5}, // S_DUSTLAYER4
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS90, 5, {NULL}, 0, 0, S_NULL}, // S_DUSTLAYER5
-	{SPR_ADST, 0|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST1
-	{SPR_ADST, 3|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST2
-	{SPR_ADST, 6|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST3
+	{SPR_NULL, 0, 1, {A_DustDevilThink}, 0, 0, S_DUSTDEVIL, 0}, //S_DUSTDEVIL
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 2 * TICRATE, {NULL}, 0, 0, S_DUSTLAYER2, 0}, // S_DUSTLAYER1
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 5, {NULL}, 0, 0, S_DUSTLAYER3, 0}, // S_DUSTLAYER2
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER4, 0}, // S_DUSTLAYER3
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER5, 0}, // S_DUSTLAYER4
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS90, 5, {NULL}, 0, 0, S_NULL, 0}, // S_DUSTLAYER5
+	{SPR_ADST, 0|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL, 0}, // S_ARIDDUST1
+	{SPR_ADST, 3|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL, 0}, // S_ARIDDUST2
+	{SPR_ADST, 6|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL, 0}, // S_ARIDDUST3
 
 	// Minecart
-	{SPR_NULL, 0,                            1, {NULL},                 0, 0, S_MINECART_IDLE},   // S_MINECART_IDLE
-	{SPR_NULL, 0,                            0, {A_KillSegments},       0, 0, S_TNTBARREL_EXPL4}, // S_MINECART_DTH1
-	{SPR_MCRT, 8|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL},            // S_MINECARTEND
-	{SPR_MCRT, 0|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL},            // S_MINECARTSEG_FRONT
-	{SPR_MCRT, 1|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL},            // S_MINECARTSEG_BACK
-	{SPR_MCRT, 2|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL},            // S_MINECARTSEG_LEFT
-	{SPR_MCRT, 5|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL},            // S_MINECARTSEG_RIGHT
-	{SPR_LCKN, 2|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL},            // S_MINECARTSIDEMARK1
-	{SPR_LCKN, 0|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL},            // S_MINECARTSIDEMARK2
-	{SPR_MCSP, FF_FULLBRIGHT,                1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK},   // S_MINECARTSPARK
+	{SPR_NULL, 0,                            1, {NULL},                 0, 0, S_MINECART_IDLE, 0},   // S_MINECART_IDLE
+	{SPR_NULL, 0,                            0, {A_KillSegments},       0, 0, S_TNTBARREL_EXPL4, 0}, // S_MINECART_DTH1
+	{SPR_MCRT, 8|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTEND
+	{SPR_MCRT, 0|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSEG_FRONT
+	{SPR_MCRT, 1|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSEG_BACK
+	{SPR_MCRT, 2|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL, 0},            // S_MINECARTSEG_LEFT
+	{SPR_MCRT, 5|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL, 0},            // S_MINECARTSEG_RIGHT
+	{SPR_LCKN, 2|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSIDEMARK1
+	{SPR_LCKN, 0|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSIDEMARK2
+	{SPR_MCSP, FF_FULLBRIGHT,                1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK, 0},   // S_MINECARTSPARK
 
 	// Saloon door
-	{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR
-	{SPR_NULL, 0, -1, {A_SaloonDoorSpawn}, MT_SALOONDOOR, 48, S_NULL}, // S_SALOONDOORCENTER
+	{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SALOONDOOR
+	{SPR_NULL, 0, -1, {A_SaloonDoorSpawn}, MT_SALOONDOOR, 48, S_NULL, 0}, // S_SALOONDOORCENTER
 
 	// Train cameo
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2}, // S_TRAINCAMEOSPAWNER_1
-	{SPR_NULL, 0, 14, {A_TrainCameo}, 20, 18, S_TRAINCAMEOSPAWNER_3}, // S_TRAINCAMEOSPAWNER_2
-	{SPR_NULL, 0, 1, {A_Repeat}, 1, 0, S_TRAINCAMEOSPAWNER_4}, // S_TRAINCAMEOSPAWNER_3
-	{SPR_NULL, 0, 18, {A_TrainCameo2}, 20, 44, S_TRAINCAMEOSPAWNER_5}, // S_TRAINCAMEOSPAWNER_4
-	{SPR_NULL, 0, 1, {A_Repeat}, 5, S_TRAINCAMEOSPAWNER_4, S_NULL}, // S_TRAINCAMEOSPAWNER_5
-	{SPR_NULL, 0, 2, {A_SmokeTrailer}, MT_SMOKE, 0, S_TRAINPUFFMAKER}, // S_TRAINPUFFMAKER
+	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2, 0}, // S_TRAINCAMEOSPAWNER_1
+	{SPR_NULL, 0, 14, {A_TrainCameo}, 20, 18, S_TRAINCAMEOSPAWNER_3, 0}, // S_TRAINCAMEOSPAWNER_2
+	{SPR_NULL, 0, 1, {A_Repeat}, 1, 0, S_TRAINCAMEOSPAWNER_4, 0}, // S_TRAINCAMEOSPAWNER_3
+	{SPR_NULL, 0, 18, {A_TrainCameo2}, 20, 44, S_TRAINCAMEOSPAWNER_5, 0}, // S_TRAINCAMEOSPAWNER_4
+	{SPR_NULL, 0, 1, {A_Repeat}, 5, S_TRAINCAMEOSPAWNER_4, S_NULL, 0}, // S_TRAINCAMEOSPAWNER_5
+	{SPR_NULL, 0, 2, {A_SmokeTrailer}, MT_SMOKE, 0, S_TRAINPUFFMAKER, 0}, // S_TRAINPUFFMAKER
 
-	{SPR_ADST, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_TRAINDUST
-	{SPR_STEA, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_TRAINSTEAM
+	{SPR_ADST, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TRAINDUST
+	{SPR_STEA, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TRAINSTEAM
 
 	// Flame jet
-	{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, FF_FULLBRIGHT  ,  4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1
-	{SPR_FLME, FF_FULLBRIGHT|1,  5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2
-	{SPR_FLME, FF_FULLBRIGHT|2, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME3
-	{SPR_FLME, FF_FULLBRIGHT|3,  4, {NULL}, 0, 0, S_FLAMEJETFLAME5}, // S_FLAMEJETFLAME4
-	{SPR_FLME, FF_FULLBRIGHT|4,  5, {NULL}, 0, 0, S_FLAMEJETFLAME6}, // S_FLAMEJETFLAME5
-	{SPR_FLME, FF_FULLBRIGHT|5, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME6
-	{SPR_FLME, FF_FULLBRIGHT|6,  4, {NULL}, 0, 0, S_FLAMEJETFLAME8}, // S_FLAMEJETFLAME7
-	{SPR_FLME, FF_FULLBRIGHT|7,  5, {NULL}, 0, 0, S_FLAMEJETFLAME9}, // S_FLAMEJETFLAME8
-	{SPR_FLME, FF_FULLBRIGHT|8, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME9
+	{SPR_NULL, 0, 2*TICRATE, {NULL},             0, 0, S_FLAMEJETSTART, 0}, // S_FLAMEJETSTND
+	{SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTOP, 0}, // S_FLAMEJETSTART
+	{SPR_NULL, 0,         1, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTND, 0}, // S_FLAMEJETSTOP
+	{SPR_FLME, FF_FULLBRIGHT  ,  4, {NULL}, 0, 0, S_FLAMEJETFLAME2, 0}, // S_FLAMEJETFLAME1
+	{SPR_FLME, FF_FULLBRIGHT|1,  5, {NULL}, 0, 0, S_FLAMEJETFLAME3, 0}, // S_FLAMEJETFLAME2
+	{SPR_FLME, FF_FULLBRIGHT|2, 11, {NULL}, 0, 0,           S_NULL, 0}, // S_FLAMEJETFLAME3
+	{SPR_FLME, FF_FULLBRIGHT|3,  4, {NULL}, 0, 0, S_FLAMEJETFLAME5, 0}, // S_FLAMEJETFLAME4
+	{SPR_FLME, FF_FULLBRIGHT|4,  5, {NULL}, 0, 0, S_FLAMEJETFLAME6, 0}, // S_FLAMEJETFLAME5
+	{SPR_FLME, FF_FULLBRIGHT|5, 11, {NULL}, 0, 0,           S_NULL, 0}, // S_FLAMEJETFLAME6
+	{SPR_FLME, FF_FULLBRIGHT|6,  4, {NULL}, 0, 0, S_FLAMEJETFLAME8, 0}, // S_FLAMEJETFLAME7
+	{SPR_FLME, FF_FULLBRIGHT|7,  5, {NULL}, 0, 0, S_FLAMEJETFLAME9, 0}, // S_FLAMEJETFLAME8
+	{SPR_FLME, FF_FULLBRIGHT|8, 11, {NULL}, 0, 0,           S_NULL, 0}, // S_FLAMEJETFLAME9
 
 	// Spinning flame jets
 	// A: Counter-clockwise
-	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISA2}, // S_FJSPINAXISA1
-	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                 6,         6, S_FJSPINAXISA1}, // S_FJSPINAXISA2
+	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISA2, 0}, // S_FJSPINAXISA1
+	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                 6,         6, S_FJSPINAXISA1, 0}, // S_FJSPINAXISA2
 
 	// B: Clockwise
-	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISB2}, // S_FJSPINAXISB1
-	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                -6,        -6, S_FJSPINAXISB1}, // S_FJSPINAXISB2
+	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISB2, 0}, // S_FJSPINAXISB1
+	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                -6,        -6, S_FJSPINAXISB1, 0}, // S_FJSPINAXISB2
 
 	// Blade's flame
-	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2}, // S_FLAMEJETFLAMEB1
-	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2
-	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL},  // S_FLAMEJETFLAMEB3
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2, 0}, // S_FLAMEJETFLAMEB1
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3, 0}, // S_FLAMEJETFLAMEB2
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL, 0},  // S_FLAMEJETFLAMEB3
 
 	// Lavafall
-	{SPR_LFAL, 5, 1, {NULL}, 0, 0, S_LAVAFALL_DORMANT}, // S_LAVAFALL_DORMANT
-	{SPR_LFAL, 6|FF_ANIMATE, 4, {A_LavafallRocks}, 1, 2, S_LAVAFALL_TELL}, // S_LAVAFALL_TELL
-	{SPR_LFAL, 9|FF_FULLBRIGHT|FF_ANIMATE, 2, {A_LavafallLava}, 1, 1, S_LAVAFALL_SHOOT}, // S_LAVAFALL_SHOOT
-	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA2}, // S_LAVAFALL_LAVA1
-	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA1}, // S_LAVAFALL_LAVA2
-	{SPR_LFAL, 2|FF_FULLBRIGHT|FF_ANIMATE, 9, {NULL}, 2, 3, S_NULL}, // S_LAVAFALL_LAVA3
-	{SPR_LFAL, 11|FF_ANIMATE|FF_RANDOMANIM, 12, {NULL}, 3, 3, S_LAVAFALLROCK}, // S_LAVAFALLROCK
+	{SPR_LFAL, 5, 1, {NULL}, 0, 0, S_LAVAFALL_DORMANT, 0}, // S_LAVAFALL_DORMANT
+	{SPR_LFAL, 6|FF_ANIMATE, 4, {A_LavafallRocks}, 1, 2, S_LAVAFALL_TELL, 0}, // S_LAVAFALL_TELL
+	{SPR_LFAL, 9|FF_FULLBRIGHT|FF_ANIMATE, 2, {A_LavafallLava}, 1, 1, S_LAVAFALL_SHOOT, 0}, // S_LAVAFALL_SHOOT
+	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA2, 0}, // S_LAVAFALL_LAVA1
+	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA1, 0}, // S_LAVAFALL_LAVA2
+	{SPR_LFAL, 2|FF_FULLBRIGHT|FF_ANIMATE, 9, {NULL}, 2, 3, S_NULL, 0}, // S_LAVAFALL_LAVA3
+	{SPR_LFAL, 11|FF_ANIMATE|FF_RANDOMANIM, 12, {NULL}, 3, 3, S_LAVAFALLROCK, 0}, // S_LAVAFALLROCK
 
 	// Rollout Rock
-	{SPR_NULL, 0, 1, {A_RolloutSpawn}, 256*FRACUNIT, MT_ROLLOUTROCK, S_ROLLOUTSPAWN}, // S_ROLLOUTSPAWN
-	{SPR_PUMI, 0, 1, {A_RolloutRock},    63*FRACUNIT/64,  7*FRACUNIT/10,  S_ROLLOUTROCK}, // S_ROLLOUTROCK
+	{SPR_NULL, 0, 1, {A_RolloutSpawn}, 256*FRACUNIT, MT_ROLLOUTROCK, S_ROLLOUTSPAWN, 0}, // S_ROLLOUTSPAWN
+	{SPR_PUMI, 0, 1, {A_RolloutRock},    63*FRACUNIT/64,  7*FRACUNIT/10,  S_ROLLOUTROCK, 0}, // S_ROLLOUTROCK
 
 	// RVZ scenery
-	{SPR_JPLA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERNLEAF
-	{SPR_JPLA, 1, 1, {NULL}, 0, 0, S_BIGFERN2}, // S_BIGFERN1
-	{SPR_JPLA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERN2
-	{SPR_JPLA, 2, -1, {NULL}, 0, 0, S_NULL}, // S_JUNGLEPALM
-	{SPR_TFLO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_TORCHFLOWER}, // S_TORCHFLOWER
-	{SPR_WVIN, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_LONG
-	{SPR_WVIN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_SHORT
+	{SPR_JPLA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGFERNLEAF
+	{SPR_JPLA, 1, 1, {NULL}, 0, 0, S_BIGFERN2, 0}, // S_BIGFERN1
+	{SPR_JPLA, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGFERN2
+	{SPR_JPLA, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JUNGLEPALM
+	{SPR_TFLO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_TORCHFLOWER, 0}, // S_TORCHFLOWER
+	{SPR_WVIN, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLVINE_LONG
+	{SPR_WVIN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLVINE_SHORT
 
 	// Glaregoyles
-	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLE_CHARGE},  // S_GLAREGOYLE
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLE_BLINK},  // S_GLAREGOYLE_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLE_HOLD}, // S_GLAREGOYLE_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLE_FIRE},  // S_GLAREGOYLE_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLE_LOOP},  // S_GLAREGOYLE_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLE_FIRE, S_GLAREGOYLE_COOLDOWN}, // S_GLAREGOYLE_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLE}, // S_GLAREGOYLE_COOLDOWN
-
-	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEUP_CHARGE},  // S_GLAREGOYLEUP
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEUP_BLINK},  // S_GLAREGOYLEUP_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEUP_HOLD}, // S_GLAREGOYLEUP_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEUP_FIRE},  // S_GLAREGOYLEUP_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_GLAREGOYLEUP_LOOP},  // S_GLAREGOYLEUP_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEUP_FIRE, S_GLAREGOYLEUP_COOLDOWN}, // S_GLAREGOYLEUP_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEUP}, // S_GLAREGOYLEUP_COOLDOWN
-
-	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEDOWN_CHARGE},  // S_GLAREGOYLEDOWN
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEDOWN_BLINK},  // S_GLAREGOYLEDOWN_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEDOWN_HOLD}, // S_GLAREGOYLEDOWN_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEDOWN_FIRE},  // S_GLAREGOYLEDOWN_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_GLAREGOYLEDOWN_LOOP},  // S_GLAREGOYLEDOWN_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEDOWN_FIRE, S_GLAREGOYLEDOWN_COOLDOWN}, // S_GLAREGOYLEDOWN_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEDOWN}, // S_GLAREGOYLEDOWN_COOLDOWN
-
-	{SPR_BGAR,            0, 90, {NULL},       0, 0, S_GLAREGOYLELONG_CHARGE},  // S_GLAREGOYLELONG
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLELONG_BLINK},  // S_GLAREGOYLELONG_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLELONG_HOLD}, // S_GLAREGOYLELONG_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLELONG_FIRE},  // S_GLAREGOYLELONG_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLELONG_LOOP},  // S_GLAREGOYLELONG_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   5, S_GLAREGOYLELONG_FIRE, S_GLAREGOYLELONG_COOLDOWN}, // S_GLAREGOYLELONG_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLELONG}, // S_GLAREGOYLELONG_COOLDOWN
+	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLE_CHARGE, 0},  // S_GLAREGOYLE
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLE_BLINK, 0},  // S_GLAREGOYLE_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLE_HOLD, 0}, // S_GLAREGOYLE_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLE_FIRE, 0},  // S_GLAREGOYLE_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLE_LOOP, 0},  // S_GLAREGOYLE_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLE_FIRE, S_GLAREGOYLE_COOLDOWN, 0}, // S_GLAREGOYLE_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLE, 0}, // S_GLAREGOYLE_COOLDOWN
+
+	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEUP_CHARGE, 0},  // S_GLAREGOYLEUP
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEUP_BLINK, 0},  // S_GLAREGOYLEUP_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEUP_HOLD, 0}, // S_GLAREGOYLEUP_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEUP_FIRE, 0},  // S_GLAREGOYLEUP_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_GLAREGOYLEUP_LOOP, 0},  // S_GLAREGOYLEUP_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEUP_FIRE, S_GLAREGOYLEUP_COOLDOWN, 0}, // S_GLAREGOYLEUP_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEUP, 0}, // S_GLAREGOYLEUP_COOLDOWN
+
+	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEDOWN_CHARGE, 0},  // S_GLAREGOYLEDOWN
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEDOWN_BLINK, 0},  // S_GLAREGOYLEDOWN_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEDOWN_HOLD, 0}, // S_GLAREGOYLEDOWN_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEDOWN_FIRE, 0},  // S_GLAREGOYLEDOWN_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_GLAREGOYLEDOWN_LOOP, 0},  // S_GLAREGOYLEDOWN_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEDOWN_FIRE, S_GLAREGOYLEDOWN_COOLDOWN, 0}, // S_GLAREGOYLEDOWN_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEDOWN, 0}, // S_GLAREGOYLEDOWN_COOLDOWN
+
+	{SPR_BGAR,            0, 90, {NULL},       0, 0, S_GLAREGOYLELONG_CHARGE, 0},  // S_GLAREGOYLELONG
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLELONG_BLINK, 0},  // S_GLAREGOYLELONG_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLELONG_HOLD, 0}, // S_GLAREGOYLELONG_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLELONG_FIRE, 0},  // S_GLAREGOYLELONG_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLELONG_LOOP, 0},  // S_GLAREGOYLELONG_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   5, S_GLAREGOYLELONG_FIRE, S_GLAREGOYLELONG_COOLDOWN, 0}, // S_GLAREGOYLELONG_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLELONG, 0}, // S_GLAREGOYLELONG_COOLDOWN
 
 	// 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,               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,               0, -1, {NULL},                  0, 0, S_TARGET_IDLE, 0},  // S_TARGET_IDLE
+	{SPR_RCRY, FF_FULLBRIGHT|1,  0, {A_PlaySound},           sfx_ding, 1, S_TARGET_HIT2, 0},  // S_TARGET_HIT1
+	{SPR_RCRY, FF_FULLBRIGHT|1, 45, {A_SetObjectFlags},      MF_PUSHABLE, 2, S_TARGET_RESPAWN, 0},  // S_TARGET_HIT2
+	{SPR_RCRY,               1,  0, {A_SpawnObjectRelative}, 0, MT_TARGET, S_NULL, 0},  // S_TARGET_RESPAWN
+	{SPR_RCRY, FF_FULLBRIGHT|1, -1, {A_SetObjectFlags},      MF_PUSHABLE, 1, S_TARGET_ALLDONE, 0},  // S_TARGET_ALLDONE
 
 	// Green flame
-	{SPR_CFLM, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 3, S_GREENFLAME}, // S_GREENFLAME
+	{SPR_CFLM, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 3, S_GREENFLAME, 0}, // S_GREENFLAME
 
 	// ATZ Blue Gargoyle
-	{SPR_BGAR, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEGARGOYLE
+	{SPR_BGAR, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUEGARGOYLE
 
 	// Stalagmites
-	{SPR_STLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_STG0
-	{SPR_STLG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_STG1
-	{SPR_STLG, 2, -1, {NULL}, 0, 0, S_NULL}, // S_STG2
-	{SPR_STLG, 3, -1, {NULL}, 0, 0, S_NULL}, // S_STG3
-	{SPR_STLG, 4, -1, {NULL}, 0, 0, S_NULL}, // S_STG4
-	{SPR_STLG, 5, -1, {NULL}, 0, 0, S_NULL}, // S_STG5
-	{SPR_STLG, 6, -1, {NULL}, 0, 0, S_NULL}, // S_STG6
-	{SPR_STLG, 7, -1, {NULL}, 0, 0, S_NULL}, // S_STG7
-	{SPR_STLG, 8, -1, {NULL}, 0, 0, S_NULL}, // S_STG8
-	{SPR_STLG, 9, -1, {NULL}, 0, 0, S_NULL}, // S_STG9
+	{SPR_STLG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG0
+	{SPR_STLG, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG1
+	{SPR_STLG, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG2
+	{SPR_STLG, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG3
+	{SPR_STLG, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG4
+	{SPR_STLG, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG5
+	{SPR_STLG, 6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG6
+	{SPR_STLG, 7, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG7
+	{SPR_STLG, 8, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG8
+	{SPR_STLG, 9, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG9
 
 	// Xmas-specific stuff
-	{SPR_XMS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_XMASPOLE
-	{SPR_XMS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANDYCANE
-	{SPR_XMS3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOWMAN
-	{SPR_XMS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOWMANHAT
-	{SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST1
-	{SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2
-	{SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR
-	{SPR_XMS6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MISTLETOE
+	{SPR_XMS1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASPOLE
+	{SPR_XMS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANDYCANE
+	{SPR_XMS3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOWMAN
+	{SPR_XMS3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOWMANHAT
+	{SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LAMPPOST1
+	{SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LAMPPOST2
+	{SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HANGSTAR
+	{SPR_XMS6, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MISTLETOE
 	// Xmas GFZ bushes
-	{SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBLUEBERRYBUSH
-	{SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBERRYBUSH
-	{SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBUSH
+	{SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASBLUEBERRYBUSH
+	{SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASBERRYBUSH
+	{SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASBUSH
 	// FHZ
-	{SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE1
-	{SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE2
-	{SPR_ROSY, 16, 8, {NULL}, 0, 0, S_ROSY_IDLE2}, // S_ROSY_IDLE1
-	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE3}, // S_ROSY_IDLE2
-	{SPR_ROSY, 18, 8, {NULL}, 0, 0, S_ROSY_IDLE4}, // S_ROSY_IDLE3
-	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE1}, // S_ROSY_IDLE4
-	{SPR_ROSY, 14, -1, {NULL}, 1, 0, S_NULL}, // S_ROSY_JUMP
-	{SPR_ROSY,  5, -1, {NULL}, 7, 0, S_NULL}, // S_ROSY_WALK
-	{SPR_ROSY, 19, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_HUG
-	{SPR_ROSY, 13, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_PAIN
-	{SPR_ROSY,  1|FF_ANIMATE, -1, {NULL}, 3, 16, S_NULL}, // S_ROSY_STND
-	{SPR_ROSY, 20|FF_ANIMATE, TICRATE, {NULL}, 3, 4, S_ROSY_WALK}, // S_ROSY_UNHAPPY
+	{SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZICE1
+	{SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZICE2
+	{SPR_ROSY, 16, 8, {NULL}, 0, 0, S_ROSY_IDLE2, 0}, // S_ROSY_IDLE1
+	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE3, 0}, // S_ROSY_IDLE2
+	{SPR_ROSY, 18, 8, {NULL}, 0, 0, S_ROSY_IDLE4, 0}, // S_ROSY_IDLE3
+	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE1, 0}, // S_ROSY_IDLE4
+	{SPR_ROSY, 14, -1, {NULL}, 1, 0, S_NULL, 0}, // S_ROSY_JUMP
+	{SPR_ROSY,  5, -1, {NULL}, 7, 0, S_NULL, 0}, // S_ROSY_WALK
+	{SPR_ROSY, 19, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_HUG
+	{SPR_ROSY, 13, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_PAIN
+	{SPR_ROSY,  1|FF_ANIMATE, -1, {NULL}, 3, 16, S_NULL, 0}, // S_ROSY_STND
+	{SPR_ROSY, 20|FF_ANIMATE, TICRATE, {NULL}, 3, 4, S_ROSY_WALK, 0}, // S_ROSY_UNHAPPY
 
 	// Halloween Scenery
 	// Pumpkins
-	{SPR_PUMK,  0, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO1
-	{SPR_PUMK,  3|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_2}, // S_JACKO1OVERLAY_1
-	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_3}, // S_JACKO1OVERLAY_2
-	{SPR_PUMK,  5|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_4}, // S_JACKO1OVERLAY_3
-	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_1}, // S_JACKO1OVERLAY_4
-	{SPR_PUMK,  1, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO2
-	{SPR_PUMK,  6|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_2}, // S_JACKO2OVERLAY_1
-	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_3}, // S_JACKO2OVERLAY_2
-	{SPR_PUMK,  8|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_4}, // S_JACKO2OVERLAY_3
-	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_1}, // S_JACKO2OVERLAY_4
-	{SPR_PUMK,  2, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO3
-	{SPR_PUMK,  9|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_2}, // S_JACKO3OVERLAY_1
-	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_3}, // S_JACKO3OVERLAY_2
-	{SPR_PUMK, 11|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_4}, // S_JACKO3OVERLAY_3
-	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_1}, // S_JACKO3OVERLAY_4
+	{SPR_PUMK,  0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JACKO1
+	{SPR_PUMK,  3|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_2, 0}, // S_JACKO1OVERLAY_1
+	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_3, 0}, // S_JACKO1OVERLAY_2
+	{SPR_PUMK,  5|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_4, 0}, // S_JACKO1OVERLAY_3
+	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_1, 0}, // S_JACKO1OVERLAY_4
+	{SPR_PUMK,  1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JACKO2
+	{SPR_PUMK,  6|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_2, 0}, // S_JACKO2OVERLAY_1
+	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_3, 0}, // S_JACKO2OVERLAY_2
+	{SPR_PUMK,  8|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_4, 0}, // S_JACKO2OVERLAY_3
+	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_1, 0}, // S_JACKO2OVERLAY_4
+	{SPR_PUMK,  2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JACKO3
+	{SPR_PUMK,  9|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_2, 0}, // S_JACKO3OVERLAY_1
+	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_3, 0}, // S_JACKO3OVERLAY_2
+	{SPR_PUMK, 11|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_4, 0}, // S_JACKO3OVERLAY_3
+	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_1, 0}, // S_JACKO3OVERLAY_4
 	// Dr Seuss Trees
-	{SPR_HHPL, 2, -1, {A_ConnectToGround}, MT_HHZTREE_PART, 0, S_NULL}, // S_HHZTREE_TOP,
-	{SPR_HHPL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTREE_TRUNK,
-	{SPR_HHPL, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTREE_LEAF,
+	{SPR_HHPL, 2, -1, {A_ConnectToGround}, MT_HHZTREE_PART, 0, S_NULL, 0}, // S_HHZTREE_TOP,
+	{SPR_HHPL, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTREE_TRUNK,
+	{SPR_HHPL, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTREE_LEAF,
 	// Mushroom
-	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_2},  // S_HHZSHROOM_1,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_3},  // S_HHZSHROOM_2,
-	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_4},  // S_HHZSHROOM_3,
-	{SPR_SHRM, 1,  1, {NULL}, 0, 0, S_HHZSHROOM_5},  // S_HHZSHROOM_4,
-	{SPR_SHRM, 0,  1, {NULL}, 0, 0, S_HHZSHROOM_6},  // S_HHZSHROOM_5,
-	{SPR_SHRM, 1,  4, {NULL}, 0, 0, S_HHZSHROOM_7},  // S_HHZSHROOM_6,
-	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_8},  // S_HHZSHROOM_7,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_9},  // S_HHZSHROOM_8,
-	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_10}, // S_HHZSHROOM_9,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_11}, // S_HHZSHROOM_10,
-	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_12}, // S_HHZSHROOM_11,
-	{SPR_SHRM, 6,  1, {NULL}, 0, 0, S_HHZSHROOM_13}, // S_HHZSHROOM_12,
-	{SPR_SHRM, 7,  1, {NULL}, 0, 0, S_HHZSHROOM_14}, // S_HHZSHROOM_13,
-	{SPR_SHRM, 6,  4, {NULL}, 0, 0, S_HHZSHROOM_15}, // S_HHZSHROOM_14,
-	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_16}, // S_HHZSHROOM_15,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_1},  // S_HHZSHROOM_16,
+	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_2, 0},  // S_HHZSHROOM_1,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_3, 0},  // S_HHZSHROOM_2,
+	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_4, 0},  // S_HHZSHROOM_3,
+	{SPR_SHRM, 1,  1, {NULL}, 0, 0, S_HHZSHROOM_5, 0},  // S_HHZSHROOM_4,
+	{SPR_SHRM, 0,  1, {NULL}, 0, 0, S_HHZSHROOM_6, 0},  // S_HHZSHROOM_5,
+	{SPR_SHRM, 1,  4, {NULL}, 0, 0, S_HHZSHROOM_7, 0},  // S_HHZSHROOM_6,
+	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_8, 0},  // S_HHZSHROOM_7,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_9, 0},  // S_HHZSHROOM_8,
+	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_10, 0}, // S_HHZSHROOM_9,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_11, 0}, // S_HHZSHROOM_10,
+	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_12, 0}, // S_HHZSHROOM_11,
+	{SPR_SHRM, 6,  1, {NULL}, 0, 0, S_HHZSHROOM_13, 0}, // S_HHZSHROOM_12,
+	{SPR_SHRM, 7,  1, {NULL}, 0, 0, S_HHZSHROOM_14, 0}, // S_HHZSHROOM_13,
+	{SPR_SHRM, 6,  4, {NULL}, 0, 0, S_HHZSHROOM_15, 0}, // S_HHZSHROOM_14,
+	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_16, 0}, // S_HHZSHROOM_15,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_1, 0},  // S_HHZSHROOM_16,
 	// Misc
-	{SPR_HHZM, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HHZGRASS,
-	{SPR_HHZM, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTENT1,
-	{SPR_HHZM, 2, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTENT2,
-	{SPR_HHZM, 4, -1, {NULL}, 0, 0, S_NULL}, // S_HHZSTALAGMITE_TALL,
-	{SPR_HHZM, 5, -1, {NULL}, 0, 0, S_NULL}, // S_HHZSTALAGMITE_SHORT,
+	{SPR_HHZM, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZGRASS,
+	{SPR_HHZM, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTENT1,
+	{SPR_HHZM, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTENT2,
+	{SPR_HHZM, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZSTALAGMITE_TALL,
+	{SPR_HHZM, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZSTALAGMITE_SHORT,
 
 	// Loads of Botanic Serenity bullshit
-	{SPR_BSZ1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_RED
-	{SPR_BSZ1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_PURPLE
-	{SPR_BSZ1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_BLUE
-	{SPR_BSZ1, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_CYAN
-	{SPR_BSZ1, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_YELLOW
-	{SPR_BSZ1, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_ORANGE
-	{SPR_BSZ2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_RED
-	{SPR_BSZ2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_PURPLE
-	{SPR_BSZ2, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_BLUE
-	{SPR_BSZ2, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_CYAN
-	{SPR_BSZ2, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_YELLOW
-	{SPR_BSZ2, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_ORANGE
-	{SPR_BSZ3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_RED
-	{SPR_BSZ3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_PURPLE
-	{SPR_BSZ3, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_BLUE
-	{SPR_BSZ3, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_CYAN
-	{SPR_BSZ3, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_YELLOW
-	{SPR_BSZ3, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_ORANGE
-	{SPR_BST1, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_RED
-	{SPR_BST2, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_PURPLE
-	{SPR_BST3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_BLUE
-	{SPR_BST4, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_CYAN
-	{SPR_BST5, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_YELLOW
-	{SPR_BST6, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_ORANGE
-	{SPR_BSZ5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_RED
-	{SPR_BSZ5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_PURPLE
-	{SPR_BSZ5, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_BLUE
-	{SPR_BSZ5, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_CYAN
-	{SPR_BSZ5, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_YELLOW
-	{SPR_BSZ5, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_ORANGE
-	{SPR_BSZ6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_RED
-	{SPR_BSZ6, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_PURPLE
-	{SPR_BSZ6, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_BLUE
-	{SPR_BSZ6, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_CYAN
-	{SPR_BSZ6, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_YELLOW
-	{SPR_BSZ6, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_ORANGE
-	{SPR_BSZ7, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_RED
-	{SPR_BSZ7, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_PURPLE
-	{SPR_BSZ7, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_BLUE
-	{SPR_BSZ7, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_CYAN
-	{SPR_BSZ7, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_YELLOW
-	{SPR_BSZ7, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_ORANGE
-	{SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHRUB
-	{SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLOVER
-	{SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BIG_PALMTREE_TRUNK
-	{SPR_BSZ8, 3, -1, {A_ConnectToGround}, MT_BIG_PALMTREE_TRUNK, 0, S_NULL}, // S_BIG_PALMTREE_TOP
-	{SPR_BSZ8, 4, -1, {NULL}, 0, 0, S_NULL}, // S_PALMTREE_TRUNK
-	{SPR_BSZ8, 5, -1, {A_ConnectToGround},     MT_PALMTREE_TRUNK, 0, S_NULL}, // S_PALMTREE_TOP
+	{SPR_BSZ1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_RED
+	{SPR_BSZ1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_PURPLE
+	{SPR_BSZ1, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_BLUE
+	{SPR_BSZ1, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_CYAN
+	{SPR_BSZ1, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_YELLOW
+	{SPR_BSZ1, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_ORANGE
+	{SPR_BSZ2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_RED
+	{SPR_BSZ2, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_PURPLE
+	{SPR_BSZ2, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_BLUE
+	{SPR_BSZ2, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_CYAN
+	{SPR_BSZ2, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_YELLOW
+	{SPR_BSZ2, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_ORANGE
+	{SPR_BSZ3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_RED
+	{SPR_BSZ3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_PURPLE
+	{SPR_BSZ3, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_BLUE
+	{SPR_BSZ3, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_CYAN
+	{SPR_BSZ3, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_YELLOW
+	{SPR_BSZ3, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_ORANGE
+	{SPR_BST1, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_RED
+	{SPR_BST2, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_PURPLE
+	{SPR_BST3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_BLUE
+	{SPR_BST4, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_CYAN
+	{SPR_BST5, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_YELLOW
+	{SPR_BST6, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_ORANGE
+	{SPR_BSZ5, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_RED
+	{SPR_BSZ5, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_PURPLE
+	{SPR_BSZ5, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_BLUE
+	{SPR_BSZ5, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_CYAN
+	{SPR_BSZ5, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_YELLOW
+	{SPR_BSZ5, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_ORANGE
+	{SPR_BSZ6, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_RED
+	{SPR_BSZ6, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_PURPLE
+	{SPR_BSZ6, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_BLUE
+	{SPR_BSZ6, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_CYAN
+	{SPR_BSZ6, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_YELLOW
+	{SPR_BSZ6, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_ORANGE
+	{SPR_BSZ7, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_RED
+	{SPR_BSZ7, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_PURPLE
+	{SPR_BSZ7, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_BLUE
+	{SPR_BSZ7, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_CYAN
+	{SPR_BSZ7, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_YELLOW
+	{SPR_BSZ7, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_ORANGE
+	{SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHRUB
+	{SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLOVER
+	{SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIG_PALMTREE_TRUNK
+	{SPR_BSZ8, 3, -1, {A_ConnectToGround}, MT_BIG_PALMTREE_TRUNK, 0, S_NULL, 0}, // S_BIG_PALMTREE_TOP
+	{SPR_BSZ8, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_PALMTREE_TRUNK
+	{SPR_BSZ8, 5, -1, {A_ConnectToGround},     MT_PALMTREE_TRUNK, 0, S_NULL, 0}, // S_PALMTREE_TOP
 
 	// 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,   5, {NULL}, 0, 0, S_DBALL2, 0}, // S_DBALL1
+	{SPR_DBAL, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_DBALL3, 0}, // S_DBALL2
+	{SPR_DBAL, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_DBALL4, 0}, // S_DBALL3
+	{SPR_DBAL, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_DBALL5, 0}, // S_DBALL4
+	{SPR_DBAL, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_DBALL6, 0}, // S_DBALL5
+	{SPR_DBAL, FF_FULLBRIGHT|5, 5, {NULL}, 0, 0, S_DBALL1, 0}, // S_DBALL6
 
-	{SPR_ESTA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE2
+	{SPR_ESTA, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGSTATUE2
 
 	// Shield Orb
-	{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   , 2, {NULL}, 0, 0, S_ARMF2 }, // S_ARMF1
-	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF3 }, // S_ARMF2
-	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF4 }, // S_ARMF3
-	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF5 }, // S_ARMF4
-	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF6 }, // S_ARMF5
-	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF7 }, // S_ARMF6
-	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF8 }, // S_ARMF7
-	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF9 }, // S_ARMF8
-	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF10}, // S_ARMF9
-	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF11}, // S_ARMF10
-	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF12}, // S_ARMF11
-	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF13}, // S_ARMF12
-	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF14}, // S_ARMF13
-	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF15}, // S_ARMF14
-	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF16}, // S_ARMF15
-	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF17}, // S_ARMF16
-	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF18}, // S_ARMF17
-	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF19}, // S_ARMF18
-	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF20}, // S_ARMF19
-	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF21}, // S_ARMF20
-	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF22}, // S_ARMF21
-	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF23}, // S_ARMF22
-	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF24}, // S_ARMF23
-	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF25}, // S_ARMF24
-	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF26}, // S_ARMF25
-	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF27}, // S_ARMF26
-	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF28}, // S_ARMF27
-	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF29}, // S_ARMF28
-	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF30}, // S_ARMF29
-	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF31}, // S_ARMF30
-	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF32}, // S_ARMF31
-	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF1 }, // S_ARMF32
-
-	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB2 }, // S_ARMB1
-	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB3 }, // S_ARMB2
-	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB4 }, // S_ARMB3
-	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB5 }, // S_ARMB4
-	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB6 }, // S_ARMB5
-	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB7 }, // S_ARMB6
-	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB8 }, // S_ARMB7
-	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB9 }, // S_ARMB8
-	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB10}, // S_ARMB9
-	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB11}, // S_ARMB10
-	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB12}, // S_ARMB11
-	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB13}, // S_ARMB12
-	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB14}, // S_ARMB13
-	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB15}, // S_ARMB14
-	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB16}, // S_ARMB15
-	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB17}, // S_ARMB16
-	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB18}, // S_ARMB17
-	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB19}, // S_ARMB18
-	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB20}, // S_ARMB19
-	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB21}, // S_ARMB20
-	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB22}, // S_ARMB21
-	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB23}, // S_ARMB22
-	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB24}, // S_ARMB23
-	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB25}, // S_ARMB24
-	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB26}, // S_ARMB25
-	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB27}, // S_ARMB26
-	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB28}, // S_ARMB27
-	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB29}, // S_ARMB28
-	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB30}, // S_ARMB29
-	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB31}, // S_ARMB30
-	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB32}, // S_ARMB31
-	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB1 }, // S_ARMB32
-
-	{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_MAGN, FF_FULLBRIGHT|FF_TRANS10|12, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN13
-
-	{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_FORC, FF_TRANS50|20, -1, {NULL}, 0, 0, S_NULL}, // S_FORC21
-
-	{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_NULL,             0, 1, {NULL}, 0, 0, S_ELEM14}, // S_ELEM13
-	{SPR_ELEM, FF_TRANS50|11, 1, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM14
-
-	{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_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10}, // S_ELEMF9
-	{SPR_NULL, 0,                1, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF10
-
-	{SPR_PITY, FF_TRANS30   , 2, {NULL}, 0, 0, S_PITY2},  // S_PITY1
-	{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3},  // S_PITY2
-	{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4},  // S_PITY3
-	{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5},  // S_PITY4
-	{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6},  // S_PITY5
-	{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7},  // S_PITY6
-	{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8},  // S_PITY7
-	{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9},  // S_PITY8
-	{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10}, // S_PITY9
-	{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11}, // S_PITY10
-	{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12}, // S_PITY11
-	{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1},  // S_PITY12
-
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40  , 2, {NULL}, 0, 0, S_FIRS2}, // S_FIRS1
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3}, // S_FIRS2
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|2, 2, {NULL}, 0, 0, S_FIRS4}, // S_FIRS3
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|3, 2, {NULL}, 0, 0, S_FIRS5}, // S_FIRS4
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|4, 2, {NULL}, 0, 0, S_FIRS6}, // S_FIRS5
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|5, 2, {NULL}, 0, 0, S_FIRS7}, // S_FIRS6
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|6, 2, {NULL}, 0, 0, S_FIRS8}, // S_FIRS7
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|7, 2, {NULL}, 0, 0, S_FIRS9}, // S_FIRS8
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|8, 2, {NULL}, 0, 0, S_FIRS1}, // S_FIRS9
-
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|18, 1, {NULL}, 0, 0, S_FIRS11}, // S_FIRS10
-	{SPR_NULL, 0,                           1, {NULL}, 0, 0, S_FIRS1 }, // S_FIRS11
-
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_FIRSB2}, // S_FIRSB1
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_FIRSB3}, // S_FIRSB2
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_FIRSB4}, // S_FIRSB3
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|12, 2, {NULL}, 0, 0, S_FIRSB5}, // S_FIRSB4
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|13, 2, {NULL}, 0, 0, S_FIRSB6}, // S_FIRSB5
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|14, 2, {NULL}, 0, 0, S_FIRSB7}, // S_FIRSB6
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|15, 2, {NULL}, 0, 0, S_FIRSB8}, // S_FIRSB7
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|16, 2, {NULL}, 0, 0, S_FIRSB9}, // S_FIRSB8
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|17, 2, {NULL}, 0, 0, S_FIRSB1}, // S_FIRSB9
-
-	{SPR_NULL, 0,                           2, {NULL}, 0, 0, S_FIRSB1 }, // S_FIRSB10
-
-	{SPR_BUBS, FF_TRANS30  , 3, {NULL}, 0, 0, S_BUBS2}, // S_BUBS1
-	{SPR_BUBS, FF_TRANS30|1, 3, {NULL}, 0, 0, S_BUBS3}, // S_BUBS2
-	{SPR_BUBS, FF_TRANS30|2, 3, {NULL}, 0, 0, S_BUBS4}, // S_BUBS3
-	{SPR_BUBS, FF_TRANS30|3, 3, {NULL}, 0, 0, S_BUBS5}, // S_BUBS4
-	{SPR_BUBS, FF_TRANS30|4, 3, {NULL}, 0, 0, S_BUBS6}, // S_BUBS5
-	{SPR_BUBS, FF_TRANS30|5, 3, {NULL}, 0, 0, S_BUBS7}, // S_BUBS6
-	{SPR_BUBS, FF_TRANS30|6, 3, {NULL}, 0, 0, S_BUBS8}, // S_BUBS7
-	{SPR_BUBS, FF_TRANS30|7, 3, {NULL}, 0, 0, S_BUBS9}, // S_BUBS8
-	{SPR_BUBS, FF_TRANS30|8, 3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS9
-
-	{SPR_NULL, 0,   3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS10
-	{SPR_NULL, 0, 4*3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS11
-
-	{SPR_BUBS, FF_TRANS30| 9, 3, {NULL}, 0, 0, S_BUBSB2}, // S_BUBSB1
-	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB3}, // S_BUBSB2
-	{SPR_BUBS, FF_TRANS30|11, 3, {NULL}, 0, 0, S_BUBSB4}, // S_BUBSB3
-	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB1}, // S_BUBSB4
-
-	{SPR_BUBS, FF_TRANS30|12, 3, {NULL}, 0, 0, S_BUBSB3}, // S_BUBSB5
-	{SPR_BUBS, FF_TRANS30|13, 3, {NULL}, 0, 0, S_BUBSB5}, // S_BUBSB6
-
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,   2, {NULL}, 0, 0, S_ZAPS2 }, // S_ZAPS1
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,   2, {NULL}, 0, 0, S_ZAPS3 }, // S_ZAPS2
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,   2, {NULL}, 0, 0, S_ZAPS4 }, // S_ZAPS3
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,   2, {NULL}, 0, 0, S_ZAPS5 }, // S_ZAPS4
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,   2, {NULL}, 0, 0, S_ZAPS6 }, // S_ZAPS5
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,   2, {NULL}, 0, 0, S_ZAPS7 }, // S_ZAPS6
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,   2, {NULL}, 0, 0, S_ZAPS8 }, // S_ZAPS7
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,   2, {NULL}, 0, 0, S_ZAPS9 }, // S_ZAPS8
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,   2, {NULL}, 0, 0, S_ZAPS10}, // S_ZAPS9
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS11}, // S_ZAPS10
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS12}, // S_ZAPS11
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS13}, // S_ZAPS12
-	{SPR_NULL,                           0, 9*2, {NULL}, 0, 0, S_ZAPS14}, // S_ZAPS13
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS15}, // S_ZAPS14
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS16}, // S_ZAPS15
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS1 }, // S_ZAPS16
-
-	{SPR_NULL,                           0, 12*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB1
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,    2, {NULL}, 0, 0, S_ZAPSB3 }, // S_ZAPSB2
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,    2, {NULL}, 0, 0, S_ZAPSB4 }, // S_ZAPSB3
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,    2, {NULL}, 0, 0, S_ZAPSB5 }, // S_ZAPSB4
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,    2, {NULL}, 0, 0, S_ZAPSB6 }, // S_ZAPSB5
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,    2, {NULL}, 0, 0, S_ZAPSB7 }, // S_ZAPSB6
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,    2, {NULL}, 0, 0, S_ZAPSB8 }, // S_ZAPSB7
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,    2, {NULL}, 0, 0, S_ZAPSB9 }, // S_ZAPSB8
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,    2, {NULL}, 0, 0, S_ZAPSB10}, // S_ZAPSB9
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,    2, {NULL}, 0, 0, S_ZAPSB11}, // S_ZAPSB10
-	{SPR_NULL,                           0, 15*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB11
+	{SPR_ARMA, FF_TRANS40   , 2, {NULL}, 0, 0, S_ARMA2 , 0}, // S_ARMA1
+	{SPR_ARMA, FF_TRANS40| 1, 2, {NULL}, 0, 0, S_ARMA3 , 0}, // S_ARMA2
+	{SPR_ARMA, FF_TRANS40| 2, 2, {NULL}, 0, 0, S_ARMA4 , 0}, // S_ARMA3
+	{SPR_ARMA, FF_TRANS40| 3, 2, {NULL}, 0, 0, S_ARMA5 , 0}, // S_ARMA4
+	{SPR_ARMA, FF_TRANS40| 4, 2, {NULL}, 0, 0, S_ARMA6 , 0}, // S_ARMA5
+	{SPR_ARMA, FF_TRANS40| 5, 2, {NULL}, 0, 0, S_ARMA7 , 0}, // S_ARMA6
+	{SPR_ARMA, FF_TRANS40| 6, 2, {NULL}, 0, 0, S_ARMA8 , 0}, // S_ARMA7
+	{SPR_ARMA, FF_TRANS40| 7, 2, {NULL}, 0, 0, S_ARMA9 , 0}, // S_ARMA8
+	{SPR_ARMA, FF_TRANS40| 8, 2, {NULL}, 0, 0, S_ARMA10, 0}, // S_ARMA9
+	{SPR_ARMA, FF_TRANS40| 9, 2, {NULL}, 0, 0, S_ARMA11, 0}, // S_ARMA10
+	{SPR_ARMA, FF_TRANS40|10, 2, {NULL}, 0, 0, S_ARMA12, 0}, // S_ARMA11
+	{SPR_ARMA, FF_TRANS40|11, 2, {NULL}, 0, 0, S_ARMA13, 0}, // S_ARMA12
+	{SPR_ARMA, FF_TRANS40|12, 2, {NULL}, 0, 0, S_ARMA14, 0}, // S_ARMA13
+	{SPR_ARMA, FF_TRANS40|13, 2, {NULL}, 0, 0, S_ARMA15, 0}, // S_ARMA14
+	{SPR_ARMA, FF_TRANS40|14, 2, {NULL}, 0, 0, S_ARMA16, 0}, // S_ARMA15
+	{SPR_ARMA, FF_TRANS40|15, 2, {NULL}, 0, 0, S_ARMA1 , 0}, // S_ARMA16
+
+	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF2 , 0}, // S_ARMF1
+	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF3 , 0}, // S_ARMF2
+	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF4 , 0}, // S_ARMF3
+	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF5 , 0}, // S_ARMF4
+	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF6 , 0}, // S_ARMF5
+	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF7 , 0}, // S_ARMF6
+	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF8 , 0}, // S_ARMF7
+	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF9 , 0}, // S_ARMF8
+	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF10, 0}, // S_ARMF9
+	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF11, 0}, // S_ARMF10
+	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF12, 0}, // S_ARMF11
+	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF13, 0}, // S_ARMF12
+	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF14, 0}, // S_ARMF13
+	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF15, 0}, // S_ARMF14
+	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF16, 0}, // S_ARMF15
+	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF17, 0}, // S_ARMF16
+	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF18, 0}, // S_ARMF17
+	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF19, 0}, // S_ARMF18
+	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF20, 0}, // S_ARMF19
+	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF21, 0}, // S_ARMF20
+	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF22, 0}, // S_ARMF21
+	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF23, 0}, // S_ARMF22
+	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF24, 0}, // S_ARMF23
+	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF25, 0}, // S_ARMF24
+	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF26, 0}, // S_ARMF25
+	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF27, 0}, // S_ARMF26
+	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF28, 0}, // S_ARMF27
+	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF29, 0}, // S_ARMF28
+	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF30, 0}, // S_ARMF29
+	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF31, 0}, // S_ARMF30
+	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF32, 0}, // S_ARMF31
+	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF1 , 0}, // S_ARMF32
+
+	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB2 , 0}, // S_ARMB1
+	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB3 , 0}, // S_ARMB2
+	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB4 , 0}, // S_ARMB3
+	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB5 , 0}, // S_ARMB4
+	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB6 , 0}, // S_ARMB5
+	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB7 , 0}, // S_ARMB6
+	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB8 , 0}, // S_ARMB7
+	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB9 , 0}, // S_ARMB8
+	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB10, 0}, // S_ARMB9
+	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB11, 0}, // S_ARMB10
+	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB12, 0}, // S_ARMB11
+	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB13, 0}, // S_ARMB12
+	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB14, 0}, // S_ARMB13
+	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB15, 0}, // S_ARMB14
+	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB16, 0}, // S_ARMB15
+	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB17, 0}, // S_ARMB16
+	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB18, 0}, // S_ARMB17
+	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB19, 0}, // S_ARMB18
+	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB20, 0}, // S_ARMB19
+	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB21, 0}, // S_ARMB20
+	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB22, 0}, // S_ARMB21
+	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB23, 0}, // S_ARMB22
+	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB24, 0}, // S_ARMB23
+	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB25, 0}, // S_ARMB24
+	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB26, 0}, // S_ARMB25
+	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB27, 0}, // S_ARMB26
+	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB28, 0}, // S_ARMB27
+	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB29, 0}, // S_ARMB28
+	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB30, 0}, // S_ARMB29
+	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB31, 0}, // S_ARMB30
+	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB32, 0}, // S_ARMB31
+	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB1 , 0}, // S_ARMB32
+
+	{SPR_WIND, FF_TRANS70  , 2, {NULL}, 0, 0, S_WIND2, 0}, // S_WIND1
+	{SPR_WIND, FF_TRANS70|1, 2, {NULL}, 0, 0, S_WIND3, 0}, // S_WIND2
+	{SPR_WIND, FF_TRANS70|2, 2, {NULL}, 0, 0, S_WIND4, 0}, // S_WIND3
+	{SPR_WIND, FF_TRANS70|3, 2, {NULL}, 0, 0, S_WIND5, 0}, // S_WIND4
+	{SPR_WIND, FF_TRANS70|4, 2, {NULL}, 0, 0, S_WIND6, 0}, // S_WIND5
+	{SPR_WIND, FF_TRANS70|5, 2, {NULL}, 0, 0, S_WIND7, 0}, // S_WIND6
+	{SPR_WIND, FF_TRANS70|6, 2, {NULL}, 0, 0, S_WIND8, 0}, // S_WIND7
+	{SPR_WIND, FF_TRANS70|7, 2, {NULL}, 0, 0, S_WIND1, 0}, // S_WIND8
+
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40   , 2, {NULL}, 0, 0, S_MAGN2 , 0}, // S_MAGN1
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 1, 2, {NULL}, 0, 0, S_MAGN3 , 0}, // S_MAGN2
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 2, 2, {NULL}, 0, 0, S_MAGN4 , 0}, // S_MAGN3
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 3, 2, {NULL}, 0, 0, S_MAGN5 , 0}, // S_MAGN4
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 4, 2, {NULL}, 0, 0, S_MAGN6 , 0}, // S_MAGN5
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 5, 2, {NULL}, 0, 0, S_MAGN7 , 0}, // S_MAGN6
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 6, 2, {NULL}, 0, 0, S_MAGN8 , 0}, // S_MAGN7
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 7, 2, {NULL}, 0, 0, S_MAGN9 , 0}, // S_MAGN8
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 8, 2, {NULL}, 0, 0, S_MAGN10, 0}, // S_MAGN9
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_MAGN11, 0}, // S_MAGN10
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_MAGN12, 0}, // S_MAGN11
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_MAGN1 , 0}, // S_MAGN12
+
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS10|12, 2, {NULL}, 0, 0, S_MAGN1 , 0}, // S_MAGN13
+
+	{SPR_FORC, FF_TRANS50  , 3, {NULL}, 0, 0, S_FORC2 , 0}, // S_FORC1
+	{SPR_FORC, FF_TRANS50|1, 3, {NULL}, 0, 0, S_FORC3 , 0}, // S_FORC2
+	{SPR_FORC, FF_TRANS50|2, 3, {NULL}, 0, 0, S_FORC4 , 0}, // S_FORC3
+	{SPR_FORC, FF_TRANS50|3, 3, {NULL}, 0, 0, S_FORC5 , 0}, // S_FORC4
+	{SPR_FORC, FF_TRANS50|4, 3, {NULL}, 0, 0, S_FORC6 , 0}, // S_FORC5
+	{SPR_FORC, FF_TRANS50|5, 3, {NULL}, 0, 0, S_FORC7 , 0}, // S_FORC6
+	{SPR_FORC, FF_TRANS50|6, 3, {NULL}, 0, 0, S_FORC8 , 0}, // S_FORC7
+	{SPR_FORC, FF_TRANS50|7, 3, {NULL}, 0, 0, S_FORC9 , 0}, // S_FORC8
+	{SPR_FORC, FF_TRANS50|8, 3, {NULL}, 0, 0, S_FORC10, 0}, // S_FORC9
+	{SPR_FORC, FF_TRANS50|9, 3, {NULL}, 0, 0, S_FORC1 , 0}, // S_FORC10
+
+	{SPR_FORC, FF_TRANS50|10, 3, {NULL}, 0, 0, S_FORC12, 0}, // S_FORC11
+	{SPR_FORC, FF_TRANS50|11, 3, {NULL}, 0, 0, S_FORC13, 0}, // S_FORC12
+	{SPR_FORC, FF_TRANS50|12, 3, {NULL}, 0, 0, S_FORC14, 0}, // S_FORC13
+	{SPR_FORC, FF_TRANS50|13, 3, {NULL}, 0, 0, S_FORC15, 0}, // S_FORC14
+	{SPR_FORC, FF_TRANS50|14, 3, {NULL}, 0, 0, S_FORC16, 0}, // S_FORC15
+	{SPR_FORC, FF_TRANS50|15, 3, {NULL}, 0, 0, S_FORC17, 0}, // S_FORC16
+	{SPR_FORC, FF_TRANS50|16, 3, {NULL}, 0, 0, S_FORC18, 0}, // S_FORC17
+	{SPR_FORC, FF_TRANS50|17, 3, {NULL}, 0, 0, S_FORC19, 0}, // S_FORC18
+	{SPR_FORC, FF_TRANS50|18, 3, {NULL}, 0, 0, S_FORC20, 0}, // S_FORC19
+	{SPR_FORC, FF_TRANS50|19, 3, {NULL}, 0, 0, S_FORC11, 0}, // S_FORC20
+
+	{SPR_FORC, FF_TRANS50|20, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FORC21
+
+	{SPR_ELEM, FF_TRANS50   , 4, {NULL}, 0, 0, S_ELEM2 , 0}, // S_ELEM1
+	{SPR_ELEM, FF_TRANS50| 1, 4, {NULL}, 0, 0, S_ELEM3 , 0}, // S_ELEM2
+	{SPR_ELEM, FF_TRANS50| 2, 4, {NULL}, 0, 0, S_ELEM4 , 0}, // S_ELEM3
+	{SPR_ELEM, FF_TRANS50| 3, 4, {NULL}, 0, 0, S_ELEM5 , 0}, // S_ELEM4
+	{SPR_ELEM, FF_TRANS50| 4, 4, {NULL}, 0, 0, S_ELEM6 , 0}, // S_ELEM5
+	{SPR_ELEM, FF_TRANS50| 5, 4, {NULL}, 0, 0, S_ELEM7 , 0}, // S_ELEM6
+	{SPR_ELEM, FF_TRANS50| 6, 4, {NULL}, 0, 0, S_ELEM8 , 0}, // S_ELEM7
+	{SPR_ELEM, FF_TRANS50| 7, 4, {NULL}, 0, 0, S_ELEM9 , 0}, // S_ELEM8
+	{SPR_ELEM, FF_TRANS50| 8, 4, {NULL}, 0, 0, S_ELEM10, 0}, // S_ELEM9
+	{SPR_ELEM, FF_TRANS50| 9, 4, {NULL}, 0, 0, S_ELEM11, 0}, // S_ELEM10
+	{SPR_ELEM, FF_TRANS50|10, 4, {NULL}, 0, 0, S_ELEM12, 0}, // S_ELEM11
+	{SPR_ELEM, FF_TRANS50|11, 4, {NULL}, 0, 0, S_ELEM1 , 0}, // S_ELEM12
+
+	{SPR_NULL,             0, 1, {NULL}, 0, 0, S_ELEM14, 0}, // S_ELEM13
+	{SPR_ELEM, FF_TRANS50|11, 1, {NULL}, 0, 0, S_ELEM1 , 0}, // S_ELEM14
+
+	{SPR_ELEM, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ELEMF2 , 0}, // S_ELEMF1
+	{SPR_ELEM, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ELEMF3 , 0}, // S_ELEMF2
+	{SPR_ELEM, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ELEMF4 , 0}, // S_ELEMF3
+	{SPR_ELEM, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ELEMF5 , 0}, // S_ELEMF4
+	{SPR_ELEM, FF_FULLBRIGHT|16, 3, {NULL}, 0, 0, S_ELEMF6 , 0}, // S_ELEMF5
+	{SPR_ELEM, FF_FULLBRIGHT|17, 3, {NULL}, 0, 0, S_ELEMF7 , 0}, // S_ELEMF6
+	{SPR_ELEM, FF_FULLBRIGHT|18, 3, {NULL}, 0, 0, S_ELEMF8 , 0}, // S_ELEMF7
+	{SPR_ELEM, FF_FULLBRIGHT|19, 3, {NULL}, 0, 0, S_ELEMF1 , 0}, // S_ELEMF8
+
+	{SPR_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10, 0}, // S_ELEMF9
+	{SPR_NULL, 0,                1, {NULL}, 0, 0, S_ELEMF1 , 0}, // S_ELEMF10
+
+	{SPR_PITY, FF_TRANS30   , 2, {NULL}, 0, 0, S_PITY2, 0},  // S_PITY1
+	{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3, 0},  // S_PITY2
+	{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4, 0},  // S_PITY3
+	{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5, 0},  // S_PITY4
+	{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6, 0},  // S_PITY5
+	{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7, 0},  // S_PITY6
+	{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8, 0},  // S_PITY7
+	{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9, 0},  // S_PITY8
+	{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10, 0}, // S_PITY9
+	{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11, 0}, // S_PITY10
+	{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12, 0}, // S_PITY11
+	{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1, 0},  // S_PITY12
+
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40  , 2, {NULL}, 0, 0, S_FIRS2, 0}, // S_FIRS1
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3, 0}, // S_FIRS2
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|2, 2, {NULL}, 0, 0, S_FIRS4, 0}, // S_FIRS3
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|3, 2, {NULL}, 0, 0, S_FIRS5, 0}, // S_FIRS4
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|4, 2, {NULL}, 0, 0, S_FIRS6, 0}, // S_FIRS5
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|5, 2, {NULL}, 0, 0, S_FIRS7, 0}, // S_FIRS6
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|6, 2, {NULL}, 0, 0, S_FIRS8, 0}, // S_FIRS7
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|7, 2, {NULL}, 0, 0, S_FIRS9, 0}, // S_FIRS8
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|8, 2, {NULL}, 0, 0, S_FIRS1, 0}, // S_FIRS9
+
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|18, 1, {NULL}, 0, 0, S_FIRS11, 0}, // S_FIRS10
+	{SPR_NULL, 0,                           1, {NULL}, 0, 0, S_FIRS1 , 0}, // S_FIRS11
+
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_FIRSB2, 0}, // S_FIRSB1
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_FIRSB3, 0}, // S_FIRSB2
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_FIRSB4, 0}, // S_FIRSB3
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|12, 2, {NULL}, 0, 0, S_FIRSB5, 0}, // S_FIRSB4
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|13, 2, {NULL}, 0, 0, S_FIRSB6, 0}, // S_FIRSB5
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|14, 2, {NULL}, 0, 0, S_FIRSB7, 0}, // S_FIRSB6
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|15, 2, {NULL}, 0, 0, S_FIRSB8, 0}, // S_FIRSB7
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|16, 2, {NULL}, 0, 0, S_FIRSB9, 0}, // S_FIRSB8
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|17, 2, {NULL}, 0, 0, S_FIRSB1, 0}, // S_FIRSB9
+
+	{SPR_NULL, 0,                           2, {NULL}, 0, 0, S_FIRSB1 , 0}, // S_FIRSB10
+
+	{SPR_BUBS, FF_TRANS30  , 3, {NULL}, 0, 0, S_BUBS2, 0}, // S_BUBS1
+	{SPR_BUBS, FF_TRANS30|1, 3, {NULL}, 0, 0, S_BUBS3, 0}, // S_BUBS2
+	{SPR_BUBS, FF_TRANS30|2, 3, {NULL}, 0, 0, S_BUBS4, 0}, // S_BUBS3
+	{SPR_BUBS, FF_TRANS30|3, 3, {NULL}, 0, 0, S_BUBS5, 0}, // S_BUBS4
+	{SPR_BUBS, FF_TRANS30|4, 3, {NULL}, 0, 0, S_BUBS6, 0}, // S_BUBS5
+	{SPR_BUBS, FF_TRANS30|5, 3, {NULL}, 0, 0, S_BUBS7, 0}, // S_BUBS6
+	{SPR_BUBS, FF_TRANS30|6, 3, {NULL}, 0, 0, S_BUBS8, 0}, // S_BUBS7
+	{SPR_BUBS, FF_TRANS30|7, 3, {NULL}, 0, 0, S_BUBS9, 0}, // S_BUBS8
+	{SPR_BUBS, FF_TRANS30|8, 3, {NULL}, 0, 0, S_BUBS1, 0}, // S_BUBS9
+
+	{SPR_NULL, 0,   3, {NULL}, 0, 0, S_BUBS1, 0}, // S_BUBS10
+	{SPR_NULL, 0, 4*3, {NULL}, 0, 0, S_BUBS1, 0}, // S_BUBS11
+
+	{SPR_BUBS, FF_TRANS30| 9, 3, {NULL}, 0, 0, S_BUBSB2, 0}, // S_BUBSB1
+	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB3, 0}, // S_BUBSB2
+	{SPR_BUBS, FF_TRANS30|11, 3, {NULL}, 0, 0, S_BUBSB4, 0}, // S_BUBSB3
+	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB1, 0}, // S_BUBSB4
+
+	{SPR_BUBS, FF_TRANS30|12, 3, {NULL}, 0, 0, S_BUBSB3, 0}, // S_BUBSB5
+	{SPR_BUBS, FF_TRANS30|13, 3, {NULL}, 0, 0, S_BUBSB5, 0}, // S_BUBSB6
+
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,   2, {NULL}, 0, 0, S_ZAPS2 , 0}, // S_ZAPS1
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,   2, {NULL}, 0, 0, S_ZAPS3 , 0}, // S_ZAPS2
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,   2, {NULL}, 0, 0, S_ZAPS4 , 0}, // S_ZAPS3
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,   2, {NULL}, 0, 0, S_ZAPS5 , 0}, // S_ZAPS4
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,   2, {NULL}, 0, 0, S_ZAPS6 , 0}, // S_ZAPS5
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,   2, {NULL}, 0, 0, S_ZAPS7 , 0}, // S_ZAPS6
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,   2, {NULL}, 0, 0, S_ZAPS8 , 0}, // S_ZAPS7
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,   2, {NULL}, 0, 0, S_ZAPS9 , 0}, // S_ZAPS8
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,   2, {NULL}, 0, 0, S_ZAPS10, 0}, // S_ZAPS9
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS11, 0}, // S_ZAPS10
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS12, 0}, // S_ZAPS11
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS13, 0}, // S_ZAPS12
+	{SPR_NULL,                           0, 9*2, {NULL}, 0, 0, S_ZAPS14, 0}, // S_ZAPS13
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS15, 0}, // S_ZAPS14
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS16, 0}, // S_ZAPS15
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS1 , 0}, // S_ZAPS16
+
+	{SPR_NULL,                           0, 12*2, {NULL}, 0, 0, S_ZAPSB2 , 0}, // S_ZAPSB1
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,    2, {NULL}, 0, 0, S_ZAPSB3 , 0}, // S_ZAPSB2
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,    2, {NULL}, 0, 0, S_ZAPSB4 , 0}, // S_ZAPSB3
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,    2, {NULL}, 0, 0, S_ZAPSB5 , 0}, // S_ZAPSB4
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,    2, {NULL}, 0, 0, S_ZAPSB6 , 0}, // S_ZAPSB5
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,    2, {NULL}, 0, 0, S_ZAPSB7 , 0}, // S_ZAPSB6
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,    2, {NULL}, 0, 0, S_ZAPSB8 , 0}, // S_ZAPSB7
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,    2, {NULL}, 0, 0, S_ZAPSB9 , 0}, // S_ZAPSB8
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,    2, {NULL}, 0, 0, S_ZAPSB10, 0}, // S_ZAPSB9
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,    2, {NULL}, 0, 0, S_ZAPSB11, 0}, // S_ZAPSB10
+	{SPR_NULL,                           0, 15*2, {NULL}, 0, 0, S_ZAPSB2 , 0}, // S_ZAPSB11
 
 	// Thunder spark
-	{SPR_SSPK, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL},   // S_THUNDERCOIN_SPARK
+	{SPR_SSPK, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL, 0},   // S_THUNDERCOIN_SPARK
 
 	// Invincibility Sparkles
-	{SPR_IVSP, FF_ANIMATE|FF_FULLBRIGHT, 32, {NULL}, 31, 1, S_NULL},   // S_IVSP
+	{SPR_IVSP, FF_ANIMATE|FF_FULLBRIGHT, 32, {NULL}, 31, 1, S_NULL, 0},   // S_IVSP
 
 	// Super Sonic Spark
-	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1
-	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK3}, // S_SSPK2
-	{SPR_SSPK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK4}, // S_SSPK3
-	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK5}, // S_SSPK4
-	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL},  // S_SSPK5
+	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2, 0}, // S_SSPK1
+	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK3, 0}, // S_SSPK2
+	{SPR_SSPK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK4, 0}, // S_SSPK3
+	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK5, 0}, // S_SSPK4
+	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0},  // S_SSPK5
 
 	// Flicky-sized bubble
-	{SPR_FBUB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FLICKY_BUBBLE
+	{SPR_FBUB, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FLICKY_BUBBLE
 
 	// Bluebird
-	{SPR_FL01, 0, 2, {A_FlickyCheck}, S_FLICKY_01_FLAP1, S_FLICKY_01_FLAP1, S_FLICKY_01_OUT},   // S_FLICKY_01_OUT
-	{SPR_FL01, 1, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP2}, // S_FLICKY_01_FLAP1
-	{SPR_FL01, 2, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP3}, // S_FLICKY_01_FLAP2
-	{SPR_FL01, 3, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP1}, // S_FLICKY_01_FLAP3
-	{SPR_FL01, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL},                                         // S_FLICKY_01_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_01, 384*FRACUNIT, S_FLICKY_01_CENTER},        // S_FLICKY_01_CENTER
+	{SPR_FL01, 0, 2, {A_FlickyCheck}, S_FLICKY_01_FLAP1, S_FLICKY_01_FLAP1, S_FLICKY_01_OUT, 0},   // S_FLICKY_01_OUT
+	{SPR_FL01, 1, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP2, 0}, // S_FLICKY_01_FLAP1
+	{SPR_FL01, 2, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP3, 0}, // S_FLICKY_01_FLAP2
+	{SPR_FL01, 3, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP1, 0}, // S_FLICKY_01_FLAP3
+	{SPR_FL01, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL, 0},                                         // S_FLICKY_01_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_01, 384*FRACUNIT, S_FLICKY_01_CENTER, 0},        // S_FLICKY_01_CENTER
 
 	// Rabbit
-	{SPR_FL02, 0, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_OUT},  // S_FLICKY_02_OUT
-	{SPR_FL02, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_02_HOP},  // S_FLICKY_02_AIM
-	{SPR_FL02, 1, 1, {A_FlickyHop},        6*FRACUNIT,       4*FRACUNIT, S_FLICKY_02_UP},   // S_FLICKY_02_HOP
-	{SPR_FL02, 2, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, S_FLICKY_02_DOWN, S_FLICKY_02_UP},   // S_FLICKY_02_UP
-	{SPR_FL02, 3, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_DOWN}, // S_FLICKY_02_DOWN
-	{SPR_FL02, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_02_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_02, 384*FRACUNIT, S_FLICKY_02_CENTER},        // S_FLICKY_02_CENTER
+	{SPR_FL02, 0, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_OUT, 0},  // S_FLICKY_02_OUT
+	{SPR_FL02, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_02_HOP, 0},  // S_FLICKY_02_AIM
+	{SPR_FL02, 1, 1, {A_FlickyHop},        6*FRACUNIT,       4*FRACUNIT, S_FLICKY_02_UP, 0},   // S_FLICKY_02_HOP
+	{SPR_FL02, 2, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, S_FLICKY_02_DOWN, S_FLICKY_02_UP, 0},   // S_FLICKY_02_UP
+	{SPR_FL02, 3, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_DOWN, 0}, // S_FLICKY_02_DOWN
+	{SPR_FL02, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_02_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_02, 384*FRACUNIT, S_FLICKY_02_CENTER, 0},        // S_FLICKY_02_CENTER
 
 	// Chicken
-	{SPR_FL03, 0, 2, {A_FlickyCheck},   S_FLICKY_03_AIM, S_FLICKY_03_FLAP1, S_FLICKY_03_OUT},   // S_FLICKY_03_OUT
-	{SPR_FL03, 1, 1, {A_FlickyAim},            ANGLE_45,       32*FRACUNIT, S_FLICKY_03_HOP},   // S_FLICKY_03_AIM
-	{SPR_FL03, 1, 1, {A_FlickyHop},          7*FRACUNIT,        2*FRACUNIT, S_FLICKY_03_UP},    // S_FLICKY_03_HOP
-	{SPR_FL03, 2, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, S_FLICKY_03_FLAP1, S_FLICKY_03_UP},    // S_FLICKY_03_UP
-	{SPR_FL03, 3, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP2}, // S_FLICKY_03_FLAP1
-	{SPR_FL03, 4, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP1}, // S_FLICKY_03_FLAP2
-	{SPR_FL03, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_03_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_03, 384*FRACUNIT, S_FLICKY_03_CENTER},        // S_FLICKY_03_CENTER
+	{SPR_FL03, 0, 2, {A_FlickyCheck},   S_FLICKY_03_AIM, S_FLICKY_03_FLAP1, S_FLICKY_03_OUT, 0},   // S_FLICKY_03_OUT
+	{SPR_FL03, 1, 1, {A_FlickyAim},            ANGLE_45,       32*FRACUNIT, S_FLICKY_03_HOP, 0},   // S_FLICKY_03_AIM
+	{SPR_FL03, 1, 1, {A_FlickyHop},          7*FRACUNIT,        2*FRACUNIT, S_FLICKY_03_UP, 0},    // S_FLICKY_03_HOP
+	{SPR_FL03, 2, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, S_FLICKY_03_FLAP1, S_FLICKY_03_UP, 0},    // S_FLICKY_03_UP
+	{SPR_FL03, 3, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP2, 0}, // S_FLICKY_03_FLAP1
+	{SPR_FL03, 4, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP1, 0}, // S_FLICKY_03_FLAP2
+	{SPR_FL03, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_03_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_03, 384*FRACUNIT, S_FLICKY_03_CENTER, 0},        // S_FLICKY_03_CENTER
 
 	// Seal
-	{SPR_FL04, 0, 2, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_OUT},   // S_FLICKY_04_OUT
-	{SPR_FL04, 1, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_04_HOP},   // S_FLICKY_04_AIM
-	{SPR_FL04, 1, 1, {A_FlickyHop},        3*FRACUNIT,        2*FRACUNIT, S_FLICKY_04_UP},    // S_FLICKY_04_HOP
-	{SPR_FL04, 2, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,  S_FLICKY_04_DOWN, S_FLICKY_04_UP},    // S_FLICKY_04_UP
-	{SPR_FL04, 3, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_DOWN},  // S_FLICKY_04_DOWN
-	{SPR_FL04, 3, 4, {A_FlickyFly},        2*FRACUNIT,       48*FRACUNIT, S_FLICKY_04_SWIM2}, // S_FLICKY_04_SWIM1
-	{SPR_FL04, 4, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM3}, // S_FLICKY_04_SWIM2
-	{SPR_FL04, 3, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM4}, // S_FLICKY_04_SWIM3
-	{SPR_FL04, 5, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM1}, // S_FLICKY_04_SWIM4
-	{SPR_FL04, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_04_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_04, 384*FRACUNIT, S_FLICKY_04_CENTER},        // S_FLICKY_04_CENTER
+	{SPR_FL04, 0, 2, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_OUT, 0},   // S_FLICKY_04_OUT
+	{SPR_FL04, 1, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_04_HOP, 0},   // S_FLICKY_04_AIM
+	{SPR_FL04, 1, 1, {A_FlickyHop},        3*FRACUNIT,        2*FRACUNIT, S_FLICKY_04_UP, 0},    // S_FLICKY_04_HOP
+	{SPR_FL04, 2, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,  S_FLICKY_04_DOWN, S_FLICKY_04_UP, 0},    // S_FLICKY_04_UP
+	{SPR_FL04, 3, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_DOWN, 0},  // S_FLICKY_04_DOWN
+	{SPR_FL04, 3, 4, {A_FlickyFly},        2*FRACUNIT,       48*FRACUNIT, S_FLICKY_04_SWIM2, 0}, // S_FLICKY_04_SWIM1
+	{SPR_FL04, 4, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM3, 0}, // S_FLICKY_04_SWIM2
+	{SPR_FL04, 3, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM4, 0}, // S_FLICKY_04_SWIM3
+	{SPR_FL04, 5, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM1, 0}, // S_FLICKY_04_SWIM4
+	{SPR_FL04, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_04_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_04, 384*FRACUNIT, S_FLICKY_04_CENTER, 0},        // S_FLICKY_04_CENTER
 
 	// Pig
-	{SPR_FL05, 0, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_OUT},  // S_FLICKY_05_OUT
-	{SPR_FL05, 1, 1, {A_FlickyAim},             ANG20,      32*FRACUNIT, S_FLICKY_05_HOP},  // S_FLICKY_05_AIM
-	{SPR_FL05, 1, 1, {A_FlickyHop},        4*FRACUNIT,       3*FRACUNIT, S_FLICKY_05_UP},   // S_FLICKY_05_HOP
-	{SPR_FL05, 2, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, S_FLICKY_05_DOWN, S_FLICKY_05_UP},   // S_FLICKY_05_UP
-	{SPR_FL05, 3, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_DOWN}, // S_FLICKY_05_DOWN
-	{SPR_FL05, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_05_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_05, 384*FRACUNIT, S_FLICKY_05_CENTER},        // S_FLICKY_05_CENTER
+	{SPR_FL05, 0, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_OUT, 0},  // S_FLICKY_05_OUT
+	{SPR_FL05, 1, 1, {A_FlickyAim},             ANG20,      32*FRACUNIT, S_FLICKY_05_HOP, 0},  // S_FLICKY_05_AIM
+	{SPR_FL05, 1, 1, {A_FlickyHop},        4*FRACUNIT,       3*FRACUNIT, S_FLICKY_05_UP, 0},   // S_FLICKY_05_HOP
+	{SPR_FL05, 2, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, S_FLICKY_05_DOWN, S_FLICKY_05_UP, 0},   // S_FLICKY_05_UP
+	{SPR_FL05, 3, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_DOWN, 0}, // S_FLICKY_05_DOWN
+	{SPR_FL05, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_05_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_05, 384*FRACUNIT, S_FLICKY_05_CENTER, 0},        // S_FLICKY_05_CENTER
 
 	// Chipmunk
-	{SPR_FL06, 0, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_OUT},  // S_FLICKY_06_OUT
-	{SPR_FL06, 1, 1, {A_FlickyAim},          ANGLE_90,      32*FRACUNIT, S_FLICKY_06_HOP},  // S_FLICKY_06_AIM
-	{SPR_FL06, 1, 1, {A_FlickyHop},        5*FRACUNIT,       6*FRACUNIT, S_FLICKY_06_UP},   // S_FLICKY_06_HOP
-	{SPR_FL06, 2, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, S_FLICKY_06_DOWN, S_FLICKY_06_UP},   // S_FLICKY_06_UP
-	{SPR_FL06, 3, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_DOWN}, // S_FLICKY_06_DOWN
-	{SPR_FL06, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_06_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_06, 384*FRACUNIT, S_FLICKY_06_CENTER},        // S_FLICKY_06_CENTER
+	{SPR_FL06, 0, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_OUT, 0},  // S_FLICKY_06_OUT
+	{SPR_FL06, 1, 1, {A_FlickyAim},          ANGLE_90,      32*FRACUNIT, S_FLICKY_06_HOP, 0},  // S_FLICKY_06_AIM
+	{SPR_FL06, 1, 1, {A_FlickyHop},        5*FRACUNIT,       6*FRACUNIT, S_FLICKY_06_UP, 0},   // S_FLICKY_06_HOP
+	{SPR_FL06, 2, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, S_FLICKY_06_DOWN, S_FLICKY_06_UP, 0},   // S_FLICKY_06_UP
+	{SPR_FL06, 3, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_DOWN, 0}, // S_FLICKY_06_DOWN
+	{SPR_FL06, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_06_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_06, 384*FRACUNIT, S_FLICKY_06_CENTER, 0},        // S_FLICKY_06_CENTER
 
 	// Penguin
-	{SPR_FL07, 0, 2, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_OUT},   // S_FLICKY_07_OUT
-	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPL},  // S_FLICKY_07_AIML
-	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPL},   // S_FLICKY_07_HOPL
-	{SPR_FL07, 2, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR, S_FLICKY_07_DOWNL, S_FLICKY_07_UPL},   // S_FLICKY_07_UPL
-	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR,                 0, S_FLICKY_07_DOWNL}, // S_FLICKY_07_DOWNL
-	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPR},  // S_FLICKY_07_AIMR
-	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPR},   // S_FLICKY_07_HOPR
-	{SPR_FL07, 3, 4, {A_FlickyCheck}, S_FLICKY_07_AIML, S_FLICKY_07_DOWNR, S_FLICKY_07_UPR},   // S_FLICKY_07_UPR
-	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_DOWNR}, // S_FLICKY_07_DOWNR
-	{SPR_FL07, 4, 4, {A_FlickyFly},         3*FRACUNIT,       72*FRACUNIT, S_FLICKY_07_SWIM2}, // S_FLICKY_07_SWIM1
-	{SPR_FL07, 5, 4, {A_FlickyCoast},         FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3}, // S_FLICKY_07_SWIM2
-	{SPR_FL07, 6, 4, {A_FlickyCoast},       2*FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3}, // S_FLICKY_07_SWIM3
-	{SPR_FL07, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_07_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_07, 384*FRACUNIT, S_FLICKY_07_CENTER},        // S_FLICKY_07_CENTER
+	{SPR_FL07, 0, 2, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_OUT, 0},   // S_FLICKY_07_OUT
+	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPL, 0},  // S_FLICKY_07_AIML
+	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPL, 0},   // S_FLICKY_07_HOPL
+	{SPR_FL07, 2, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR, S_FLICKY_07_DOWNL, S_FLICKY_07_UPL, 0},   // S_FLICKY_07_UPL
+	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR,                 0, S_FLICKY_07_DOWNL, 0}, // S_FLICKY_07_DOWNL
+	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPR, 0},  // S_FLICKY_07_AIMR
+	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPR, 0},   // S_FLICKY_07_HOPR
+	{SPR_FL07, 3, 4, {A_FlickyCheck}, S_FLICKY_07_AIML, S_FLICKY_07_DOWNR, S_FLICKY_07_UPR, 0},   // S_FLICKY_07_UPR
+	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_DOWNR, 0}, // S_FLICKY_07_DOWNR
+	{SPR_FL07, 4, 4, {A_FlickyFly},         3*FRACUNIT,       72*FRACUNIT, S_FLICKY_07_SWIM2, 0}, // S_FLICKY_07_SWIM1
+	{SPR_FL07, 5, 4, {A_FlickyCoast},         FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3, 0}, // S_FLICKY_07_SWIM2
+	{SPR_FL07, 6, 4, {A_FlickyCoast},       2*FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3, 0}, // S_FLICKY_07_SWIM3
+	{SPR_FL07, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_07_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_07, 384*FRACUNIT, S_FLICKY_07_CENTER, 0},        // S_FLICKY_07_CENTER
 
 	// Fish
-	{SPR_FL08, 0, 2, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_OUT},   // S_FLICKY_08_OUT
-	{SPR_FL08, 2, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_08_HOP},   // S_FLICKY_08_AIM
-	{SPR_FL08, 2, 1, {A_FlickyFlounder},   2*FRACUNIT,        1*FRACUNIT, S_FLICKY_08_FLAP1}, // S_FLICKY_08_HOP
-	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP2}, // S_FLICKY_08_FLAP1
-	{SPR_FL08, 1, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP3}, // S_FLICKY_08_FLAP2
-	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP4}, // S_FLICKY_08_FLAP3
-	{SPR_FL08, 2, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP1}, // S_FLICKY_08_FLAP4
-	{SPR_FL08, 0, 4, {A_FlickyFly},        3*FRACUNIT,       64*FRACUNIT, S_FLICKY_08_SWIM2}, // S_FLICKY_08_SWIM1
-	{SPR_FL08, 1, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM3}, // S_FLICKY_08_SWIM2
-	{SPR_FL08, 0, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4}, // S_FLICKY_08_SWIM3
-	{SPR_FL08, 2, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4}, // S_FLICKY_08_SWIM4
-	{SPR_FL08, FF_ANIMATE, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_08_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_08, 384*FRACUNIT, S_FLICKY_08_CENTER},        // S_FLICKY_08_CENTER
+	{SPR_FL08, 0, 2, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_OUT, 0},   // S_FLICKY_08_OUT
+	{SPR_FL08, 2, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_08_HOP, 0},   // S_FLICKY_08_AIM
+	{SPR_FL08, 2, 1, {A_FlickyFlounder},   2*FRACUNIT,        1*FRACUNIT, S_FLICKY_08_FLAP1, 0}, // S_FLICKY_08_HOP
+	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP2, 0}, // S_FLICKY_08_FLAP1
+	{SPR_FL08, 1, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP3, 0}, // S_FLICKY_08_FLAP2
+	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP4, 0}, // S_FLICKY_08_FLAP3
+	{SPR_FL08, 2, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP1, 0}, // S_FLICKY_08_FLAP4
+	{SPR_FL08, 0, 4, {A_FlickyFly},        3*FRACUNIT,       64*FRACUNIT, S_FLICKY_08_SWIM2, 0}, // S_FLICKY_08_SWIM1
+	{SPR_FL08, 1, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM3, 0}, // S_FLICKY_08_SWIM2
+	{SPR_FL08, 0, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4, 0}, // S_FLICKY_08_SWIM3
+	{SPR_FL08, 2, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4, 0}, // S_FLICKY_08_SWIM4
+	{SPR_FL08, FF_ANIMATE, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_08_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_08, 384*FRACUNIT, S_FLICKY_08_CENTER, 0},        // S_FLICKY_08_CENTER
 
 	// Ram
-	{SPR_FL09, 0, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_OUT},  // S_FLICKY_09_OUT
-	{SPR_FL09, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_09_HOP},  // S_FLICKY_09_AIM
-	{SPR_FL09, 1, 1, {A_FlickyHop},        7*FRACUNIT,       2*FRACUNIT, S_FLICKY_09_UP},   // S_FLICKY_09_HOP
-	{SPR_FL09, 2, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, S_FLICKY_09_DOWN, S_FLICKY_09_UP},   // S_FLICKY_09_UP
-	{SPR_FL09, 3, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_DOWN}, // S_FLICKY_09_DOWN
-	{SPR_FL09, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_09_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_09, 384*FRACUNIT, S_FLICKY_09_CENTER},        // S_FLICKY_09_CENTER
+	{SPR_FL09, 0, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_OUT, 0},  // S_FLICKY_09_OUT
+	{SPR_FL09, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_09_HOP, 0},  // S_FLICKY_09_AIM
+	{SPR_FL09, 1, 1, {A_FlickyHop},        7*FRACUNIT,       2*FRACUNIT, S_FLICKY_09_UP, 0},   // S_FLICKY_09_HOP
+	{SPR_FL09, 2, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, S_FLICKY_09_DOWN, S_FLICKY_09_UP, 0},   // S_FLICKY_09_UP
+	{SPR_FL09, 3, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_DOWN, 0}, // S_FLICKY_09_DOWN
+	{SPR_FL09, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_09_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_09, 384*FRACUNIT, S_FLICKY_09_CENTER, 0},        // S_FLICKY_09_CENTER
 
 	// Puffin
-	{SPR_FL10, 0, 2, {A_FlickyCheck}, S_FLICKY_10_FLAP1, S_FLICKY_10_FLAP1, S_FLICKY_10_OUT},   // S_FLICKY_10_OUT
-	{SPR_FL10, 1, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP2}, // S_FLICKY_10_FLAP1
-	{SPR_FL10, 2, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP1}, // S_FLICKY_10_FLAP2
-	{SPR_FL10, FF_ANIMATE|1, -1, {NULL}, 1, 3, S_NULL}, // S_FLICKY_10_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_10, 384*FRACUNIT, S_FLICKY_10_CENTER},        // S_FLICKY_10_CENTER
+	{SPR_FL10, 0, 2, {A_FlickyCheck}, S_FLICKY_10_FLAP1, S_FLICKY_10_FLAP1, S_FLICKY_10_OUT, 0},   // S_FLICKY_10_OUT
+	{SPR_FL10, 1, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP2, 0}, // S_FLICKY_10_FLAP1
+	{SPR_FL10, 2, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP1, 0}, // S_FLICKY_10_FLAP2
+	{SPR_FL10, FF_ANIMATE|1, -1, {NULL}, 1, 3, S_NULL, 0}, // S_FLICKY_10_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_10, 384*FRACUNIT, S_FLICKY_10_CENTER, 0},        // S_FLICKY_10_CENTER
 
 	// Cow
-	{SPR_FL11, 0, 2, {A_FlickyCheck}, S_FLICKY_11_AIM,           0, S_FLICKY_11_OUT},  // S_FLICKY_11_OUT
-	{SPR_FL11, 1, 1, {A_FlickyAim},          ANGLE_90, 64*FRACUNIT, S_FLICKY_11_RUN1}, // S_FLICKY_11_AIM
-	{SPR_FL11, 1, 3, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN2}, // S_FLICKY_11_RUN1
-	{SPR_FL11, 2, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN3}, // S_FLICKY_11_RUN2
-	{SPR_FL11, 3, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_AIM},  // S_FLICKY_11_RUN3
-	{SPR_FL11, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_11_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_11, 384*FRACUNIT, S_FLICKY_11_CENTER},        // S_FLICKY_11_CENTER
+	{SPR_FL11, 0, 2, {A_FlickyCheck}, S_FLICKY_11_AIM,           0, S_FLICKY_11_OUT, 0},  // S_FLICKY_11_OUT
+	{SPR_FL11, 1, 1, {A_FlickyAim},          ANGLE_90, 64*FRACUNIT, S_FLICKY_11_RUN1, 0}, // S_FLICKY_11_AIM
+	{SPR_FL11, 1, 3, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN2, 0}, // S_FLICKY_11_RUN1
+	{SPR_FL11, 2, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN3, 0}, // S_FLICKY_11_RUN2
+	{SPR_FL11, 3, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_AIM, 0},  // S_FLICKY_11_RUN3
+	{SPR_FL11, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_11_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_11, 384*FRACUNIT, S_FLICKY_11_CENTER, 0},        // S_FLICKY_11_CENTER
 
 	// Rat
-	{SPR_FL12, 0, 2, {A_FlickyCheck}, S_FLICKY_12_AIM,           0, S_FLICKY_12_OUT},  // S_FLICKY_12_OUT
-	{SPR_FL12, 1, 1, {A_FlickyAim},          ANGLE_90, 32*FRACUNIT, S_FLICKY_12_RUN1}, // S_FLICKY_12_AIM
-	{SPR_FL12, 1, 2, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN2}, // S_FLICKY_12_RUN1
-	{SPR_FL12, 2, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN3}, // S_FLICKY_12_RUN2
-	{SPR_FL12, 3, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_AIM},  // S_FLICKY_12_RUN3
-	{SPR_FL12, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_12_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_12, 384*FRACUNIT, S_FLICKY_12_CENTER},        // S_FLICKY_12_CENTER
+	{SPR_FL12, 0, 2, {A_FlickyCheck}, S_FLICKY_12_AIM,           0, S_FLICKY_12_OUT, 0},  // S_FLICKY_12_OUT
+	{SPR_FL12, 1, 1, {A_FlickyAim},          ANGLE_90, 32*FRACUNIT, S_FLICKY_12_RUN1, 0}, // S_FLICKY_12_AIM
+	{SPR_FL12, 1, 2, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN2, 0}, // S_FLICKY_12_RUN1
+	{SPR_FL12, 2, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN3, 0}, // S_FLICKY_12_RUN2
+	{SPR_FL12, 3, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_AIM, 0},  // S_FLICKY_12_RUN3
+	{SPR_FL12, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_12_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_12, 384*FRACUNIT, S_FLICKY_12_CENTER, 0},        // S_FLICKY_12_CENTER
 
 	// Bear
-	{SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_OUT},  // S_FLICKY_13_OUT
-	{SPR_FL13, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_13_HOP},  // S_FLICKY_13_AIM
-	{SPR_FL13, 1, 1, {A_FlickyHop},        5*FRACUNIT,       3*FRACUNIT, S_FLICKY_13_UP},   // S_FLICKY_13_HOP
-	{SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP},   // S_FLICKY_13_UP
-	{SPR_FL13, 3, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_DOWN}, // S_FLICKY_13_DOWN
-	{SPR_FL13, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_13_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_13, 384*FRACUNIT, S_FLICKY_13_CENTER},        // S_FLICKY_13_CENTER
+	{SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_OUT, 0},  // S_FLICKY_13_OUT
+	{SPR_FL13, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_13_HOP, 0},  // S_FLICKY_13_AIM
+	{SPR_FL13, 1, 1, {A_FlickyHop},        5*FRACUNIT,       3*FRACUNIT, S_FLICKY_13_UP, 0},   // S_FLICKY_13_HOP
+	{SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP, 0},   // S_FLICKY_13_UP
+	{SPR_FL13, 3, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_DOWN, 0}, // S_FLICKY_13_DOWN
+	{SPR_FL13, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_13_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_13, 384*FRACUNIT, S_FLICKY_13_CENTER, 0},        // S_FLICKY_13_CENTER
 
 	// Dove
-	{SPR_FL14, 0, 2, {A_FlickyCheck}, S_FLICKY_14_FLAP1, S_FLICKY_14_FLAP1, S_FLICKY_14_OUT},   // S_FLICKY_14_OUT
-	{SPR_FL14, 1, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP2}, // S_FLICKY_14_FLAP1
-	{SPR_FL14, 2, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP3}, // S_FLICKY_14_FLAP2
-	{SPR_FL14, 3, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP1}, // S_FLICKY_14_FLAP3
-	{SPR_FL14, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_14_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_14, 384*FRACUNIT, S_FLICKY_14_CENTER},        // S_FLICKY_14_CENTER
+	{SPR_FL14, 0, 2, {A_FlickyCheck}, S_FLICKY_14_FLAP1, S_FLICKY_14_FLAP1, S_FLICKY_14_OUT, 0},   // S_FLICKY_14_OUT
+	{SPR_FL14, 1, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP2, 0}, // S_FLICKY_14_FLAP1
+	{SPR_FL14, 2, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP3, 0}, // S_FLICKY_14_FLAP2
+	{SPR_FL14, 3, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP1, 0}, // S_FLICKY_14_FLAP3
+	{SPR_FL14, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL, 0}, // S_FLICKY_14_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_14, 384*FRACUNIT, S_FLICKY_14_CENTER, 0},        // S_FLICKY_14_CENTER
 
 	// Cat
-	{SPR_FL15, 0, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_OUT},  // S_FLICKY_15_OUT
-	{SPR_FL15, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_15_HOP},  // S_FLICKY_15_AIM
-	{SPR_FL15, 1, 1, {A_FlickyFlounder},   2*FRACUNIT,       6*FRACUNIT, S_FLICKY_15_UP},   // S_FLICKY_15_HOP
-	{SPR_FL15, 2, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, S_FLICKY_15_DOWN, S_FLICKY_15_UP},   // S_FLICKY_15_UP
-	{SPR_FL15, 3, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_DOWN}, // S_FLICKY_15_DOWN
-	{SPR_FL15, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_15_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_15, 384*FRACUNIT, S_FLICKY_15_CENTER},        // S_FLICKY_15_CENTER
+	{SPR_FL15, 0, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_OUT, 0},  // S_FLICKY_15_OUT
+	{SPR_FL15, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_15_HOP, 0},  // S_FLICKY_15_AIM
+	{SPR_FL15, 1, 1, {A_FlickyFlounder},   2*FRACUNIT,       6*FRACUNIT, S_FLICKY_15_UP, 0},   // S_FLICKY_15_HOP
+	{SPR_FL15, 2, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, S_FLICKY_15_DOWN, S_FLICKY_15_UP, 0},   // S_FLICKY_15_UP
+	{SPR_FL15, 3, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_DOWN, 0}, // S_FLICKY_15_DOWN
+	{SPR_FL15, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_15_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_15, 384*FRACUNIT, S_FLICKY_15_CENTER, 0},        // S_FLICKY_15_CENTER
 
 	// Canary
-	{SPR_FL16, 0, 2, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_OUT},   // S_FLICKY_16_OUT
-	{SPR_FL16, 1, 3, {A_FlickyFly},                4*FRACUNIT, 8*FRACUNIT, S_FLICKY_16_FLAP2}, // S_FLICKY_16_FLAP1
-	{SPR_FL16, 2, 3, {A_SetObjectFlags},         MF_NOGRAVITY,          1, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP2
-	{SPR_FL16, 3, 3, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP3
-	{SPR_FL16, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_16_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_16, 384*FRACUNIT, S_FLICKY_16_CENTER},        // S_FLICKY_16_CENTER
+	{SPR_FL16, 0, 2, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_OUT, 0},   // S_FLICKY_16_OUT
+	{SPR_FL16, 1, 3, {A_FlickyFly},                4*FRACUNIT, 8*FRACUNIT, S_FLICKY_16_FLAP2, 0}, // S_FLICKY_16_FLAP1
+	{SPR_FL16, 2, 3, {A_SetObjectFlags},         MF_NOGRAVITY,          1, S_FLICKY_16_FLAP3, 0}, // S_FLICKY_16_FLAP2
+	{SPR_FL16, 3, 3, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_FLAP3, 0}, // S_FLICKY_16_FLAP3
+	{SPR_FL16, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL, 0}, // S_FLICKY_16_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_16, 384*FRACUNIT, S_FLICKY_16_CENTER, 0},        // S_FLICKY_16_CENTER
 
 	// Spider
-	{SPR_FS01, 0, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_OUT},  // S_SECRETFLICKY_01_OUT
-	{SPR_FS01, 1, 1, {A_FlickyAim},                   ANG30,            32*FRACUNIT, S_SECRETFLICKY_01_HOP},  // S_SECRETFLICKY_01_AIM
-	{SPR_FS01, 1, 1, {A_FlickyFlounder},         2*FRACUNIT,             6*FRACUNIT, S_SECRETFLICKY_01_UP},   // S_SECRETFLICKY_01_HOP
-	{SPR_FS01, 2, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, S_SECRETFLICKY_01_DOWN, S_SECRETFLICKY_01_UP},   // S_SECRETFLICKY_01_UP
-	{SPR_FS01, 3, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_DOWN}, // S_SECRETFLICKY_01_DOWN
-	{SPR_FS01, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_SECRETFLICKY_01_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_01, 384*FRACUNIT, S_SECRETFLICKY_01_CENTER},        // S_SECRETFLICKY_01_CENTER
+	{SPR_FS01, 0, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_OUT, 0},  // S_SECRETFLICKY_01_OUT
+	{SPR_FS01, 1, 1, {A_FlickyAim},                   ANG30,            32*FRACUNIT, S_SECRETFLICKY_01_HOP, 0},  // S_SECRETFLICKY_01_AIM
+	{SPR_FS01, 1, 1, {A_FlickyFlounder},         2*FRACUNIT,             6*FRACUNIT, S_SECRETFLICKY_01_UP, 0},   // S_SECRETFLICKY_01_HOP
+	{SPR_FS01, 2, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, S_SECRETFLICKY_01_DOWN, S_SECRETFLICKY_01_UP, 0},   // S_SECRETFLICKY_01_UP
+	{SPR_FS01, 3, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_DOWN, 0}, // S_SECRETFLICKY_01_DOWN
+	{SPR_FS01, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_SECRETFLICKY_01_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_01, 384*FRACUNIT, S_SECRETFLICKY_01_CENTER, 0},        // S_SECRETFLICKY_01_CENTER
 
 	// Bat
-	{SPR_FS02, 0, 2, {A_FlickyHeightCheck}, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_OUT},   // S_SECRETFLICKY_02_OUT
-	{SPR_FS02, 1, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP2}, // S_SECRETFLICKY_02_FLAP1
-	{SPR_FS02, 2, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP3}, // S_SECRETFLICKY_02_FLAP2
-	{SPR_FS02, 3, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP1}, // S_SECRETFLICKY_02_FLAP3
-	{SPR_FS02, FF_ANIMATE|1, -1, {NULL}, 2, 2, S_NULL}, // S_SECRETFLICKY_02_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_02, 384*FRACUNIT, S_SECRETFLICKY_02_CENTER},        // S_SECRETFLICKY_02_CENTER
+	{SPR_FS02, 0, 2, {A_FlickyHeightCheck}, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_OUT, 0},   // S_SECRETFLICKY_02_OUT
+	{SPR_FS02, 1, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP2, 0}, // S_SECRETFLICKY_02_FLAP1
+	{SPR_FS02, 2, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP3, 0}, // S_SECRETFLICKY_02_FLAP2
+	{SPR_FS02, 3, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP1, 0}, // S_SECRETFLICKY_02_FLAP3
+	{SPR_FS02, FF_ANIMATE|1, -1, {NULL}, 2, 2, S_NULL, 0}, // S_SECRETFLICKY_02_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_02, 384*FRACUNIT, S_SECRETFLICKY_02_CENTER, 0},        // S_SECRETFLICKY_02_CENTER
 
 	// Fan
-	{SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2}, // S_FAN
-	{SPR_FANS, 1, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN3}, // S_FAN2
-	{SPR_FANS, 2, 1, {A_FanBubbleSpawn},  512, 0, S_FAN4}, // S_FAN3
-	{SPR_FANS, 3, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN5}, // S_FAN4
-	{SPR_FANS, 4, 1, {A_FanBubbleSpawn},  512, 0, S_FAN},  // S_FAN5
+	{SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2, 0}, // S_FAN
+	{SPR_FANS, 1, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN3, 0}, // S_FAN2
+	{SPR_FANS, 2, 1, {A_FanBubbleSpawn},  512, 0, S_FAN4, 0}, // S_FAN3
+	{SPR_FANS, 3, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN5, 0}, // S_FAN4
+	{SPR_FANS, 4, 1, {A_FanBubbleSpawn},  512, 0, S_FAN, 0},  // S_FAN5
 
 	// Steam Riser
-	{SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2},   // S_STEAM1
-	{SPR_STEM, 1, 2, {A_UnsetSolidSteam}, 0, 0, S_STEAM3}, // S_STEAM2
-	{SPR_STEM, 2, 2, {NULL}, 0, 0, S_STEAM4},              // S_STEAM3
-	{SPR_STEM, 3, 2, {NULL}, 0, 0, S_STEAM5},              // S_STEAM4
-	{SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6},              // S_STEAM5
-	{SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7},              // S_STEAM6
-	{SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8},              // S_STEAM7
-	{SPR_NULL, 0, 18, {NULL}, 0, 0, S_STEAM1},             // S_STEAM8
+	{SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2, 0},   // S_STEAM1
+	{SPR_STEM, 1, 2, {A_UnsetSolidSteam}, 0, 0, S_STEAM3, 0}, // S_STEAM2
+	{SPR_STEM, 2, 2, {NULL}, 0, 0, S_STEAM4, 0},              // S_STEAM3
+	{SPR_STEM, 3, 2, {NULL}, 0, 0, S_STEAM5, 0},              // S_STEAM4
+	{SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6, 0},              // S_STEAM5
+	{SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7, 0},              // S_STEAM6
+	{SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8, 0},              // S_STEAM7
+	{SPR_NULL, 0, 18, {NULL}, 0, 0, S_STEAM1, 0},             // S_STEAM8
 
 	// Bumpers
-	{SPR_BUMP, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL},   3, 4, S_NULL},   // S_BUMPER
-	{SPR_BUMP, FF_ANIMATE|4,             12, {A_Pain}, 1, 3, S_BUMPER}, //S_BUMPERHIT
+	{SPR_BUMP, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL},   3, 4, S_NULL, 0},   // S_BUMPER
+	{SPR_BUMP, FF_ANIMATE|4,             12, {A_Pain}, 1, 3, S_BUMPER, 0}, //S_BUMPERHIT
 
 	// Balloons
-	{SPR_BLON, FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_BALLOON
-	{SPR_BLON, 3, 0, {A_RemoteDamage},   0, 1, S_BALLOONPOP2}, // S_BALLOONPOP1
-	{SPR_BLON, 3, 1, {A_Pain},           0, 0, S_BALLOONPOP3}, // S_BALLOONPOP2
-	{SPR_BLON, 4, 1, {NULL},             0, 0, S_BALLOONPOP4}, // S_BALLOONPOP3
-	{SPR_NULL, 0, TICRATE, {A_CheckFlags2}, MF2_AMBUSH, S_BALLOONPOP5, S_NULL}, // S_BALLOONPOP4
-	{SPR_NULL, 0, 15*TICRATE, {NULL},    0, 0, S_BALLOONPOP6}, // S_BALLOONPOP5
-	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_NULL},        // S_BALLOONPOP6
+	{SPR_BLON, FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL, 0}, // S_BALLOON
+	{SPR_BLON, 3, 0, {A_RemoteDamage},   0, 1, S_BALLOONPOP2, 0}, // S_BALLOONPOP1
+	{SPR_BLON, 3, 1, {A_Pain},           0, 0, S_BALLOONPOP3, 0}, // S_BALLOONPOP2
+	{SPR_BLON, 4, 1, {NULL},             0, 0, S_BALLOONPOP4, 0}, // S_BALLOONPOP3
+	{SPR_NULL, 0, TICRATE, {A_CheckFlags2}, MF2_AMBUSH, S_BALLOONPOP5, S_NULL, 0}, // S_BALLOONPOP4
+	{SPR_NULL, 0, 15*TICRATE, {NULL},    0, 0, S_BALLOONPOP6, 0}, // S_BALLOONPOP5
+	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_NULL, 0},        // S_BALLOONPOP6
 
 	// Yellow Spring
-	{SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL},           // S_YELLOWSPRING
-	{SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3}, // S_YELLOWSPRING2
-	{SPR_SPRY, 3, 1, {NULL}, 0, 0, S_YELLOWSPRING4},   // S_YELLOWSPRING3
-	{SPR_SPRY, 2, 1, {NULL}, 0, 0, S_YELLOWSPRING5},   // S_YELLOWSPRING4
-	{SPR_SPRY, 1, 1, {NULL}, 0, 0, S_YELLOWSPRING},    // S_YELLOWSPRING5
+	{SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL, 0},           // S_YELLOWSPRING
+	{SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3, 0}, // S_YELLOWSPRING2
+	{SPR_SPRY, 3, 1, {NULL}, 0, 0, S_YELLOWSPRING4, 0},   // S_YELLOWSPRING3
+	{SPR_SPRY, 2, 1, {NULL}, 0, 0, S_YELLOWSPRING5, 0},   // S_YELLOWSPRING4
+	{SPR_SPRY, 1, 1, {NULL}, 0, 0, S_YELLOWSPRING, 0},    // S_YELLOWSPRING5
 
 	// Red Spring
-	{SPR_SPRR, 0, -1, {NULL}, 0, 0, S_NULL},        // S_REDSPRING
-	{SPR_SPRR, 4, 4, {A_Pain}, 0, 0, S_REDSPRING3}, // S_REDSPRING2
-	{SPR_SPRR, 3, 1, {NULL}, 0, 0, S_REDSPRING4},   // S_REDSPRING3
-	{SPR_SPRR, 2, 1, {NULL}, 0, 0, S_REDSPRING5},   // S_REDSPRING4
-	{SPR_SPRR, 1, 1, {NULL}, 0, 0, S_REDSPRING},    // S_REDSPRING5
+	{SPR_SPRR, 0, -1, {NULL}, 0, 0, S_NULL, 0},        // S_REDSPRING
+	{SPR_SPRR, 4, 4, {A_Pain}, 0, 0, S_REDSPRING3, 0}, // S_REDSPRING2
+	{SPR_SPRR, 3, 1, {NULL}, 0, 0, S_REDSPRING4, 0},   // S_REDSPRING3
+	{SPR_SPRR, 2, 1, {NULL}, 0, 0, S_REDSPRING5, 0},   // S_REDSPRING4
+	{SPR_SPRR, 1, 1, {NULL}, 0, 0, S_REDSPRING, 0},    // S_REDSPRING5
 
 	// Blue Spring
-	{SPR_SPRB, 0, -1, {NULL}, 0, 0, S_NULL},         // S_BLUESPRING
-	{SPR_SPRB, 4, 4, {A_Pain}, 0, 0, S_BLUESPRING3}, // S_BLUESPRING2
-	{SPR_SPRB, 3, 1, {NULL}, 0, 0, S_BLUESPRING4},   // S_BLUESPRING3
-	{SPR_SPRB, 2, 1, {NULL}, 0, 0, S_BLUESPRING5},   // S_BLUESPRING4
-	{SPR_SPRB, 1, 1, {NULL}, 0, 0, S_BLUESPRING},    // S_BLUESPRING5
+	{SPR_SPRB, 0, -1, {NULL}, 0, 0, S_NULL, 0},         // S_BLUESPRING
+	{SPR_SPRB, 4, 4, {A_Pain}, 0, 0, S_BLUESPRING3, 0}, // S_BLUESPRING2
+	{SPR_SPRB, 3, 1, {NULL}, 0, 0, S_BLUESPRING4, 0},   // S_BLUESPRING3
+	{SPR_SPRB, 2, 1, {NULL}, 0, 0, S_BLUESPRING5, 0},   // S_BLUESPRING4
+	{SPR_SPRB, 1, 1, {NULL}, 0, 0, S_BLUESPRING, 0},    // S_BLUESPRING5
 
 	// Yellow Diagonal Spring
-	{SPR_YSPR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_YDIAG1
-	{SPR_YSPR, 1, 1, {A_Pain}, 0, 0, S_YDIAG3}, // S_YDIAG2
-	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG4},   // S_YDIAG3
-	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG5},   // S_YDIAG4
-	{SPR_YSPR, 4, 1, {NULL}, 0, 0, S_YDIAG6},   // S_YDIAG5
-	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG7},   // S_YDIAG6
-	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG8},   // S_YDIAG7
-	{SPR_YSPR, 1, 1, {NULL}, 0, 0, S_YDIAG1},   // S_YDIAG8
+	{SPR_YSPR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_YDIAG1
+	{SPR_YSPR, 1, 1, {A_Pain}, 0, 0, S_YDIAG3, 0}, // S_YDIAG2
+	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG4, 0},   // S_YDIAG3
+	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG5, 0},   // S_YDIAG4
+	{SPR_YSPR, 4, 1, {NULL}, 0, 0, S_YDIAG6, 0},   // S_YDIAG5
+	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG7, 0},   // S_YDIAG6
+	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG8, 0},   // S_YDIAG7
+	{SPR_YSPR, 1, 1, {NULL}, 0, 0, S_YDIAG1, 0},   // S_YDIAG8
 
 	// Red Diagonal Spring
-	{SPR_RSPR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_RDIAG1
-	{SPR_RSPR, 1, 1, {A_Pain}, 0, 0, S_RDIAG3}, // S_RDIAG2
-	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG4},   // S_RDIAG3
-	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG5},   // S_RDIAG4
-	{SPR_RSPR, 4, 1, {NULL}, 0, 0, S_RDIAG6},   // S_RDIAG5
-	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG7},   // S_RDIAG6
-	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG8},   // S_RDIAG7
-	{SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1},   // S_RDIAG8
+	{SPR_RSPR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_RDIAG1
+	{SPR_RSPR, 1, 1, {A_Pain}, 0, 0, S_RDIAG3, 0}, // S_RDIAG2
+	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG4, 0},   // S_RDIAG3
+	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG5, 0},   // S_RDIAG4
+	{SPR_RSPR, 4, 1, {NULL}, 0, 0, S_RDIAG6, 0},   // S_RDIAG5
+	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG7, 0},   // S_RDIAG6
+	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG8, 0},   // S_RDIAG7
+	{SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1, 0},   // S_RDIAG8
 
 	// Blue Diagonal Spring
-	{SPR_BSPR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_BDIAG1
-	{SPR_BSPR, 1, 1, {A_Pain}, 0, 0, S_BDIAG3}, // S_BDIAG2
-	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG4},   // S_BDIAG3
-	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG5},   // S_BDIAG4
-	{SPR_BSPR, 4, 1, {NULL}, 0, 0, S_BDIAG6},   // S_BDIAG5
-	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG7},   // S_BDIAG6
-	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG8},   // S_BDIAG7
-	{SPR_BSPR, 1, 1, {NULL}, 0, 0, S_BDIAG1},   // S_BDIAG8
+	{SPR_BSPR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_BDIAG1
+	{SPR_BSPR, 1, 1, {A_Pain}, 0, 0, S_BDIAG3, 0}, // S_BDIAG2
+	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG4, 0},   // S_BDIAG3
+	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG5, 0},   // S_BDIAG4
+	{SPR_BSPR, 4, 1, {NULL}, 0, 0, S_BDIAG6, 0},   // S_BDIAG5
+	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG7, 0},   // S_BDIAG6
+	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG8, 0},   // S_BDIAG7
+	{SPR_BSPR, 1, 1, {NULL}, 0, 0, S_BDIAG1, 0},   // S_BDIAG8
 
 	// Yellow Side Spring
-	{SPR_SSWY, 0, -1, {NULL}, 0, 0, S_NULL},    // S_YHORIZ1
-	{SPR_SSWY, 1, 1, {A_Pain}, 0, 0, S_YHORIZ3}, // S_YHORIZ2
-	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ4},   // S_YHORIZ3
-	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ5},   // S_YHORIZ4
-	{SPR_SSWY, 4, 1, {NULL}, 0, 0, S_YHORIZ6},   // S_YHORIZ5
-	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ7},   // S_YHORIZ6
-	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ8},   // S_YHORIZ7
-	{SPR_SSWY, 1, 1, {NULL}, 0, 0, S_YHORIZ1},   // S_YHORIZ8
+	{SPR_SSWY, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_YHORIZ1
+	{SPR_SSWY, 1, 1, {A_Pain}, 0, 0, S_YHORIZ3, 0}, // S_YHORIZ2
+	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ4, 0},   // S_YHORIZ3
+	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ5, 0},   // S_YHORIZ4
+	{SPR_SSWY, 4, 1, {NULL}, 0, 0, S_YHORIZ6, 0},   // S_YHORIZ5
+	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ7, 0},   // S_YHORIZ6
+	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ8, 0},   // S_YHORIZ7
+	{SPR_SSWY, 1, 1, {NULL}, 0, 0, S_YHORIZ1, 0},   // S_YHORIZ8
 
 	// Red Side Spring
-	{SPR_SSWR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_RHORIZ1
-	{SPR_SSWR, 1, 1, {A_Pain}, 0, 0, S_RHORIZ3}, // S_RHORIZ2
-	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ4},   // S_RHORIZ3
-	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ5},   // S_RHORIZ4
-	{SPR_SSWR, 4, 1, {NULL}, 0, 0, S_RHORIZ6},   // S_RHORIZ5
-	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ7},   // S_RHORIZ6
-	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ8},   // S_RHORIZ7
-	{SPR_SSWR, 1, 1, {NULL}, 0, 0, S_RHORIZ1},   // S_RHORIZ8
+	{SPR_SSWR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_RHORIZ1
+	{SPR_SSWR, 1, 1, {A_Pain}, 0, 0, S_RHORIZ3, 0}, // S_RHORIZ2
+	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ4, 0},   // S_RHORIZ3
+	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ5, 0},   // S_RHORIZ4
+	{SPR_SSWR, 4, 1, {NULL}, 0, 0, S_RHORIZ6, 0},   // S_RHORIZ5
+	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ7, 0},   // S_RHORIZ6
+	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ8, 0},   // S_RHORIZ7
+	{SPR_SSWR, 1, 1, {NULL}, 0, 0, S_RHORIZ1, 0},   // S_RHORIZ8
 
 	// Blue Side Spring
-	{SPR_SSWB, 0, -1, {NULL}, 0, 0, S_NULL},    // S_BHORIZ1
-	{SPR_SSWB, 1, 1, {A_Pain}, 0, 0, S_BHORIZ3}, // S_BHORIZ2
-	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ4},   // S_BHORIZ3
-	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ5},   // S_BHORIZ4
-	{SPR_SSWB, 4, 1, {NULL}, 0, 0, S_BHORIZ6},   // S_BHORIZ5
-	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ7},   // S_BHORIZ6
-	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ8},   // S_BHORIZ7
-	{SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1},   // S_BHORIZ8
+	{SPR_SSWB, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_BHORIZ1
+	{SPR_SSWB, 1, 1, {A_Pain}, 0, 0, S_BHORIZ3, 0}, // S_BHORIZ2
+	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ4, 0},   // S_BHORIZ3
+	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ5, 0},   // S_BHORIZ4
+	{SPR_SSWB, 4, 1, {NULL}, 0, 0, S_BHORIZ6, 0},   // S_BHORIZ5
+	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ7, 0},   // S_BHORIZ6
+	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ8, 0},   // S_BHORIZ7
+	{SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1, 0},   // S_BHORIZ8
 
 	// Boosters
-	{SPR_NULL, 0, 1, {A_Pain}, 0, 0, S_INVISIBLE}, // S_BOOSTERSOUND
-	{SPR_BSTY,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_YELLOWBOOSTERROLLER
-	{SPR_BSTY, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_YELLOWBOOSTERSEG_LEFT
-	{SPR_BSTY, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_YELLOWBOOSTERSEG_RIGHT
-	{SPR_BSTY, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWBOOSTERSEG_FACE
-	{SPR_BSTR,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_REDBOOSTERROLLER
-	{SPR_BSTR, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_REDBOOSTERSEG_LEFT
-	{SPR_BSTR, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_REDBOOSTERSEG_RIGHT
-	{SPR_BSTR, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL}, // S_REDBOOSTERSEG_FACE
+	{SPR_NULL, 0, 1, {A_Pain}, 0, 0, S_INVISIBLE, 0}, // S_BOOSTERSOUND
+	{SPR_BSTY,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_YELLOWBOOSTERROLLER
+	{SPR_BSTY, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_YELLOWBOOSTERSEG_LEFT
+	{SPR_BSTY, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_YELLOWBOOSTERSEG_RIGHT
+	{SPR_BSTY, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL, 0}, // S_YELLOWBOOSTERSEG_FACE
+	{SPR_BSTR,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_REDBOOSTERROLLER
+	{SPR_BSTR, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_REDBOOSTERSEG_LEFT
+	{SPR_BSTR, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_REDBOOSTERSEG_RIGHT
+	{SPR_BSTR, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL, 0}, // S_REDBOOSTERSEG_FACE
 
 	// Rain
-	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
-	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
+	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL, 0}, // S_RAIN1
+	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1, 0}, // S_RAINRETURN
 
 	// Snowflake
-	{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1
-	{SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW2
-	{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW3
+	{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOW1
+	{SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOW2
+	{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOW3
 
 	// Water Splish
-	{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
+	{SPR_SPLH, FF_TRANS50  , 2, {NULL}, 0, 0, S_SPLISH2, 0}, // S_SPLISH1
+	{SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3, 0}, // S_SPLISH2
+	{SPR_SPLH, FF_TRANS50|2, 2, {NULL}, 0, 0, S_SPLISH4, 0}, // S_SPLISH3
+	{SPR_SPLH, FF_TRANS50|3, 2, {NULL}, 0, 0, S_SPLISH5, 0}, // S_SPLISH4
+	{SPR_SPLH, FF_TRANS50|4, 2, {NULL}, 0, 0, S_SPLISH6, 0}, // S_SPLISH5
+	{SPR_SPLH, FF_TRANS50|5, 2, {NULL}, 0, 0, S_SPLISH7, 0}, // S_SPLISH6
+	{SPR_SPLH, FF_TRANS50|6, 2, {NULL}, 0, 0, S_SPLISH8, 0}, // S_SPLISH7
+	{SPR_SPLH, FF_TRANS50|7, 2, {NULL}, 0, 0, S_SPLISH9, 0}, // S_SPLISH8
+	{SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL, 0},    // S_SPLISH9
 
 	// Lava splish
-	{SPR_LSPL, FF_ANIMATE, 16, {NULL}, 7, 2, S_NULL}, // S_LAVASPLISH
+	{SPR_LSPL, FF_ANIMATE, 16, {NULL}, 7, 2, S_NULL, 0}, // S_LAVASPLISH
 
 	// Water Splash
-	{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
+	{SPR_SPLA, FF_TRANS50  , 3, {NULL}, 0, 0, S_SPLASH2, 0},    // S_SPLASH1
+	{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3, 0},    // S_SPLASH2
+	{SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN, 0}, // S_SPLASH3
 
 	// Smoke
-	{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
+	{SPR_SMOK, FF_TRANS50  , 4, {NULL}, 0, 0, S_SMOKE2, 0}, // S_SMOKE1
+	{SPR_SMOK, FF_TRANS50|1, 5, {NULL}, 0, 0, S_SMOKE3, 0}, // S_SMOKE2
+	{SPR_SMOK, FF_TRANS50|2, 6, {NULL}, 0, 0, S_SMOKE4, 0}, // S_SMOKE3
+	{SPR_SMOK, FF_TRANS50|3, 7, {NULL}, 0, 0, S_SMOKE5, 0}, // S_SMOKE4
+	{SPR_SMOK, FF_TRANS50|4, 8, {NULL}, 0, 0, S_NULL, 0},   // S_SMOKE5
 
 	// Bubbles
-	{SPR_BUBL, FF_TRANS50,   1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE},  // S_SMALLBUBBLE
-	{SPR_BUBL, FF_TRANS50|1, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE}, // S_MEDIUMBUBBLE
+	{SPR_BUBL, FF_TRANS50,   1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE, 0},  // S_SMALLBUBBLE
+	{SPR_BUBL, FF_TRANS50|1, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE, 0}, // S_MEDIUMBUBBLE
 
 	// Extra Large Bubble (breathable)
-	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|2,   8, {A_BubbleRise}, 0, 1024, S_LARGEBUBBLE2}, // S_LARGEBUBBLE1
-	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|3,   8, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_LARGEBUBBLE2
-	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|4,  16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_EXTRALARGEBUBBLE
+	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|2,   8, {A_BubbleRise}, 0, 1024, S_LARGEBUBBLE2, 0}, // S_LARGEBUBBLE1
+	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|3,   8, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE, 0}, // S_LARGEBUBBLE2
+	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|4,  16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE, 0}, // S_EXTRALARGEBUBBLE
 
 	// Extra Large Bubble goes POP!
-	{SPR_BUBL, 5, 16, {NULL}, 0, 0, S_NULL}, // S_POP1
+	{SPR_BUBL, 5, 16, {NULL}, 0, 0, S_NULL, 0}, // S_POP1
 
-	{SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL},  // S_WATERZAP
+	{SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL, 0},  // S_WATERZAP
 
 	// Spindash dust
-	{SPR_DUST,                          0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1
-	{SPR_DUST,                          1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2
-	{SPR_DUST,               FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3
-	{SPR_DUST,               FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4
-	{SPR_BUBL,                          0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1
-	{SPR_BUBL,                          0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2
-	{SPR_BUBL,               FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3
-	{SPR_BUBL,               FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4
-	{SPR_FPRT,            FF_FULLBRIGHT|0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1
-	{SPR_FPRT,            FF_FULLBRIGHT|0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2
-	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3
-	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4
-
-
-	{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
+	{SPR_DUST,                          0, 7, {NULL}, 0, 0, S_SPINDUST2, 0}, // S_SPINDUST1
+	{SPR_DUST,                          1, 6, {NULL}, 0, 0, S_SPINDUST3, 0}, // S_SPINDUST2
+	{SPR_DUST,               FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4, 0}, // S_SPINDUST3
+	{SPR_DUST,               FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL, 0}, // S_SPINDUST4
+	{SPR_BUBL,                          0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2, 0}, // S_SPINDUST_BUBBLE1
+	{SPR_BUBL,                          0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3, 0}, // S_SPINDUST_BUBBLE2
+	{SPR_BUBL,               FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4, 0}, // S_SPINDUST_BUBBLE3
+	{SPR_BUBL,               FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL, 0}, // S_SPINDUST_BUBBLE4
+	{SPR_FPRT,            FF_FULLBRIGHT|0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2, 0}, // S_SPINDUST_FIRE1
+	{SPR_FPRT,            FF_FULLBRIGHT|0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3, 0}, // S_SPINDUST_FIRE2
+	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4, 0}, // S_SPINDUST_FIRE3
+	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL, 0}, // S_SPINDUST_FIRE4
+
+
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50,    2, {NULL}, 0, 0, S_FOG2, 0},  // S_FOG1
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|1,  2, {NULL}, 0, 0, S_FOG3, 0},  // S_FOG2
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|2,  2, {NULL}, 0, 0, S_FOG4, 0},  // S_FOG3
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|3,  2, {NULL}, 0, 0, S_FOG5, 0},  // S_FOG4
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|4,  2, {NULL}, 0, 0, S_FOG6, 0},  // S_FOG5
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|5,  2, {NULL}, 0, 0, S_FOG7, 0},  // S_FOG6
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|6,  2, {NULL}, 0, 0, S_FOG8, 0},  // S_FOG7
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|7,  2, {NULL}, 0, 0, S_FOG9, 0},  // S_FOG8
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|8,  2, {NULL}, 0, 0, S_FOG10, 0}, // S_FOG9
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|9,  2, {NULL}, 0, 0, S_FOG11, 0}, // S_FOG10
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|10, 2, {NULL}, 0, 0, S_FOG12, 0}, // S_FOG11
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|11, 2, {NULL}, 0, 0, S_FOG13, 0}, // S_FOG12
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|12, 2, {NULL}, 0, 0, S_FOG14, 0}, // S_FOG13
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|13, 2, {NULL}, 0, 0, S_NULL, 0},  // S_FOG14
 
 	// Flower Seed
-	{SPR_SEED, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 2, 2, S_NULL}, // S_SEED
+	{SPR_SEED, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 2, 2, S_NULL, 0}, // S_SEED
 
 	// Particle sprite
-	{SPR_PRTL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE
-
-	{SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRA  - 100
-	{SPR_SCOR, 1, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRB  - 200
-	{SPR_SCOR, 2, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRC  - 500
-	{SPR_SCOR, 3, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRD  - 1000
-	{SPR_SCOR, 4, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRE  - 10000
-	{SPR_SCOR, 5, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRF  - 400 (mario mode)
-	{SPR_SCOR, 6, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRG  - 800 (mario mode)
-	{SPR_SCOR, 7, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRH  - 2000 (mario mode)
-	{SPR_SCOR, 8, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRI  - 4000 (mario mode)
-	{SPR_SCOR, 9, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRJ  - 8000 (mario mode)
-	{SPR_SCOR, 10, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRK - 1UP (mario mode)
-	{SPR_SCOR, 11, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRL - 10
+	{SPR_PRTL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL, 0}, // S_PARTICLE
+
+	{SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRA  - 100
+	{SPR_SCOR, 1, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRB  - 200
+	{SPR_SCOR, 2, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRC  - 500
+	{SPR_SCOR, 3, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRD  - 1000
+	{SPR_SCOR, 4, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRE  - 10000
+	{SPR_SCOR, 5, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRF  - 400 (mario mode)
+	{SPR_SCOR, 6, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRG  - 800 (mario mode)
+	{SPR_SCOR, 7, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRH  - 2000 (mario mode)
+	{SPR_SCOR, 8, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRI  - 4000 (mario mode)
+	{SPR_SCOR, 9, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRJ  - 8000 (mario mode)
+	{SPR_SCOR, 10, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRK - 1UP (mario mode)
+	{SPR_SCOR, 11, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRL - 10
 
 	// Drowning Timer Numbers
-	{SPR_DRWN, 0, 40, {NULL}, 0, 0, S_NULL}, // S_ZERO1
-	{SPR_DRWN, 1, 40, {NULL}, 0, 0, S_NULL}, // S_ONE1
-	{SPR_DRWN, 2, 40, {NULL}, 0, 0, S_NULL}, // S_TWO1
-	{SPR_DRWN, 3, 40, {NULL}, 0, 0, S_NULL}, // S_THREE1
-	{SPR_DRWN, 4, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR1
-	{SPR_DRWN, 5, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE1
-
-	{SPR_DRWN,  6, 40, {NULL}, 0, 0, S_NULL}, // S_ZERO2
-	{SPR_DRWN,  7, 40, {NULL}, 0, 0, S_NULL}, // S_ONE2
-	{SPR_DRWN,  8, 40, {NULL}, 0, 0, S_NULL}, // S_TWO2
-	{SPR_DRWN,  9, 40, {NULL}, 0, 0, S_NULL}, // S_THREE2
-	{SPR_DRWN, 10, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR2
-	{SPR_DRWN, 11, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE2
+	{SPR_DRWN, 0, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ZERO1
+	{SPR_DRWN, 1, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ONE1
+	{SPR_DRWN, 2, 40, {NULL}, 0, 0, S_NULL, 0}, // S_TWO1
+	{SPR_DRWN, 3, 40, {NULL}, 0, 0, S_NULL, 0}, // S_THREE1
+	{SPR_DRWN, 4, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FOUR1
+	{SPR_DRWN, 5, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FIVE1
+
+	{SPR_DRWN,  6, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ZERO2
+	{SPR_DRWN,  7, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ONE2
+	{SPR_DRWN,  8, 40, {NULL}, 0, 0, S_NULL, 0}, // S_TWO2
+	{SPR_DRWN,  9, 40, {NULL}, 0, 0, S_NULL, 0}, // S_THREE2
+	{SPR_DRWN, 10, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FOUR2
+	{SPR_DRWN, 11, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FIVE2
 
 	// Flight indicator
-	{SPR_FLII, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 4, S_NULL}, // S_FLIGHTINDICATOR
+	{SPR_FLII, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 4, S_NULL, 0}, // S_FLIGHTINDICATOR
 
-	{SPR_LCKN,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON1
-	{SPR_LCKN, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON2
-	{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON3
-	{SPR_LCKN, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON4
+	{SPR_LCKN,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON1
+	{SPR_LCKN, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON2
+	{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON3
+	{SPR_LCKN, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON4
 
-	{SPR_LCKN,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF1
-	{SPR_LCKN, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF2
-	{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF3
-	{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF4
+	{SPR_LCKN,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF1
+	{SPR_LCKN, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF2
+	{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF3
+	{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF4
 
-	{SPR_TTAG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_TTAG
+	{SPR_TTAG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL, 0}, // S_TTAG
 
 	// CTF Sign
-	{SPR_GFLG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
+	{SPR_GFLG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL, 0}, // S_GOTFLAG
 
 	// Finish flag
-	{SPR_FNSF,    FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_FINISHFLAG
+	{SPR_FNSF,    FF_TRANS30, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FINISHFLAG
 
-	{SPR_CORK,             0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
-	{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LHRT
+	{SPR_CORK,             0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORK
+	{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LHRT
 
 	// 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, {A_ThrownRing}, 0, 0, S_RRNG2, 0}, // S_RRNG1
+	{SPR_RRNG, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_RRNG3, 0}, // S_RRNG2
+	{SPR_RRNG, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_RRNG4, 0}, // S_RRNG3
+	{SPR_RRNG, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_RRNG5, 0}, // S_RRNG4
+	{SPR_RRNG, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_RRNG6, 0}, // S_RRNG5
+	{SPR_RRNG, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_RRNG7, 0}, // S_RRNG6
+	{SPR_RRNG, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_RRNG1, 0}, // S_RRNG7
 
 	// Weapon Ring Ammo
-	{SPR_RNGB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_BOUNCERINGAMMO},    // S_BOUNCERINGAMMO
-	{SPR_RNGR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_RAILRINGAMMO},      // S_RAILRINGAMMO
-	{SPR_RNGI, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_INFINITYRINGAMMO},  // S_INFINITYRINGAMMO
-	{SPR_RNGA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_AUTOMATICRINGAMMO}, // S_AUTOMATICRINGAMMO
-	{SPR_RNGE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_EXPLOSIONRINGAMMO}, // S_EXPLOSIONRINGAMMO
-	{SPR_RNGS, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_SCATTERRINGAMMO},   // S_SCATTERRINGAMMO
-	{SPR_RNGG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_GRENADERINGAMMO},   // S_GRENADERINGAMMO
+	{SPR_RNGB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_BOUNCERINGAMMO, 0},    // S_BOUNCERINGAMMO
+	{SPR_RNGR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_RAILRINGAMMO, 0},      // S_RAILRINGAMMO
+	{SPR_RNGI, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_INFINITYRINGAMMO, 0},  // S_INFINITYRINGAMMO
+	{SPR_RNGA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_AUTOMATICRINGAMMO, 0}, // S_AUTOMATICRINGAMMO
+	{SPR_RNGE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_EXPLOSIONRINGAMMO, 0}, // S_EXPLOSIONRINGAMMO
+	{SPR_RNGS, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_SCATTERRINGAMMO, 0},   // S_SCATTERRINGAMMO
+	{SPR_RNGG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_GRENADERINGAMMO, 0},   // S_GRENADERINGAMMO
 
 	// Bounce Ring Pickup
-	{SPR_PIKB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_BOUNCEPICKUP},  // S_BOUNCEPICKUP
+	{SPR_PIKB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_BOUNCEPICKUP, 0},  // S_BOUNCEPICKUP
 
-	{SPR_PIKB,  0, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE2}, // S_BOUNCEPICKUPFADE1
-	{SPR_PIKB,  2, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE3}, // S_BOUNCEPICKUPFADE2
-	{SPR_PIKB,  4, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE4}, // S_BOUNCEPICKUPFADE3
-	{SPR_PIKB,  6, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE5}, // S_BOUNCEPICKUPFADE4
-	{SPR_PIKB,  8, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE6}, // S_BOUNCEPICKUPFADE5
-	{SPR_PIKB, 10, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE7}, // S_BOUNCEPICKUPFADE6
-	{SPR_PIKB, 12, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE8}, // S_BOUNCEPICKUPFADE7
-	{SPR_PIKB, 14, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE1}, // S_BOUNCEPICKUPFADE8
+	{SPR_PIKB,  0, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE2, 0}, // S_BOUNCEPICKUPFADE1
+	{SPR_PIKB,  2, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE3, 0}, // S_BOUNCEPICKUPFADE2
+	{SPR_PIKB,  4, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE4, 0}, // S_BOUNCEPICKUPFADE3
+	{SPR_PIKB,  6, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE5, 0}, // S_BOUNCEPICKUPFADE4
+	{SPR_PIKB,  8, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE6, 0}, // S_BOUNCEPICKUPFADE5
+	{SPR_PIKB, 10, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE7, 0}, // S_BOUNCEPICKUPFADE6
+	{SPR_PIKB, 12, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE8, 0}, // S_BOUNCEPICKUPFADE7
+	{SPR_PIKB, 14, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE1, 0}, // S_BOUNCEPICKUPFADE8
 
 	// Rail Ring Pickup
-	{SPR_PIKR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_RAILPICKUP},  // S_RAILPICKUP
+	{SPR_PIKR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_RAILPICKUP, 0},  // S_RAILPICKUP
 
-	{SPR_PIKR,  0, 1, {NULL}, 0, 0, S_RAILPICKUPFADE2}, // S_RAILPICKUPFADE1
-	{SPR_PIKR,  2, 1, {NULL}, 0, 0, S_RAILPICKUPFADE3}, // S_RAILPICKUPFADE2
-	{SPR_PIKR,  4, 1, {NULL}, 0, 0, S_RAILPICKUPFADE4}, // S_RAILPICKUPFADE3
-	{SPR_PIKR,  6, 1, {NULL}, 0, 0, S_RAILPICKUPFADE5}, // S_RAILPICKUPFADE4
-	{SPR_PIKR,  8, 1, {NULL}, 0, 0, S_RAILPICKUPFADE6}, // S_RAILPICKUPFADE5
-	{SPR_PIKR, 10, 1, {NULL}, 0, 0, S_RAILPICKUPFADE7}, // S_RAILPICKUPFADE6
-	{SPR_PIKR, 12, 1, {NULL}, 0, 0, S_RAILPICKUPFADE8}, // S_RAILPICKUPFADE7
-	{SPR_PIKR, 14, 1, {NULL}, 0, 0, S_RAILPICKUPFADE1}, // S_RAILPICKUPFADE8
+	{SPR_PIKR,  0, 1, {NULL}, 0, 0, S_RAILPICKUPFADE2, 0}, // S_RAILPICKUPFADE1
+	{SPR_PIKR,  2, 1, {NULL}, 0, 0, S_RAILPICKUPFADE3, 0}, // S_RAILPICKUPFADE2
+	{SPR_PIKR,  4, 1, {NULL}, 0, 0, S_RAILPICKUPFADE4, 0}, // S_RAILPICKUPFADE3
+	{SPR_PIKR,  6, 1, {NULL}, 0, 0, S_RAILPICKUPFADE5, 0}, // S_RAILPICKUPFADE4
+	{SPR_PIKR,  8, 1, {NULL}, 0, 0, S_RAILPICKUPFADE6, 0}, // S_RAILPICKUPFADE5
+	{SPR_PIKR, 10, 1, {NULL}, 0, 0, S_RAILPICKUPFADE7, 0}, // S_RAILPICKUPFADE6
+	{SPR_PIKR, 12, 1, {NULL}, 0, 0, S_RAILPICKUPFADE8, 0}, // S_RAILPICKUPFADE7
+	{SPR_PIKR, 14, 1, {NULL}, 0, 0, S_RAILPICKUPFADE1, 0}, // S_RAILPICKUPFADE8
 
 	// Auto Ring Pickup
-	{SPR_PIKA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_AUTOPICKUP},  // S_AUTOPICKUP
+	{SPR_PIKA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_AUTOPICKUP, 0},  // S_AUTOPICKUP
 
-	{SPR_PIKA,  0, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE2}, // S_AUTOPICKUPFADE1
-	{SPR_PIKA,  2, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE3}, // S_AUTOPICKUPFADE2
-	{SPR_PIKA,  4, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE4}, // S_AUTOPICKUPFADE3
-	{SPR_PIKA,  6, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE5}, // S_AUTOPICKUPFADE4
-	{SPR_PIKA,  8, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE6}, // S_AUTOPICKUPFADE5
-	{SPR_PIKA, 10, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE7}, // S_AUTOPICKUPFADE6
-	{SPR_PIKA, 12, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE8}, // S_AUTOPICKUPFADE7
-	{SPR_PIKA, 14, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE1}, // S_AUTOPICKUPFADE8
+	{SPR_PIKA,  0, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE2, 0}, // S_AUTOPICKUPFADE1
+	{SPR_PIKA,  2, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE3, 0}, // S_AUTOPICKUPFADE2
+	{SPR_PIKA,  4, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE4, 0}, // S_AUTOPICKUPFADE3
+	{SPR_PIKA,  6, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE5, 0}, // S_AUTOPICKUPFADE4
+	{SPR_PIKA,  8, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE6, 0}, // S_AUTOPICKUPFADE5
+	{SPR_PIKA, 10, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE7, 0}, // S_AUTOPICKUPFADE6
+	{SPR_PIKA, 12, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE8, 0}, // S_AUTOPICKUPFADE7
+	{SPR_PIKA, 14, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE1, 0}, // S_AUTOPICKUPFADE8
 
 	// Explode Ring Pickup
-	{SPR_PIKE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_EXPLODEPICKUP},  // S_EXPLODEPICKUP
+	{SPR_PIKE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_EXPLODEPICKUP, 0},  // S_EXPLODEPICKUP
 
-	{SPR_PIKE,  0, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE2}, // S_EXPLODEPICKUPFADE1
-	{SPR_PIKE,  2, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE3}, // S_EXPLODEPICKUPFADE2
-	{SPR_PIKE,  4, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE4}, // S_EXPLODEPICKUPFADE3
-	{SPR_PIKE,  6, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE5}, // S_EXPLODEPICKUPFADE4
-	{SPR_PIKE,  8, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE6}, // S_EXPLODEPICKUPFADE5
-	{SPR_PIKE, 10, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE7}, // S_EXPLODEPICKUPFADE6
-	{SPR_PIKE, 12, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE8}, // S_EXPLODEPICKUPFADE7
-	{SPR_PIKE, 14, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE1}, // S_EXPLODEPICKUPFADE8
+	{SPR_PIKE,  0, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE2, 0}, // S_EXPLODEPICKUPFADE1
+	{SPR_PIKE,  2, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE3, 0}, // S_EXPLODEPICKUPFADE2
+	{SPR_PIKE,  4, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE4, 0}, // S_EXPLODEPICKUPFADE3
+	{SPR_PIKE,  6, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE5, 0}, // S_EXPLODEPICKUPFADE4
+	{SPR_PIKE,  8, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE6, 0}, // S_EXPLODEPICKUPFADE5
+	{SPR_PIKE, 10, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE7, 0}, // S_EXPLODEPICKUPFADE6
+	{SPR_PIKE, 12, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE8, 0}, // S_EXPLODEPICKUPFADE7
+	{SPR_PIKE, 14, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE1, 0}, // S_EXPLODEPICKUPFADE8
 
 	// Scatter Ring Pickup
-	{SPR_PIKS,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_SCATTERPICKUP},  // S_SCATTERPICKUP
+	{SPR_PIKS,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_SCATTERPICKUP, 0},  // S_SCATTERPICKUP
 
-	{SPR_PIKS,  0, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE2}, // S_SCATTERPICKUPFADE1
-	{SPR_PIKS,  2, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE3}, // S_SCATTERPICKUPFADE2
-	{SPR_PIKS,  4, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE4}, // S_SCATTERPICKUPFADE3
-	{SPR_PIKS,  6, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE5}, // S_SCATTERPICKUPFADE4
-	{SPR_PIKS,  8, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE6}, // S_SCATTERPICKUPFADE5
-	{SPR_PIKS, 10, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE7}, // S_SCATTERPICKUPFADE6
-	{SPR_PIKS, 12, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE8}, // S_SCATTERPICKUPFADE7
-	{SPR_PIKS, 14, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE1}, // S_SCATTERPICKUPFADE8
+	{SPR_PIKS,  0, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE2, 0}, // S_SCATTERPICKUPFADE1
+	{SPR_PIKS,  2, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE3, 0}, // S_SCATTERPICKUPFADE2
+	{SPR_PIKS,  4, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE4, 0}, // S_SCATTERPICKUPFADE3
+	{SPR_PIKS,  6, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE5, 0}, // S_SCATTERPICKUPFADE4
+	{SPR_PIKS,  8, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE6, 0}, // S_SCATTERPICKUPFADE5
+	{SPR_PIKS, 10, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE7, 0}, // S_SCATTERPICKUPFADE6
+	{SPR_PIKS, 12, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE8, 0}, // S_SCATTERPICKUPFADE7
+	{SPR_PIKS, 14, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE1, 0}, // S_SCATTERPICKUPFADE8
 
 	// Grenade Ring Pickup
-	{SPR_PIKG,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_GRENADEPICKUP},  // S_GRENADEPICKUP
+	{SPR_PIKG,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_GRENADEPICKUP, 0},  // S_GRENADEPICKUP
 
-	{SPR_PIKG,  0, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE2}, // S_GRENADEPICKUPFADE1
-	{SPR_PIKG,  2, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE3}, // S_GRENADEPICKUPFADE2
-	{SPR_PIKG,  4, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE4}, // S_GRENADEPICKUPFADE3
-	{SPR_PIKG,  6, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE5}, // S_GRENADEPICKUPFADE4
-	{SPR_PIKG,  8, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE6}, // S_GRENADEPICKUPFADE5
-	{SPR_PIKG, 10, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE7}, // S_GRENADEPICKUPFADE6
-	{SPR_PIKG, 12, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE8}, // S_GRENADEPICKUPFADE7
-	{SPR_PIKG, 14, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE1}, // S_GRENADEPICKUPFADE8
+	{SPR_PIKG,  0, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE2, 0}, // S_GRENADEPICKUPFADE1
+	{SPR_PIKG,  2, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE3, 0}, // S_GRENADEPICKUPFADE2
+	{SPR_PIKG,  4, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE4, 0}, // S_GRENADEPICKUPFADE3
+	{SPR_PIKG,  6, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE5, 0}, // S_GRENADEPICKUPFADE4
+	{SPR_PIKG,  8, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE6, 0}, // S_GRENADEPICKUPFADE5
+	{SPR_PIKG, 10, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE7, 0}, // S_GRENADEPICKUPFADE6
+	{SPR_PIKG, 12, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE8, 0}, // S_GRENADEPICKUPFADE7
+	{SPR_PIKG, 14, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE1, 0}, // S_GRENADEPICKUPFADE8
 
 	// Thrown Weapon Rings
-	{SPR_RNGB, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE2}, // S_THROWNBOUNCE1
-	{SPR_RNGB, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE3}, // S_THROWNBOUNCE2
-	{SPR_RNGB, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE4}, // S_THROWNBOUNCE3
-	{SPR_RNGB, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE5}, // S_THROWNBOUNCE4
-	{SPR_RNGB, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE6}, // S_THROWNBOUNCE5
-	{SPR_RNGB, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE7}, // S_THROWNBOUNCE6
-	{SPR_RNGB, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE1}, // S_THROWNBOUNCE7
-
-	{SPR_RNGI, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY2}, // S_THROWNINFINITY1
-	{SPR_RNGI, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY3}, // S_THROWNINFINITY2
-	{SPR_RNGI, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY4}, // S_THROWNINFINITY3
-	{SPR_RNGI, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY5}, // S_THROWNINFINITY4
-	{SPR_RNGI, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY6}, // S_THROWNINFINITY5
-	{SPR_RNGI, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY7}, // S_THROWNINFINITY6
-	{SPR_RNGI, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY1}, // S_THROWNINFINITY7
-
-	{SPR_TAUT, FF_FULLBRIGHT  , 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC2}, // S_THROWNAUTOMATIC1
-	{SPR_TAUT, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC3}, // S_THROWNAUTOMATIC2
-	{SPR_TAUT, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC4}, // S_THROWNAUTOMATIC3
-	{SPR_TAUT, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC5}, // S_THROWNAUTOMATIC4
-	{SPR_TAUT, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC6}, // S_THROWNAUTOMATIC5
-	{SPR_TAUT, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC7}, // S_THROWNAUTOMATIC6
-	{SPR_TAUT, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC1}, // S_THROWNAUTOMATIC7
-
-	{SPR_RNGE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION2}, // S_THROWNEXPLOSION1
-	{SPR_RNGE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION3}, // S_THROWNEXPLOSION2
-	{SPR_RNGE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION4}, // S_THROWNEXPLOSION3
-	{SPR_RNGE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION5}, // S_THROWNEXPLOSION4
-	{SPR_RNGE, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION6}, // S_THROWNEXPLOSION5
-	{SPR_RNGE, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION7}, // S_THROWNEXPLOSION6
-	{SPR_RNGE, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION1}, // S_THROWNEXPLOSION7
-
-	{SPR_TGRE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE2},  // S_THROWNGRENADE1
-	{SPR_TGRE, FF_FULLBRIGHT| 1, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE3},  // S_THROWNGRENADE2
-	{SPR_TGRE, FF_FULLBRIGHT| 2, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE4},  // S_THROWNGRENADE3
-	{SPR_TGRE, FF_FULLBRIGHT| 3, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE5},  // S_THROWNGRENADE4
-	{SPR_TGRE, FF_FULLBRIGHT| 4, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE6},  // S_THROWNGRENADE5
-	{SPR_TGRE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE7},  // S_THROWNGRENADE6
-	{SPR_TGRE, FF_FULLBRIGHT| 6, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE8},  // S_THROWNGRENADE7
-	{SPR_TGRE, FF_FULLBRIGHT| 7, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE9},  // S_THROWNGRENADE8
-	{SPR_TGRE, FF_FULLBRIGHT| 8, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE10}, // S_THROWNGRENADE9
-	{SPR_TGRE, FF_FULLBRIGHT| 9, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE11}, // S_THROWNGRENADE10
-	{SPR_TGRE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE12}, // S_THROWNGRENADE11
-	{SPR_TGRE, FF_FULLBRIGHT|11, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE13}, // S_THROWNGRENADE12
-	{SPR_TGRE, FF_FULLBRIGHT|12, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE14}, // S_THROWNGRENADE13
-	{SPR_TGRE, FF_FULLBRIGHT|13, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE15}, // S_THROWNGRENADE14
-	{SPR_TGRE, FF_FULLBRIGHT|14, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE16}, // S_THROWNGRENADE15
-	{SPR_TGRE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE17}, // S_THROWNGRENADE16
-	{SPR_TGRE, FF_FULLBRIGHT|16, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE18}, // S_THROWNGRENADE17
-	{SPR_TGRE, FF_FULLBRIGHT|17, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE1},  // S_THROWNGRENADE18
-
-	{SPR_TSCR, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_THROWNSCATTER}, // S_THROWNSCATTER
-
-	{SPR_NULL, 0, 1, {A_RingExplode}, 0, 0, S_XPLD1}, // S_RINGEXPLODE
+	{SPR_RNGB, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE2, 0}, // S_THROWNBOUNCE1
+	{SPR_RNGB, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE3, 0}, // S_THROWNBOUNCE2
+	{SPR_RNGB, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE4, 0}, // S_THROWNBOUNCE3
+	{SPR_RNGB, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE5, 0}, // S_THROWNBOUNCE4
+	{SPR_RNGB, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE6, 0}, // S_THROWNBOUNCE5
+	{SPR_RNGB, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE7, 0}, // S_THROWNBOUNCE6
+	{SPR_RNGB, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE1, 0}, // S_THROWNBOUNCE7
+
+	{SPR_RNGI, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY2, 0}, // S_THROWNINFINITY1
+	{SPR_RNGI, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY3, 0}, // S_THROWNINFINITY2
+	{SPR_RNGI, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY4, 0}, // S_THROWNINFINITY3
+	{SPR_RNGI, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY5, 0}, // S_THROWNINFINITY4
+	{SPR_RNGI, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY6, 0}, // S_THROWNINFINITY5
+	{SPR_RNGI, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY7, 0}, // S_THROWNINFINITY6
+	{SPR_RNGI, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY1, 0}, // S_THROWNINFINITY7
+
+	{SPR_TAUT, FF_FULLBRIGHT  , 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC2, 0}, // S_THROWNAUTOMATIC1
+	{SPR_TAUT, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC3, 0}, // S_THROWNAUTOMATIC2
+	{SPR_TAUT, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC4, 0}, // S_THROWNAUTOMATIC3
+	{SPR_TAUT, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC5, 0}, // S_THROWNAUTOMATIC4
+	{SPR_TAUT, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC6, 0}, // S_THROWNAUTOMATIC5
+	{SPR_TAUT, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC7, 0}, // S_THROWNAUTOMATIC6
+	{SPR_TAUT, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC1, 0}, // S_THROWNAUTOMATIC7
+
+	{SPR_RNGE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION2, 0}, // S_THROWNEXPLOSION1
+	{SPR_RNGE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION3, 0}, // S_THROWNEXPLOSION2
+	{SPR_RNGE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION4, 0}, // S_THROWNEXPLOSION3
+	{SPR_RNGE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION5, 0}, // S_THROWNEXPLOSION4
+	{SPR_RNGE, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION6, 0}, // S_THROWNEXPLOSION5
+	{SPR_RNGE, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION7, 0}, // S_THROWNEXPLOSION6
+	{SPR_RNGE, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION1, 0}, // S_THROWNEXPLOSION7
+
+	{SPR_TGRE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE2, 0},  // S_THROWNGRENADE1
+	{SPR_TGRE, FF_FULLBRIGHT| 1, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE3, 0},  // S_THROWNGRENADE2
+	{SPR_TGRE, FF_FULLBRIGHT| 2, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE4, 0},  // S_THROWNGRENADE3
+	{SPR_TGRE, FF_FULLBRIGHT| 3, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE5, 0},  // S_THROWNGRENADE4
+	{SPR_TGRE, FF_FULLBRIGHT| 4, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE6, 0},  // S_THROWNGRENADE5
+	{SPR_TGRE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE7, 0},  // S_THROWNGRENADE6
+	{SPR_TGRE, FF_FULLBRIGHT| 6, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE8, 0},  // S_THROWNGRENADE7
+	{SPR_TGRE, FF_FULLBRIGHT| 7, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE9, 0},  // S_THROWNGRENADE8
+	{SPR_TGRE, FF_FULLBRIGHT| 8, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE10, 0}, // S_THROWNGRENADE9
+	{SPR_TGRE, FF_FULLBRIGHT| 9, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE11, 0}, // S_THROWNGRENADE10
+	{SPR_TGRE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE12, 0}, // S_THROWNGRENADE11
+	{SPR_TGRE, FF_FULLBRIGHT|11, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE13, 0}, // S_THROWNGRENADE12
+	{SPR_TGRE, FF_FULLBRIGHT|12, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE14, 0}, // S_THROWNGRENADE13
+	{SPR_TGRE, FF_FULLBRIGHT|13, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE15, 0}, // S_THROWNGRENADE14
+	{SPR_TGRE, FF_FULLBRIGHT|14, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE16, 0}, // S_THROWNGRENADE15
+	{SPR_TGRE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE17, 0}, // S_THROWNGRENADE16
+	{SPR_TGRE, FF_FULLBRIGHT|16, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE18, 0}, // S_THROWNGRENADE17
+	{SPR_TGRE, FF_FULLBRIGHT|17, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE1, 0},  // S_THROWNGRENADE18
+
+	{SPR_TSCR, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_THROWNSCATTER, 0}, // S_THROWNSCATTER
+
+	{SPR_NULL, 0, 1, {A_RingExplode}, 0, 0, S_XPLD1, 0}, // S_RINGEXPLODE
 
 	// 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,   5, {NULL}, 0, 0, S_COIN2, 0}, // S_COIN1
+	{SPR_COIN, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COIN3, 0}, // S_COIN2
+	{SPR_COIN, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COIN1, 0}, // 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,   5, {NULL}, 0, 0, S_COINSPARKLE2, 0}, // S_COINSPARKLE1
+	{SPR_CPRK, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COINSPARKLE3, 0}, // S_COINSPARKLE2
+	{SPR_CPRK, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COINSPARKLE4, 0}, // S_COINSPARKLE3
+	{SPR_CPRK, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL, 0},         // S_COINSPARKLE4
 
 	// Goomba
-	{SPR_GOOM, 0, 6, {A_Look}, 0, 0, S_GOOMBA1B}, // S_GOOMBA1
-	{SPR_GOOM, 1, 6, {A_Look}, 0, 0, S_GOOMBA1},  // S_GOOMBA1B
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA3}, // S_GOOMBA2
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA4}, // S_GOOMBA3
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA5}, // S_GOOMBA4
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA6}, // S_GOOMBA5
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA7}, // S_GOOMBA6
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA8}, // S_GOOMBA7
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA9}, // S_GOOMBA8
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA2}, // S_GOOMBA9
-	{SPR_GOOM, 2, 16, {A_Scream}, 0, 0, S_NULL},  // S_GOOMBA_DEAD
+	{SPR_GOOM, 0, 6, {A_Look}, 0, 0, S_GOOMBA1B, 0}, // S_GOOMBA1
+	{SPR_GOOM, 1, 6, {A_Look}, 0, 0, S_GOOMBA1, 0},  // S_GOOMBA1B
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA3, 0}, // S_GOOMBA2
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA4, 0}, // S_GOOMBA3
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA5, 0}, // S_GOOMBA4
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA6, 0}, // S_GOOMBA5
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA7, 0}, // S_GOOMBA6
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA8, 0}, // S_GOOMBA7
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA9, 0}, // S_GOOMBA8
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA2, 0}, // S_GOOMBA9
+	{SPR_GOOM, 2, 16, {A_Scream}, 0, 0, S_NULL, 0},  // S_GOOMBA_DEAD
 
 	// Blue Goomba
-	{SPR_BGOM, 0, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1B}, // BLUEGOOMBA1
-	{SPR_BGOM, 1, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1},  // BLUEGOOMBA1B
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA3}, // S_BLUEGOOMBA2
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA4}, // S_BLUEGOOMBA3
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA5}, // S_BLUEGOOMBA4
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA6}, // S_BLUEGOOMBA5
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA7}, // S_BLUEGOOMBA6
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA8}, // S_BLUEGOOMBA7
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA9}, // S_BLUEGOOMBA8
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA2}, // S_BLUEGOOMBA9
-	{SPR_BGOM, 2, 16, {A_Scream}, 0, 0, S_NULL},      // S_BLUEGOOMBA_DEAD
+	{SPR_BGOM, 0, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1B, 0}, // S_BLUEGOOMBA1
+	{SPR_BGOM, 1, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1, 0},  // S_BLUEGOOMBA1B
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA3, 0}, // S_BLUEGOOMBA2
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA4, 0}, // S_BLUEGOOMBA3
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA5, 0}, // S_BLUEGOOMBA4
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA6, 0}, // S_BLUEGOOMBA5
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA7, 0}, // S_BLUEGOOMBA6
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA8, 0}, // S_BLUEGOOMBA7
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA9, 0}, // S_BLUEGOOMBA8
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA2, 0}, // S_BLUEGOOMBA9
+	{SPR_BGOM, 2, 16, {A_Scream}, 0, 0, S_NULL, 0},      // S_BLUEGOOMBA_DEAD
 
 	// Fire Flower
-	{SPR_FFWR, 0, 3, {NULL}, 0, 0, S_FIREFLOWER2}, // S_FIREFLOWER1
-	{SPR_FFWR, 1, 3, {NULL}, 0, 0, S_FIREFLOWER3}, // S_FIREFLOWER2
-	{SPR_FFWR, 2, 3, {NULL}, 0, 0, S_FIREFLOWER4}, // S_FIREFLOWER3
-	{SPR_FFWR, 3, 3, {NULL}, 0, 0, S_FIREFLOWER1}, // S_FIREFLOWER4
+	{SPR_FFWR, 0, 3, {NULL}, 0, 0, S_FIREFLOWER2, 0}, // S_FIREFLOWER1
+	{SPR_FFWR, 1, 3, {NULL}, 0, 0, S_FIREFLOWER3, 0}, // S_FIREFLOWER2
+	{SPR_FFWR, 2, 3, {NULL}, 0, 0, S_FIREFLOWER4, 0}, // S_FIREFLOWER3
+	{SPR_FFWR, 3, 3, {NULL}, 0, 0, S_FIREFLOWER1, 0}, // S_FIREFLOWER4
 
 	// Thrown Mario Fireball
-	{SPR_FBLL, FF_FULLBRIGHT,   1, {A_SpawnObjectRelative}, 0, MT_FIREBALLTRAIL, S_FIREBALL},   // S_FIREBALL
-	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 1, {A_SetScale}, FRACUNIT*3/4, 0, S_FIREBALLTRAIL2}, // S_FIREBALLTRAIL1
-	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 8, {A_SetScale}, FRACUNIT/6, 1, S_NULL},             // S_FIREBALLTRAIL2
+	{SPR_FBLL, FF_FULLBRIGHT,   1, {A_SpawnObjectRelative}, 0, MT_FIREBALLTRAIL, S_FIREBALL, 0},   // S_FIREBALL
+	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 1, {A_SetScale}, FRACUNIT*3/4, 0, S_FIREBALLTRAIL2, 0}, // S_FIREBALLTRAIL1
+	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 8, {A_SetScale}, FRACUNIT/6, 1, S_NULL, 0},             // S_FIREBALLTRAIL2
 
 	// Turtle Shell
-	{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHELL
+	{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHELL
 
 	// Puma (Mario fireball)
-	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2},   // S_PUMA_START1
-	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1 + (1<<16), S_PUMA_UP1},   // S_PUMA_START2
-	{SPR_PUMA, FF_FULLBRIGHT  , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2},   // S_PUMA_UP1
-	{SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3},   // S_PUMA_UP2
-	{SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1},   // S_PUMA_UP3
-	{SPR_PUMA, FF_FULLBRIGHT|3, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN2}, // S_PUMA_DOWN1
-	{SPR_PUMA, FF_FULLBRIGHT|4, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN3}, // S_PUMA_DOWN2
-	{SPR_PUMA, FF_FULLBRIGHT|5, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN1}, // S_PUMA_DOWN3
-
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS20|6, 4,       {NULL},        0, 0, S_PUMATRAIL2},   // S_PUMATRAIL1
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS40|6, 5, {A_SetScale}, FRACUNIT, 1, S_PUMATRAIL3},   // S_PUMATRAIL2
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS50|7, 4,       {NULL},        0, 0, S_PUMATRAIL4},   // S_PUMATRAIL3
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS60|8, 3,       {NULL},        0, 0, S_NULL},         // S_PUMATRAIL4
+	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2, 0},   // S_PUMA_START1
+	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1 + (1<<16), S_PUMA_UP1, 0},   // S_PUMA_START2
+	{SPR_PUMA, FF_FULLBRIGHT  , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2, 0},   // S_PUMA_UP1
+	{SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3, 0},   // S_PUMA_UP2
+	{SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1, 0},   // S_PUMA_UP3
+	{SPR_PUMA, FF_FULLBRIGHT|3, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN2, 0}, // S_PUMA_DOWN1
+	{SPR_PUMA, FF_FULLBRIGHT|4, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN3, 0}, // S_PUMA_DOWN2
+	{SPR_PUMA, FF_FULLBRIGHT|5, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN1, 0}, // S_PUMA_DOWN3
+
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS20|6, 4,       {NULL},        0, 0, S_PUMATRAIL2, 0},   // S_PUMATRAIL1
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS40|6, 5, {A_SetScale}, FRACUNIT, 1, S_PUMATRAIL3, 0},   // S_PUMATRAIL2
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS50|7, 4,       {NULL},        0, 0, S_PUMATRAIL4, 0},   // S_PUMATRAIL3
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS60|8, 3,       {NULL},        0, 0, S_NULL, 0},         // S_PUMATRAIL4
 
 	// Hammer
-	{SPR_HAMM, FF_ANIMATE, -1, {NULL}, 3, 3, S_NULL}, // S_HAMMER
+	{SPR_HAMM, FF_ANIMATE, -1, {NULL}, 3, 3, S_NULL, 0}, // S_HAMMER
 
 	// Koopa
-	{SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL},   // S_KOOPA1
-	{SPR_KOOP, 1, 24, {NULL}, 0, 0, S_KOOPA1}, // S_KOOPA2
+	{SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL, 0},   // S_KOOPA1
+	{SPR_KOOP, 1, 24, {NULL}, 0, 0, S_KOOPA1, 0}, // S_KOOPA2
 
-	{SPR_BFLM, 0, 3,{NULL}, 0, 0, S_KOOPAFLAME2}, // S_KOOPAFLAME1
-	{SPR_BFLM, 1, 3,{NULL}, 0, 0, S_KOOPAFLAME3}, // S_KOOPAFLAME2
-	{SPR_BFLM, 2, 3,{NULL}, 0, 0, S_KOOPAFLAME1}, // S_KOOPAFLAME3
+	{SPR_BFLM, 0, 3,{NULL}, 0, 0, S_KOOPAFLAME2, 0}, // S_KOOPAFLAME1
+	{SPR_BFLM, 1, 3,{NULL}, 0, 0, S_KOOPAFLAME3, 0}, // S_KOOPAFLAME2
+	{SPR_BFLM, 2, 3,{NULL}, 0, 0, S_KOOPAFLAME1, 0}, // S_KOOPAFLAME3
 
 	// Axe
-	{SPR_MAXE, 0, 3, {NULL}, 0, 0, S_AXE2}, // S_AXE1
-	{SPR_MAXE, 1, 3, {NULL}, 0, 0, S_AXE3}, // S_AXE2
-	{SPR_MAXE, 2, 3, {NULL}, 0, 0, S_AXE1}, // S_AXE3
+	{SPR_MAXE, 0, 3, {NULL}, 0, 0, S_AXE2, 0}, // S_AXE1
+	{SPR_MAXE, 1, 3, {NULL}, 0, 0, S_AXE3, 0}, // S_AXE2
+	{SPR_MAXE, 2, 3, {NULL}, 0, 0, S_AXE1, 0}, // S_AXE3
 
-	{SPR_MUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MARIOBUSH1
-	{SPR_MUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MARIOBUSH2
-	{SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_TOAD
+	{SPR_MUS1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MARIOBUSH1
+	{SPR_MUS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MARIOBUSH2
+	{SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TOAD
 
 	// Nights Drone
-	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN2}, // S_NIGHTSDRONE_MAN1
-	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN1}, // S_NIGHTSDRONE_MAN2
+	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN2, 0}, // S_NIGHTSDRONE_MAN1
+	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN1, 0}, // S_NIGHTSDRONE_MAN2
 
 	// Sparkling point (RETURN TO THE GOAL, etc)
-	{SPR_IVSP, 0, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING2},   // S_NIGHTSDRONE_SPARKLING1
-	{SPR_IVSP, 2, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING3},   // S_NIGHTSDRONE_SPARKLING2
-	{SPR_IVSP, 4, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING4},   // S_NIGHTSDRONE_SPARKLING3
-	{SPR_IVSP, 6, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING5},   // S_NIGHTSDRONE_SPARKLING4
-	{SPR_IVSP, 8, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING6},  // S_NIGHTSDRONE_SPARKLING5
-	{SPR_IVSP, 10, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING7}, // S_NIGHTSDRONE_SPARKLING6
-	{SPR_IVSP, 12, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING8}, // S_NIGHTSDRONE_SPARKLING7
-	{SPR_IVSP, 14, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING9}, // S_NIGHTSDRONE_SPARKLING8
-	{SPR_IVSP, 16, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING10}, // S_NIGHTSDRONE_SPARKLING9
-	{SPR_IVSP, 18, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING11}, // S_NIGHTSDRONE_SPARKLING10
-	{SPR_IVSP, 20, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING12}, // S_NIGHTSDRONE_SPARKLING11
-	{SPR_IVSP, 22, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING13}, // S_NIGHTSDRONE_SPARKLING12
-	{SPR_IVSP, 24, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING14}, // S_NIGHTSDRONE_SPARKLING13
-	{SPR_IVSP, 26, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING15}, // S_NIGHTSDRONE_SPARKLING14
-	{SPR_IVSP, 28, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING16}, // S_NIGHTSDRONE_SPARKLING15
-	{SPR_IVSP, 30, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING1}, // S_NIGHTSDRONE_SPARKLING16
+	{SPR_IVSP, 0, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING2, 0},   // S_NIGHTSDRONE_SPARKLING1
+	{SPR_IVSP, 2, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING3, 0},   // S_NIGHTSDRONE_SPARKLING2
+	{SPR_IVSP, 4, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING4, 0},   // S_NIGHTSDRONE_SPARKLING3
+	{SPR_IVSP, 6, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING5, 0},   // S_NIGHTSDRONE_SPARKLING4
+	{SPR_IVSP, 8, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING6, 0},  // S_NIGHTSDRONE_SPARKLING5
+	{SPR_IVSP, 10, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING7, 0}, // S_NIGHTSDRONE_SPARKLING6
+	{SPR_IVSP, 12, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING8, 0}, // S_NIGHTSDRONE_SPARKLING7
+	{SPR_IVSP, 14, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING9, 0}, // S_NIGHTSDRONE_SPARKLING8
+	{SPR_IVSP, 16, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING10, 0}, // S_NIGHTSDRONE_SPARKLING9
+	{SPR_IVSP, 18, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING11, 0}, // S_NIGHTSDRONE_SPARKLING10
+	{SPR_IVSP, 20, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING12, 0}, // S_NIGHTSDRONE_SPARKLING11
+	{SPR_IVSP, 22, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING13, 0}, // S_NIGHTSDRONE_SPARKLING12
+	{SPR_IVSP, 24, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING14, 0}, // S_NIGHTSDRONE_SPARKLING13
+	{SPR_IVSP, 26, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING15, 0}, // S_NIGHTSDRONE_SPARKLING14
+	{SPR_IVSP, 28, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING16, 0}, // S_NIGHTSDRONE_SPARKLING15
+	{SPR_IVSP, 30, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING1, 0}, // S_NIGHTSDRONE_SPARKLING16
 
 	// NiGHTS GOAL banner (inside the sparkles!)
-	{SPR_GOAL, 0, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL2}, // S_NIGHTSDRONE_GOAL1
-	{SPR_GOAL, 1, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL3}, // S_NIGHTSDRONE_GOAL2
-	{SPR_GOAL, 2, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL4}, // S_NIGHTSDRONE_GOAL3
-	{SPR_GOAL, 3, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL1}, // S_NIGHTSDRONE_GOAL4
+	{SPR_GOAL, 0, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL2, 0}, // S_NIGHTSDRONE_GOAL1
+	{SPR_GOAL, 1, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL3, 0}, // S_NIGHTSDRONE_GOAL2
+	{SPR_GOAL, 2, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL4, 0}, // S_NIGHTSDRONE_GOAL3
+	{SPR_GOAL, 3, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL1, 0}, // S_NIGHTSDRONE_GOAL4
 
 	// 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, 140, {NULL}, 0, 0, S_NIGHTSPARKLE2, 0},   // S_NIGHTSPARKLE1
+	{SPR_NSPK, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_NIGHTSPARKLE3, 0},   // S_NIGHTSPARKLE2
+	{SPR_NSPK, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_NIGHTSPARKLE4, 0},   // S_NIGHTSPARKLE3
+	{SPR_NSPK, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_NULL, 0},            // 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, 0}, // S_NIGHTSPARKLESUPER1
+	{SPR_NSPK, FF_FULLBRIGHT|5, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER3, 0},   // S_NIGHTSPARKLESUPER2
+	{SPR_NSPK, FF_FULLBRIGHT|6, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER4, 0},   // S_NIGHTSPARKLESUPER3
+	{SPR_NSPK, FF_FULLBRIGHT|7, 7, {NULL}, 0, 0, S_NULL, 0},                 // S_NIGHTSPARKLESUPER4
 
 	// Paraloop helper -- THIS IS WHAT DETERMINES THE TIMER NOW
-	{SPR_NULL, 0, 160, {NULL}, 0, 0, S_NULL}, // S_NIGHTSLOOPHELPER
+	{SPR_NULL, 0, 160, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSLOOPHELPER
 
 	// NiGHTS bumper
-	{SPR_NBMP, 0, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER1
-	{SPR_NBMP, 1, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER2
-	{SPR_NBMP, 2, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER3
-	{SPR_NBMP, 3, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER4
-	{SPR_NBMP, 4, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER5
-	{SPR_NBMP, 5, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER6
-	{SPR_NBMP, 6, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER7
-	{SPR_NBMP, 7, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER8
-	{SPR_NBMP, 8, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER9
-	{SPR_NBMP, 9, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER10
-	{SPR_NBMP, 10, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSBUMPER11
-	{SPR_NBMP, 11, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSBUMPER12
-
-	{SPR_HOOP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HOOP
-	{SPR_HOOP, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HOOP_XMASA
-	{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_NBMP, 0, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER1
+	{SPR_NBMP, 1, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER2
+	{SPR_NBMP, 2, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER3
+	{SPR_NBMP, 3, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER4
+	{SPR_NBMP, 4, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER5
+	{SPR_NBMP, 5, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER6
+	{SPR_NBMP, 6, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER7
+	{SPR_NBMP, 7, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER8
+	{SPR_NBMP, 8, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER9
+	{SPR_NBMP, 9, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER10
+	{SPR_NBMP, 10, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSBUMPER11
+	{SPR_NBMP, 11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSBUMPER12
+
+	{SPR_HOOP, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HOOP
+	{SPR_HOOP, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HOOP_XMASA
+	{SPR_HOOP, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HOOP_XMASB
+
+	{SPR_NSCR, FF_FULLBRIGHT,    -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE10
+	{SPR_NSCR, FF_FULLBRIGHT|1,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE20
+	{SPR_NSCR, FF_FULLBRIGHT|2,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE30
+	{SPR_NSCR, FF_FULLBRIGHT|3,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE40
+	{SPR_NSCR, FF_FULLBRIGHT|4,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE50
+	{SPR_NSCR, FF_FULLBRIGHT|5,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE60
+	{SPR_NSCR, FF_FULLBRIGHT|6,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE70
+	{SPR_NSCR, FF_FULLBRIGHT|7,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE80
+	{SPR_NSCR, FF_FULLBRIGHT|8,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE90
+	{SPR_NSCR, FF_FULLBRIGHT|9,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE100
+	{SPR_NSCR, FF_FULLBRIGHT|10, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE10_2
+	{SPR_NSCR, FF_FULLBRIGHT|11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE20_2
+	{SPR_NSCR, FF_FULLBRIGHT|12, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE30_2
+	{SPR_NSCR, FF_FULLBRIGHT|13, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE40_2
+	{SPR_NSCR, FF_FULLBRIGHT|14, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE50_2
+	{SPR_NSCR, FF_FULLBRIGHT|15, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE60_2
+	{SPR_NSCR, FF_FULLBRIGHT|16, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE70_2
+	{SPR_NSCR, FF_FULLBRIGHT|17, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE80_2
+	{SPR_NSCR, FF_FULLBRIGHT|18, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE90_2
+	{SPR_NSCR, FF_FULLBRIGHT|19, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE100_2
 
 	// NiGHTS Paraloop Powerups
-	{SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSUPERLOOP
-	{SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSDRILLREFILL
-	{SPR_NPRU, 2, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSHELPER
-	{SPR_NPRU, 3, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSEXTRATIME
-	{SPR_NPRU, 4, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSLINKFREEZE
+	{SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSSUPERLOOP
+	{SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSDRILLREFILL
+	{SPR_NPRU, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSHELPER
+	{SPR_NPRU, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSEXTRATIME
+	{SPR_NPRU, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSLINKFREEZE
 
-	{SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGCAPSULE
+	{SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGCAPSULE
 
 	// Orbiting Chaos Emeralds/Ideya 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_IDYA, FF_TRANS20|FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1}, // S_ORBIDYA1
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2}, // S_ORBIDYA2
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3}, // S_ORBIDYA3
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA4}, // S_ORBIDYA4
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA5}, // S_ORBIDYA5
+	{SPR_CEMG, FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1, 0}, // S_ORBITEM1
+	{SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2, 0}, // S_ORBITEM2
+	{SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3, 0}, // S_ORBITEM3
+	{SPR_CEMG, FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4, 0}, // S_ORBITEM4
+	{SPR_CEMG, FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5, 0}, // S_ORBITEM5
+	{SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6, 0}, // S_ORBITEM6
+	{SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7, 0}, // S_ORBITEM7
+	{SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8, 0}, // S_ORBITEM8
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1, 0}, // S_ORBIDYA1
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2, 0}, // S_ORBIDYA2
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3, 0}, // S_ORBIDYA3
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA4, 0}, // S_ORBIDYA4
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA5, 0}, // S_ORBIDYA5
 
 	// Flicky helper for NiGHTS
-	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER2}, // S_NIGHTOPIANHELPER1
-	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER3}, // S_NIGHTOPIANHELPER2
-	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER4}, // S_NIGHTOPIANHELPER3
-	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER5}, // S_NIGHTOPIANHELPER4
-	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER6}, // S_NIGHTOPIANHELPER5
-	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER7}, // S_NIGHTOPIANHELPER6
-	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER8}, // S_NIGHTOPIANHELPER7
-	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER9}, // S_NIGHTOPIANHELPER8
-	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1}, // S_NIGHTOPIANHELPER9
+	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER2, 0}, // S_NIGHTOPIANHELPER1
+	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER3, 0}, // S_NIGHTOPIANHELPER2
+	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER4, 0}, // S_NIGHTOPIANHELPER3
+	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER5, 0}, // S_NIGHTOPIANHELPER4
+	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER6, 0}, // S_NIGHTOPIANHELPER5
+	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER7, 0}, // S_NIGHTOPIANHELPER6
+	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER8, 0}, // S_NIGHTOPIANHELPER7
+	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER9, 0}, // S_NIGHTOPIANHELPER8
+	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1, 0}, // S_NIGHTOPIANHELPER9
 
 	// Nightopian
-	{SPR_NTPN, 0, 2, {A_Look}, 1, 1, S_PIAN_LOOK2}, // S_PIAN_LOOK1
-	{SPR_NTPN, 1, 2, {A_Look}, 1, 1, S_PIAN_LOOK3}, // S_PIAN_LOOK2
-	{SPR_NTPN, 2, 2, {A_Look}, 1, 1, S_PIAN_LOOK1}, // S_PIAN_LOOK3
-	{SPR_NTPN, 0, 2, {A_JetgThink}, 0, 0, S_PIAN_FLY2}, // S_PIAN_FLY1
-	{SPR_NTPN, 1, 2, {NULL}, 0, 0, S_PIAN_FLY3}, // S_PIAN_FLY2
-	{SPR_NTPN, 2, 2, {NULL}, 0, 0, S_PIAN_FLY1}, // S_PIAN_FLY3
-	{SPR_NTPN, 3|FF_ANIMATE, 24, {NULL}, 2, 2, S_PIAN_FLY1}, // S_PIAN_SING
+	{SPR_NTPN, 0, 2, {A_Look}, 1, 1, S_PIAN_LOOK2, 0}, // S_PIAN_LOOK1
+	{SPR_NTPN, 1, 2, {A_Look}, 1, 1, S_PIAN_LOOK3, 0}, // S_PIAN_LOOK2
+	{SPR_NTPN, 2, 2, {A_Look}, 1, 1, S_PIAN_LOOK1, 0}, // S_PIAN_LOOK3
+	{SPR_NTPN, 0, 2, {A_JetgThink}, 0, 0, S_PIAN_FLY2, 0}, // S_PIAN_FLY1
+	{SPR_NTPN, 1, 2, {NULL}, 0, 0, S_PIAN_FLY3, 0}, // S_PIAN_FLY2
+	{SPR_NTPN, 2, 2, {NULL}, 0, 0, S_PIAN_FLY1, 0}, // S_PIAN_FLY3
+	{SPR_NTPN, 3|FF_ANIMATE, 24, {NULL}, 2, 2, S_PIAN_FLY1, 0}, // S_PIAN_SING
 
 	// Shleep
-	{SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2}, // S_SHLEEP1
-	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP3}, // S_SHLEEP2
-	{SPR_SHLP, 2, 15, {NULL}, 0, 0, S_SHLEEP4}, // S_SHLEEP3
-	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP1}, // S_SHLEEP4
-	{SPR_SHLP, 3, 1, {A_Scream},  0, 0, S_SHLEEPBOUNCE2}, // S_SHLEEPBOUNCE1
-	{SPR_SHLP, 3, 1, {A_ZThrust}, 9, 0, S_SHLEEPBOUNCE3}, // S_SHLEEPBOUNCE2
-	{SPR_SHLP, 3, 400, {A_SetObjectFlags}, MF_SLIDEME|MF_ENEMY|MF_BOUNCE|MF_NOCLIP|MF_NOCLIPHEIGHT, 0, S_NULL}, // S_SHLEEPBOUNCE3
+	{SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2, 0}, // S_SHLEEP1
+	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP3, 0}, // S_SHLEEP2
+	{SPR_SHLP, 2, 15, {NULL}, 0, 0, S_SHLEEP4, 0}, // S_SHLEEP3
+	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP1, 0}, // S_SHLEEP4
+	{SPR_SHLP, 3, 1, {A_Scream},  0, 0, S_SHLEEPBOUNCE2, 0}, // S_SHLEEPBOUNCE1
+	{SPR_SHLP, 3, 1, {A_ZThrust}, 9, 0, S_SHLEEPBOUNCE3, 0}, // S_SHLEEPBOUNCE2
+	{SPR_SHLP, 3, 400, {A_SetObjectFlags}, MF_SLIDEME|MF_ENEMY|MF_BOUNCE|MF_NOCLIP|MF_NOCLIPHEIGHT, 0, S_NULL, 0}, // S_SHLEEPBOUNCE3
 
 	// Secret badniks and hazards, shhhh
-	{SPR_PENG, 0, 2, {A_Look},  0, 0, S_PENGUINATOR_LOOK},    // S_PENGUINATOR_LOOK
-	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE2}, // S_PENGUINATOR_WADDLE1
-	{SPR_PENG, 1, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE3}, // S_PENGUINATOR_WADDLE2
-	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE4}, // S_PENGUINATOR_WADDLE3
-	{SPR_PENG, 2, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE1}, // S_PENGUINATOR_WADDLE4
-	{SPR_PENG, 0,  0, {A_FaceTarget},      0,  0, S_PENGUINATOR_SLIDE2}, // S_PENGUINATOR_SLIDE1
-	{SPR_PENG, 3,  5, {A_BunnyHop},        4, 10, S_PENGUINATOR_SLIDE3}, // S_PENGUINATOR_SLIDE2
-	{SPR_PENG, 4, 90, {A_PlayAttackSound}, 0,  0, S_PENGUINATOR_SLIDE4}, // S_PENGUINATOR_SLIDE3
-	{SPR_PENG, 3,  5, {A_Thrust},          0,  1, S_PENGUINATOR_SLIDE5}, // S_PENGUINATOR_SLIDE4
-	{SPR_PENG, 0,  5, {A_FaceTarget},      0,  0, S_PENGUINATOR_LOOK},   // S_PENGUINATOR_SLIDE5
-
-	{SPR_POPH, 0,  2, {A_Look},  (2048<<16)|1,           0, S_POPHAT_LOOK},   // S_POPHAT_LOOK
-	{SPR_POPH, 1,  0, {A_MultiShotDist}, (MT_SPINDUST<<16)|4, 24, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1
-	{SPR_POPH, 1,  2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2
-	{SPR_POPH, 2,  1, {NULL},               0,           0, S_POPHAT_SHOOT4}, // S_POPHAT_SHOOT3
-	{SPR_POPH, 0, 57, {NULL},               0,           0, S_POPHAT_LOOK},   // S_POPHAT_SHOOT4
-	{SPR_POPH, 3,  3, {A_SpawnObjectRelative}, 0, MT_POPSHOT_TRAIL, S_POPSHOT},   // S_POPSHOT
-	{SPR_NULL, 0,  2, {NULL},                  0, 0,                S_SPINDUST1}, // S_POPSHOT_TRAIL
-
-	{SPR_HIVE, 0,  5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK
-	{SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1
-	{SPR_HIVE, 0,  6, {A_PlaySound}, sfx_s3k8c, 1, S_HIVEELEMENTAL_SHOOT1}, // S_HIVEELEMENTAL_PREPARE2
-	{SPR_HIVE, 1,  4, {A_WhoCaresIfYourSonIsABee}, (MT_BUMBLEBORE<<16)|4, (1<<16)|32, S_HIVEELEMENTAL_SHOOT2}, // S_HIVEELEMENTAL_SHOOT1
-	{SPR_HIVE, 2,  2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_SHOOT2
-	{SPR_HIVE, 0,  5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_DORMANT
-	{SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_PAIN
-	{SPR_HIVE, 3,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE2}, // S_HIVEELEMENTAL_DIE1
-	{SPR_NULL, 0,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE3}, // S_HIVEELEMENTAL_DIE2
-	{SPR_NULL, 0,  0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY}, // S_HIVEELEMENTAL_DIE3
-
-	{SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_SPAWN
-	{SPR_BUMB, 0,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK2}, // S_BUMBLEBORE_LOOK1
-	{SPR_BUMB, 1,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_LOOK2
-	{SPR_BUMB, 0,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY2}, // S_BUMBLEBORE_FLY1
-	{SPR_BUMB, 1,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY1}, // S_BUMBLEBORE_FLY2
-	{SPR_BUMB, 2|FF_FULLBRIGHT,  12, {A_ZThrust},  4, (1<<16)|1, S_BUMBLEBORE_FALL1},  // S_BUMBLEBORE_RAISE
-	{SPR_BUMB, 2|FF_FULLBRIGHT,   0, {A_ZThrust}, -8, (1<<16)|1, S_BUMBLEBORE_FALL2},  // S_BUMBLEBORE_FALL1
-	{SPR_BUMB, 2|FF_FULLBRIGHT, 300, {NULL},       0,         0, S_BUMBLEBORE_DIE},    // S_BUMBLEBORE_FALL2
-	{SPR_BUMB, 4, 3, {A_MultiShotDist}, (MT_DUST<<16)|6, -40, S_BUMBLEBORE_STUCK2},    // S_BUMBLEBORE_STUCK1
-	{SPR_BUMB, 5, 120, {NULL}, 0, 0, S_BUMBLEBORE_DIE}, // S_BUMBLEBORE_STUCK2
-	{SPR_BUMB, 5, 0, {A_CryingToMomma}, 0, 0, S_XPLD1}, // S_BUMBLEBORE_DIE
-
-	{SPR_BBUZ,          0, -1, {NULL}, 0, 0, S_NULL}, // S_BUGGLEIDLE
-	{SPR_BBUZ, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL}, // S_BUGGLEFLY
-
-	{SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT
-	{SPR_FMCE, 0,  4, {A_ZThrust},  4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1
-	{SPR_FMCE, 0,  4, {A_ZThrust},  0, (1<<16)|1, S_SMASHSPIKE_FALL},  // S_SMASHSPIKE_EASE2
-	{SPR_FMCE, 0,  2, {A_ZThrust}, -6,         1, S_SMASHSPIKE_FALL},  // S_SMASHSPIKE_FALL
-	{SPR_FMCE, 1,  2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1
-	{SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2
-	{SPR_FMCE, 1,  2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1
-	{SPR_FMCE, 0,  2, {A_ZThrust}, 6, (1<<16)|1, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE2
-
-	{SPR_CACO, 0,  5, {A_Look}, (1100<<16)|1, 0, S_CACO_LOOK}, // S_CACO_LOOK
-	{SPR_CACO, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|7, -48, S_CACO_WAKE2}, // S_CACO_WAKE1
-	{SPR_CACO, 1, 10, {A_ZThrust}, 4, (1<<16)|1, S_CACO_WAKE3}, // S_CACO_WAKE2
-	{SPR_CACO, 2,  8, {A_ZThrust}, 2, (1<<16)|1, S_CACO_WAKE4}, // S_CACO_WAKE3
-	{SPR_CACO, 2,  4, {A_ZThrust}, 0, (1<<16)|1, S_CACO_ROAR},  // S_CACO_WAKE4
-	{SPR_CACO, 2, 10, {A_PlayActiveSound}, 0, 0, S_CACO_CHASE}, // S_CACO_ROAR
-	{SPR_CACO, 2,  5, {A_JetChase}, 0, 0, S_CACO_CHASE_REPEAT}, // S_CACO_CHASE
-	{SPR_CACO, 2,  0, {A_Repeat}, 5, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_CHASE_REPEAT
-	{SPR_CACO, 2,  0, {A_RandomState}, S_CACO_PREPARE_SOUND, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_RANDOM
-	{SPR_CACO, 2,  8, {A_PlaySound}, sfx_s3k95, 1, S_CACO_PREPARE1},  // S_CACO_PREPARE_SOUND
-	{SPR_CACO, 3,               8, {NULL}, 0, 0, S_CACO_PREPARE2},    // S_CACO_PREPARE1
-	{SPR_CACO, 4|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_PREPARE3},    // S_CACO_PREPARE2
-	{SPR_CACO, 5|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_SHOOT_SOUND}, // S_CACO_PREPARE3
-	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_PlaySound}, sfx_s3k4e, 1, S_CACO_SHOOT1}, // S_CACO_SHOOT_SOUND
-	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_CACOFIRE_EXPLODE1, S_CACO_SHOOT2}, // S_CACO_SHOOT1
-	{SPR_CACO, 4|FF_FULLBRIGHT, 6, {A_FireShot}, MT_CACOFIRE, -24, S_CACO_CLOSE}, // S_CACO_SHOOT2
-	{SPR_CACO, 3,              15, {NULL}, 0, 0, S_CACO_CHASE}, // S_CACO_CLOSE
-	{SPR_CACO, 10, 0, {A_SetObjectFlags}, MF_NOBLOCKMAP, 0, S_CACO_DIE_GIB1}, // S_CACO_DIE_FLAGS
-	{SPR_CACO, 10, 0, {A_NapalmScatter}, (7<<16)|MT_CACOSHARD, (30<<16)|20, S_CACO_DIE_GIB2}, // S_CACO_DIE_GIB1
-	{SPR_CACO, 10, 0, {A_NapalmScatter}, (10<<16)|MT_CACOSHARD, (24<<16)|32, S_CACO_DIE_SCREAM}, // S_CACO_DIE_GIB2
-	{SPR_CACO, 10, 0, {A_Scream}, 0, 0, S_CACO_DIE_SHATTER}, // S_CACO_DIE_SCREAM
-	{SPR_CACO, 10, 0, {A_PlaySound}, sfx_pumpkn, 1, S_CACO_DIE_FALL}, // S_CACO_DIE_SHATTER
-	{SPR_CACO, 10, 250, {A_FlickySpawn}, (1<<16), 0, S_NULL}, // S_CACO_DIE_FALL
-
-	{SPR_CACO, 6, 0, {A_RandomState}, S_CACOSHARD1_1, S_CACOSHARD2_1, S_NULL}, // S_CACOSHARD_RANDOMIZE
-	{SPR_CACO, 6, 3, {NULL}, 0, 0, S_CACOSHARD1_2}, // S_CACOSHARD1_1
-	{SPR_CACO, 7, 3, {NULL}, 0, 0, S_CACOSHARD1_1}, // S_CACOSHARD1_2
-	{SPR_CACO, 8, 3, {NULL}, 0, 0, S_CACOSHARD2_2}, // S_CACOSHARD2_1
-	{SPR_CACO, 9, 3, {NULL}, 0, 0, S_CACOSHARD2_1}, // S_CACOSHARD2_2
-	{SPR_BAL2,   FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE2}, // S_CACOFIRE1
-	{SPR_BAL2, 1|FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE3}, // S_CACOFIRE2
-	{SPR_BAL2,   FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CACOFIRE1}, // S_CACOFIRE3
-	{SPR_BAL2, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE2}, // S_CACOFIRE_EXPLODE1
-	{SPR_BAL2, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE3}, // S_CACOFIRE_EXPLODE2
-	{SPR_BAL2, 4|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE4}, // S_CACOFIRE_EXPLODE3
-	{SPR_BAL2, 5|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL},      // S_CACOFIRE_EXPLODE4
-
-	{SPR_SBOB, 1, 10, {A_ZThrust}, -2, (1<<16)|1, S_SPINBOBERT_MOVE_UP},       // S_SPINBOBERT_MOVE_FLIPUP
-	{SPR_SBOB, 0, 45, {A_ZThrust},  4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPDOWN}, // S_SPINBOBERT_MOVE_UP
-	{SPR_SBOB, 1, 10, {A_ZThrust},  2, (1<<16)|1, S_SPINBOBERT_MOVE_DOWN},     // S_SPINBOBERT_MOVE_FLIPDOWN
-	{SPR_SBOB, 2, 45, {A_ZThrust}, -4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPUP},   // S_SPINBOBERT_MOVE_DOWN
-	{SPR_SBSK, FF_FULLBRIGHT, 1, {A_RotateSpikeBall},       0,                        0, S_SPINBOBERT_FIRE_GHOST}, // S_SPINBOBERT_FIRE_MOVE
-	{SPR_SBSK, FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_SPINBOBERT_FIRE_TRAIL1, S_SPINBOBERT_FIRE_MOVE},  // S_SPINBOBERT_FIRE_GHOST
-	{SPR_SBFL, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL2}, // S_SPINBOBERT_FIRE_TRAIL1
-	{SPR_SBFL, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL3}, // S_SPINBOBERT_FIRE_TRAIL2
-	{SPR_SBFL,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL},                   // S_SPINBOBERT_FIRE_TRAIL3
-
-	{SPR_HBAT, 0,  5, {A_Look}, (900<<16)|1, 0, S_HANGSTER_LOOK}, // S_HANGSTER_LOOK
-	{SPR_HBAT, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|10, -34, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP1
-	{SPR_HBAT, 1,  2, {A_ZThrust}, -8, (1<<16)|1, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP2
-	{SPR_HBAT, 1,  6, {A_ZThrust}, -5, (1<<16), S_HANGSTER_ARC2}, // S_HANGSTER_ARC1
-	{SPR_HBAT, 1,  5, {A_ZThrust}, -2, (1<<16), S_HANGSTER_ARC3}, // S_HANGSTER_ARC2
-	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_FLY1}, // S_HANGSTER_ARC3
-	{SPR_HBAT, 1,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY2}, // S_HANGSTER_FLY1
-	{SPR_HBAT, 2,  1, {A_PlaySound}, sfx_s3k52, 1, S_HANGSTER_FLY3}, // S_HANGSTER_FLY2
-	{SPR_HBAT, 3,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY4}, // S_HANGSTER_FLY3
-	{SPR_HBAT, 2,  1, {A_Thrust}, 6, 1, S_HANGSTER_FLYREPEAT}, // S_HANGSTER_FLY4
-	{SPR_HBAT, 2,  0, {A_Repeat}, 12, S_HANGSTER_FLY1, S_HANGSTER_ARCUP1}, // S_HANGSTER_FLYREPEAT
-	{SPR_HBAT, 1,  5, {A_ZThrust},  2, (1<<16), S_HANGSTER_ARCUP2}, // S_HANGSTER_ARCUP1
-	{SPR_HBAT, 1,  6, {A_ZThrust},  5, (1<<16), S_HANGSTER_ARCUP3}, // S_HANGSTER_ARCUP2
-	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_RETURN1}, // S_HANGSTER_ARCUP3
-	{SPR_HBAT, 1,  1, {A_ZThrust},  8, (1<<16), S_HANGSTER_RETURN2}, // S_HANGSTER_RETURN1
-	{SPR_HBAT, 3,  1, {NULL}, 0, 0, S_HANGSTER_RETURN1}, // S_HANGSTER_RETURN2
-	{SPR_HBAT, 0, 15, {NULL}, 0, 0, S_HANGSTER_LOOK}, // S_HANGSTER_RETURN3
-
-	{SPR_NULL, 0,  35, {NULL}, 0, 0, S_CRUMBLE2}, // S_CRUMBLE1
-	{SPR_NULL, 0, 105, {A_Scream}, 0, 0, S_NULL}, // S_CRUMBLE2
+	{SPR_PENG, 0, 2, {A_Look},  0, 0, S_PENGUINATOR_LOOK, 0},    // S_PENGUINATOR_LOOK
+	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE2, 0}, // S_PENGUINATOR_WADDLE1
+	{SPR_PENG, 1, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE3, 0}, // S_PENGUINATOR_WADDLE2
+	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE4, 0}, // S_PENGUINATOR_WADDLE3
+	{SPR_PENG, 2, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE1, 0}, // S_PENGUINATOR_WADDLE4
+	{SPR_PENG, 0,  0, {A_FaceTarget},      0,  0, S_PENGUINATOR_SLIDE2, 0}, // S_PENGUINATOR_SLIDE1
+	{SPR_PENG, 3,  5, {A_BunnyHop},        4, 10, S_PENGUINATOR_SLIDE3, 0}, // S_PENGUINATOR_SLIDE2
+	{SPR_PENG, 4, 90, {A_PlayAttackSound}, 0,  0, S_PENGUINATOR_SLIDE4, 0}, // S_PENGUINATOR_SLIDE3
+	{SPR_PENG, 3,  5, {A_Thrust},          0,  1, S_PENGUINATOR_SLIDE5, 0}, // S_PENGUINATOR_SLIDE4
+	{SPR_PENG, 0,  5, {A_FaceTarget},      0,  0, S_PENGUINATOR_LOOK, 0},   // S_PENGUINATOR_SLIDE5
+
+	{SPR_POPH, 0,  2, {A_Look},  (2048<<16)|1,           0, S_POPHAT_LOOK, 0},   // S_POPHAT_LOOK
+	{SPR_POPH, 1,  0, {A_MultiShotDist}, (MT_SPINDUST<<16)|4, 24, S_POPHAT_SHOOT2, 0}, // S_POPHAT_SHOOT1
+	{SPR_POPH, 1,  2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT3, 0}, // S_POPHAT_SHOOT2
+	{SPR_POPH, 2,  1, {NULL},               0,           0, S_POPHAT_SHOOT4, 0}, // S_POPHAT_SHOOT3
+	{SPR_POPH, 0, 57, {NULL},               0,           0, S_POPHAT_LOOK, 0},   // S_POPHAT_SHOOT4
+	{SPR_POPH, 3,  3, {A_SpawnObjectRelative}, 0, MT_POPSHOT_TRAIL, S_POPSHOT, 0},   // S_POPSHOT
+	{SPR_NULL, 0,  2, {NULL},                  0, 0,                S_SPINDUST1, 0}, // S_POPSHOT_TRAIL
+
+	{SPR_HIVE, 0,  5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK, 0}, // S_HIVEELEMENTAL_LOOK
+	{SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2, 0}, // S_HIVEELEMENTAL_PREPARE1
+	{SPR_HIVE, 0,  6, {A_PlaySound}, sfx_s3k8c, 1, S_HIVEELEMENTAL_SHOOT1, 0}, // S_HIVEELEMENTAL_PREPARE2
+	{SPR_HIVE, 1,  4, {A_WhoCaresIfYourSonIsABee}, (MT_BUMBLEBORE<<16)|4, (1<<16)|32, S_HIVEELEMENTAL_SHOOT2, 0}, // S_HIVEELEMENTAL_SHOOT1
+	{SPR_HIVE, 2,  2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT, 0}, // S_HIVEELEMENTAL_SHOOT2
+	{SPR_HIVE, 0,  5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT, 0}, // S_HIVEELEMENTAL_DORMANT
+	{SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK, 0}, // S_HIVEELEMENTAL_PAIN
+	{SPR_HIVE, 3,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE2, 0}, // S_HIVEELEMENTAL_DIE1
+	{SPR_NULL, 0,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE3, 0}, // S_HIVEELEMENTAL_DIE2
+	{SPR_NULL, 0,  0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY, 0}, // S_HIVEELEMENTAL_DIE3
+
+	{SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1, 0}, // S_BUMBLEBORE_SPAWN
+	{SPR_BUMB, 0,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK2, 0}, // S_BUMBLEBORE_LOOK1
+	{SPR_BUMB, 1,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK1, 0}, // S_BUMBLEBORE_LOOK2
+	{SPR_BUMB, 0,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY2, 0}, // S_BUMBLEBORE_FLY1
+	{SPR_BUMB, 1,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY1, 0}, // S_BUMBLEBORE_FLY2
+	{SPR_BUMB, 2|FF_FULLBRIGHT,  12, {A_ZThrust},  4, (1<<16)|1, S_BUMBLEBORE_FALL1, 0},  // S_BUMBLEBORE_RAISE
+	{SPR_BUMB, 2|FF_FULLBRIGHT,   0, {A_ZThrust}, -8, (1<<16)|1, S_BUMBLEBORE_FALL2, 0},  // S_BUMBLEBORE_FALL1
+	{SPR_BUMB, 2|FF_FULLBRIGHT, 300, {NULL},       0,         0, S_BUMBLEBORE_DIE, 0},    // S_BUMBLEBORE_FALL2
+	{SPR_BUMB, 4, 3, {A_MultiShotDist}, (MT_DUST<<16)|6, -40, S_BUMBLEBORE_STUCK2, 0},    // S_BUMBLEBORE_STUCK1
+	{SPR_BUMB, 5, 120, {NULL}, 0, 0, S_BUMBLEBORE_DIE, 0}, // S_BUMBLEBORE_STUCK2
+	{SPR_BUMB, 5, 0, {A_CryingToMomma}, 0, 0, S_XPLD1, 0}, // S_BUMBLEBORE_DIE
+
+	{SPR_BBUZ,          0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUGGLEIDLE
+	{SPR_BBUZ, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL, 0}, // S_BUGGLEFLY
+
+	{SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1, 0}, // S_SMASHSPIKE_FLOAT
+	{SPR_FMCE, 0,  4, {A_ZThrust},  4, (1<<16)|1, S_SMASHSPIKE_EASE2, 0}, // S_SMASHSPIKE_EASE1
+	{SPR_FMCE, 0,  4, {A_ZThrust},  0, (1<<16)|1, S_SMASHSPIKE_FALL, 0},  // S_SMASHSPIKE_EASE2
+	{SPR_FMCE, 0,  2, {A_ZThrust}, -6,         1, S_SMASHSPIKE_FALL, 0},  // S_SMASHSPIKE_FALL
+	{SPR_FMCE, 1,  2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2, 0}, // S_SMASHSPIKE_STOMP1
+	{SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1, 0}, // S_SMASHSPIKE_STOMP2
+	{SPR_FMCE, 1,  2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2, 0}, // S_SMASHSPIKE_RISE1
+	{SPR_FMCE, 0,  2, {A_ZThrust}, 6, (1<<16)|1, S_SMASHSPIKE_RISE2, 0}, // S_SMASHSPIKE_RISE2
+
+	{SPR_CACO, 0,  5, {A_Look}, (1100<<16)|1, 0, S_CACO_LOOK, 0}, // S_CACO_LOOK
+	{SPR_CACO, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|7, -48, S_CACO_WAKE2, 0}, // S_CACO_WAKE1
+	{SPR_CACO, 1, 10, {A_ZThrust}, 4, (1<<16)|1, S_CACO_WAKE3, 0}, // S_CACO_WAKE2
+	{SPR_CACO, 2,  8, {A_ZThrust}, 2, (1<<16)|1, S_CACO_WAKE4, 0}, // S_CACO_WAKE3
+	{SPR_CACO, 2,  4, {A_ZThrust}, 0, (1<<16)|1, S_CACO_ROAR, 0},  // S_CACO_WAKE4
+	{SPR_CACO, 2, 10, {A_PlayActiveSound}, 0, 0, S_CACO_CHASE, 0}, // S_CACO_ROAR
+	{SPR_CACO, 2,  5, {A_JetChase}, 0, 0, S_CACO_CHASE_REPEAT, 0}, // S_CACO_CHASE
+	{SPR_CACO, 2,  0, {A_Repeat}, 5, S_CACO_CHASE, S_CACO_RANDOM, 0}, // S_CACO_CHASE_REPEAT
+	{SPR_CACO, 2,  0, {A_RandomState}, S_CACO_PREPARE_SOUND, S_CACO_CHASE, S_CACO_RANDOM, 0}, // S_CACO_RANDOM
+	{SPR_CACO, 2,  8, {A_PlaySound}, sfx_s3k95, 1, S_CACO_PREPARE1, 0},  // S_CACO_PREPARE_SOUND
+	{SPR_CACO, 3,               8, {NULL}, 0, 0, S_CACO_PREPARE2, 0},    // S_CACO_PREPARE1
+	{SPR_CACO, 4|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_PREPARE3, 0},    // S_CACO_PREPARE2
+	{SPR_CACO, 5|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_SHOOT_SOUND, 0}, // S_CACO_PREPARE3
+	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_PlaySound}, sfx_s3k4e, 1, S_CACO_SHOOT1, 0}, // S_CACO_SHOOT_SOUND
+	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_CACOFIRE_EXPLODE1, S_CACO_SHOOT2, 0}, // S_CACO_SHOOT1
+	{SPR_CACO, 4|FF_FULLBRIGHT, 6, {A_FireShot}, MT_CACOFIRE, -24, S_CACO_CLOSE, 0}, // S_CACO_SHOOT2
+	{SPR_CACO, 3,              15, {NULL}, 0, 0, S_CACO_CHASE, 0}, // S_CACO_CLOSE
+	{SPR_CACO, 10, 0, {A_SetObjectFlags}, MF_NOBLOCKMAP, 0, S_CACO_DIE_GIB1, 0}, // S_CACO_DIE_FLAGS
+	{SPR_CACO, 10, 0, {A_NapalmScatter}, (7<<16)|MT_CACOSHARD, (30<<16)|20, S_CACO_DIE_GIB2, 0}, // S_CACO_DIE_GIB1
+	{SPR_CACO, 10, 0, {A_NapalmScatter}, (10<<16)|MT_CACOSHARD, (24<<16)|32, S_CACO_DIE_SCREAM, 0}, // S_CACO_DIE_GIB2
+	{SPR_CACO, 10, 0, {A_Scream}, 0, 0, S_CACO_DIE_SHATTER, 0}, // S_CACO_DIE_SCREAM
+	{SPR_CACO, 10, 0, {A_PlaySound}, sfx_pumpkn, 1, S_CACO_DIE_FALL, 0}, // S_CACO_DIE_SHATTER
+	{SPR_CACO, 10, 250, {A_FlickySpawn}, (1<<16), 0, S_NULL, 0}, // S_CACO_DIE_FALL
+
+	{SPR_CACO, 6, 0, {A_RandomState}, S_CACOSHARD1_1, S_CACOSHARD2_1, S_NULL, 0}, // S_CACOSHARD_RANDOMIZE
+	{SPR_CACO, 6, 3, {NULL}, 0, 0, S_CACOSHARD1_2, 0}, // S_CACOSHARD1_1
+	{SPR_CACO, 7, 3, {NULL}, 0, 0, S_CACOSHARD1_1, 0}, // S_CACOSHARD1_2
+	{SPR_CACO, 8, 3, {NULL}, 0, 0, S_CACOSHARD2_2, 0}, // S_CACOSHARD2_1
+	{SPR_CACO, 9, 3, {NULL}, 0, 0, S_CACOSHARD2_1, 0}, // S_CACOSHARD2_2
+	{SPR_BAL2,   FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE2, 0}, // S_CACOFIRE1
+	{SPR_BAL2, 1|FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE3, 0}, // S_CACOFIRE2
+	{SPR_BAL2,   FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CACOFIRE1, 0}, // S_CACOFIRE3
+	{SPR_BAL2, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE2, 0}, // S_CACOFIRE_EXPLODE1
+	{SPR_BAL2, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE3, 0}, // S_CACOFIRE_EXPLODE2
+	{SPR_BAL2, 4|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE4, 0}, // S_CACOFIRE_EXPLODE3
+	{SPR_BAL2, 5|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0},      // S_CACOFIRE_EXPLODE4
+
+	{SPR_SBOB, 1, 10, {A_ZThrust}, -2, (1<<16)|1, S_SPINBOBERT_MOVE_UP, 0},       // S_SPINBOBERT_MOVE_FLIPUP
+	{SPR_SBOB, 0, 45, {A_ZThrust},  4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPDOWN, 0}, // S_SPINBOBERT_MOVE_UP
+	{SPR_SBOB, 1, 10, {A_ZThrust},  2, (1<<16)|1, S_SPINBOBERT_MOVE_DOWN, 0},     // S_SPINBOBERT_MOVE_FLIPDOWN
+	{SPR_SBOB, 2, 45, {A_ZThrust}, -4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPUP, 0},   // S_SPINBOBERT_MOVE_DOWN
+	{SPR_SBSK, FF_FULLBRIGHT, 1, {A_RotateSpikeBall},       0,                        0, S_SPINBOBERT_FIRE_GHOST, 0}, // S_SPINBOBERT_FIRE_MOVE
+	{SPR_SBSK, FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_SPINBOBERT_FIRE_TRAIL1, S_SPINBOBERT_FIRE_MOVE, 0},  // S_SPINBOBERT_FIRE_GHOST
+	{SPR_SBFL, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL2, 0}, // S_SPINBOBERT_FIRE_TRAIL1
+	{SPR_SBFL, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL3, 0}, // S_SPINBOBERT_FIRE_TRAIL2
+	{SPR_SBFL,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0},                   // S_SPINBOBERT_FIRE_TRAIL3
+
+	{SPR_HBAT, 0,  5, {A_Look}, (900<<16)|1, 0, S_HANGSTER_LOOK, 0}, // S_HANGSTER_LOOK
+	{SPR_HBAT, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|10, -34, S_HANGSTER_SWOOP2, 0}, // S_HANGSTER_SWOOP1
+	{SPR_HBAT, 1,  2, {A_ZThrust}, -8, (1<<16)|1, S_HANGSTER_SWOOP2, 0}, // S_HANGSTER_SWOOP2
+	{SPR_HBAT, 1,  6, {A_ZThrust}, -5, (1<<16), S_HANGSTER_ARC2, 0}, // S_HANGSTER_ARC1
+	{SPR_HBAT, 1,  5, {A_ZThrust}, -2, (1<<16), S_HANGSTER_ARC3, 0}, // S_HANGSTER_ARC2
+	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_FLY1, 0}, // S_HANGSTER_ARC3
+	{SPR_HBAT, 1,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY2, 0}, // S_HANGSTER_FLY1
+	{SPR_HBAT, 2,  1, {A_PlaySound}, sfx_s3k52, 1, S_HANGSTER_FLY3, 0}, // S_HANGSTER_FLY2
+	{SPR_HBAT, 3,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY4, 0}, // S_HANGSTER_FLY3
+	{SPR_HBAT, 2,  1, {A_Thrust}, 6, 1, S_HANGSTER_FLYREPEAT, 0}, // S_HANGSTER_FLY4
+	{SPR_HBAT, 2,  0, {A_Repeat}, 12, S_HANGSTER_FLY1, S_HANGSTER_ARCUP1, 0}, // S_HANGSTER_FLYREPEAT
+	{SPR_HBAT, 1,  5, {A_ZThrust},  2, (1<<16), S_HANGSTER_ARCUP2, 0}, // S_HANGSTER_ARCUP1
+	{SPR_HBAT, 1,  6, {A_ZThrust},  5, (1<<16), S_HANGSTER_ARCUP3, 0}, // S_HANGSTER_ARCUP2
+	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_RETURN1, 0}, // S_HANGSTER_ARCUP3
+	{SPR_HBAT, 1,  1, {A_ZThrust},  8, (1<<16), S_HANGSTER_RETURN2, 0}, // S_HANGSTER_RETURN1
+	{SPR_HBAT, 3,  1, {NULL}, 0, 0, S_HANGSTER_RETURN1, 0}, // S_HANGSTER_RETURN2
+	{SPR_HBAT, 0, 15, {NULL}, 0, 0, S_HANGSTER_LOOK, 0}, // S_HANGSTER_RETURN3
+
+	{SPR_NULL, 0,  35, {NULL}, 0, 0, S_CRUMBLE2, 0}, // S_CRUMBLE1
+	{SPR_NULL, 0, 105, {A_Scream}, 0, 0, S_NULL, 0}, // S_CRUMBLE2
 
 	// Spark
-	{SPR_NULL, 0, 1, {A_ModuloToState}, 2, S_SPRK2, S_SPRK3},  // S_SPRK1
-	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|0, 18, {NULL}, 8, 2, S_NULL},  // S_SPRK2
-	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|9, 18, {NULL}, 8, 2, S_NULL},  // S_SPRK3
+	{SPR_NULL, 0, 1, {A_ModuloToState}, 2, S_SPRK2, S_SPRK3, 0},  // S_SPRK1
+	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|0, 18, {NULL}, 8, 2, S_NULL, 0},  // S_SPRK2
+	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|9, 18, {NULL}, 8, 2, S_NULL, 0},  // S_SPRK3
 
 	// Robot Explosion
-	{SPR_BOM1, 0, 0, {A_FlickySpawn},  0, 0, S_XPLD1}, // S_XPLD_FLICKY
-	{SPR_BOM1, 0, 2, {A_ShadowScream}, 0, 0, S_XPLD2}, // S_XPLD1
-	{SPR_BOM1, 1, 2, {NULL},           0, 0, S_XPLD3}, // S_XPLD2
-	{SPR_BOM1, 2, 3, {NULL},           0, 0, S_XPLD4}, // S_XPLD3
-	{SPR_BOM1, 3, 3, {NULL},           0, 0, S_XPLD5}, // S_XPLD4
-	{SPR_BOM1, 4, 4, {NULL},           0, 0, S_XPLD6}, // S_XPLD5
-	{SPR_BOM1, 5, 4, {NULL},           0, 0, S_NULL},  // S_XPLD6
+	{SPR_BOM1, 0, 0, {A_FlickySpawn},  0, 0, S_XPLD1, 0}, // S_XPLD_FLICKY
+	{SPR_BOM1, 0, 2, {A_ShadowScream}, 0, 0, S_XPLD2, 0}, // S_XPLD1
+	{SPR_BOM1, 1, 2, {NULL},           0, 0, S_XPLD3, 0}, // S_XPLD2
+	{SPR_BOM1, 2, 3, {NULL},           0, 0, S_XPLD4, 0}, // S_XPLD3
+	{SPR_BOM1, 3, 3, {NULL},           0, 0, S_XPLD5, 0}, // S_XPLD4
+	{SPR_BOM1, 4, 4, {NULL},           0, 0, S_XPLD6, 0}, // S_XPLD5
+	{SPR_BOM1, 5, 4, {NULL},           0, 0, S_NULL, 0},  // S_XPLD6
 
-	{SPR_BOM1, FF_ANIMATE,   21, {NULL},          5, 4, S_INVISIBLE}, // S_XPLD_EGGTRAP
+	{SPR_BOM1, FF_ANIMATE,   21, {NULL},          5, 4, S_INVISIBLE, 0}, // S_XPLD_EGGTRAP
 
 	// Underwater Explosion
-	{SPR_BOM4, 0, 3, {A_ShadowScream}, 0, 0, S_WPLD2}, // S_WPLD1
-	{SPR_BOM4, 1, 3, {NULL},           0, 0, S_WPLD3}, // S_WPLD2
-	{SPR_BOM4, 2, 3, {NULL},           0, 0, S_WPLD4}, // S_WPLD3
-	{SPR_BOM4, 3, 3, {NULL},           0, 0, S_WPLD5}, // S_WPLD4
-	{SPR_BOM4, 4, 3, {NULL},           0, 0, S_WPLD6}, // S_WPLD5
-	{SPR_BOM4, 5, 3, {NULL},           0, 0, S_NULL},  // S_WPLD6
-
-	{SPR_DUST,   FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2}, // S_DUST1
-	{SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3}, // S_DUST2
-	{SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4}, // S_DUST3
-	{SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL},  // S_DUST4
-
-	{SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN
-
-	{SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA
-	{SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEB
-	{SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEC
-	{SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLED
-	{SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEE
-	{SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEF
-	{SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEG
-	{SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEH
-	{SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEI
-	{SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEJ
-	{SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEK
-	{SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEL
-	{SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEM
-	{SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEN
-	{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEO
-	{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEP
-
-	{SPR_GFZD, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_GFZDEBRIS
-	{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS
-	{SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_WOODDEBRIS
-	{SPR_BRIR, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_REDBRICKDEBRIS
-	{SPR_BRIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_BLUEBRICKDEBRIS
-	{SPR_BRIY, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_YELLOWBRICKDEBRIS
-
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
+	{SPR_BOM4, 0, 3, {A_ShadowScream}, 0, 0, S_WPLD2, 0}, // S_WPLD1
+	{SPR_BOM4, 1, 3, {NULL},           0, 0, S_WPLD3, 0}, // S_WPLD2
+	{SPR_BOM4, 2, 3, {NULL},           0, 0, S_WPLD4, 0}, // S_WPLD3
+	{SPR_BOM4, 3, 3, {NULL},           0, 0, S_WPLD5, 0}, // S_WPLD4
+	{SPR_BOM4, 4, 3, {NULL},           0, 0, S_WPLD6, 0}, // S_WPLD5
+	{SPR_BOM4, 5, 3, {NULL},           0, 0, S_NULL, 0},  // S_WPLD6
+
+	{SPR_DUST,   FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2, 0}, // S_DUST1
+	{SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3, 0}, // S_DUST2
+	{SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4, 0}, // S_DUST3
+	{SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL, 0},  // S_DUST4
+
+	{SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN, 0}, // S_ROCKSPAWN
+
+	{SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEA
+	{SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEB
+	{SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEC
+	{SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLED
+	{SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEE
+	{SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEF
+	{SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEG
+	{SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEH
+	{SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEI
+	{SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEJ
+	{SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEK
+	{SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEL
+	{SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEM
+	{SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEN
+	{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEO
+	{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEP
+
+	{SPR_GFZD, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_GFZDEBRIS
+	{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL, 0}, // S_BRICKDEBRIS
+	{SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL, 0}, // S_WOODDEBRIS
+	{SPR_BRIR, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_REDBRICKDEBRIS
+	{SPR_BRIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_BLUEBRICKDEBRIS
+	{SPR_BRIY, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_YELLOWBRICKDEBRIS
+
+	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL, 0}, // S_NAMECHECK
 };
 
 mobjinfo_t mobjinfo[NUMMOBJTYPES] =
@@ -7493,12 +7494,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		sfx_steam1,     // deathsound
 		0,              // speed
 		32*FRACUNIT,    // radius
-		1*FRACUNIT,     // height
+		16*FRACUNIT,    // height
 		0,              // display offset
 		20*FRACUNIT,    // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_SOLID,       // flags
+		MF_SPECIAL,     // flags
 		S_NULL          // raisestate
 	},
 
diff --git a/src/info.h b/src/info.h
index e8963cd3cdbdb28d2a498bb95cb63b9b5376a354..0361f64281150bec03676bd1b8a4baa36a18de22 100644
--- a/src/info.h
+++ b/src/info.h
@@ -575,6 +575,7 @@ extern int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION];
 #define NUMMOBJFREESLOTS 1024
 #define NUMSPRITEFREESLOTS NUMMOBJFREESLOTS
 #define NUMSTATEFREESLOTS (NUMMOBJFREESLOTS*8)
+#define MAXSPRITENAME 64
 
 // Hey, moron! If you change this table, don't forget about sprnames in info.c and the sprite lights in hw_light.c!
 typedef enum sprite
@@ -1078,9 +1079,6 @@ typedef enum sprite
 	NUMSPRITES
 } spritenum_t;
 
-// Make sure to be conscious of FF_FRAMEMASK and the fact sprite2 is stored as a UINT8 whenever you change this table.
-// Currently, FF_FRAMEMASK is 0xff, or 255 - but the second half is used by FF_SPR2SUPER, so the limitation is 0x7f.
-// Since this is zero-based, there can be at most 128 different SPR2_'s without changing that.
 typedef enum playersprite
 {
 	SPR2_STND = 0,
@@ -1160,15 +1158,17 @@ typedef enum playersprite
 	SPR2_XTRA, // stuff that isn't in-map - "would this ever need an md2 or variable length animation?"
 
 	SPR2_FIRSTFREESLOT,
-	SPR2_LASTFREESLOT = 0x7f,
+	SPR2_LASTFREESLOT = 1024, // Do not make higher than SPR2F_MASK (currently 0x3FF) plus one
 	NUMPLAYERSPRITES
 } playersprite_t;
 
-// SPR2_XTRA
-#define XTRA_LIFEPIC    0                 // Life icon patch
-#define XTRA_CHARSEL    1                 // Character select picture
-#define XTRA_CONTINUE   2                 // Continue icon
-#define XTRA_ENDING     3                 // Ending finale patches
+enum
+{
+	XTRA_LIFEPIC,
+	XTRA_CHARSEL,
+	XTRA_CONTINUE,
+	XTRA_ENDING
+};
 
 typedef enum state
 {
@@ -4380,11 +4380,12 @@ typedef struct
 	INT32 var1;
 	INT32 var2;
 	statenum_t nextstate;
+	UINT16 sprite2;
 } state_t;
 
 extern state_t states[NUMSTATES];
-extern char sprnames[NUMSPRITES + 1][5];
-extern char spr2names[NUMPLAYERSPRITES][5];
+extern char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1];
+extern char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1];
 extern playersprite_t spr2defaults[NUMPLAYERSPRITES];
 extern state_t *astate;
 extern playersprite_t free_spr2;
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 680c6a2c3ca9afbd48fdf7320d1b8a9e502373fb..f6b8f462b5a41cee30c33145fd62fa28daa01e92 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -44,6 +44,21 @@ return luaL_error(L, "HUD rendering code should not call this function!");\
 else if (hook_cmd_running)\
 return luaL_error(L, "CMD building code should not call this function!");
 
+#define NOSPAWNNULL if (type >= NUMMOBJTYPES)\
+return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);\
+else if (type == MT_NULL)\
+{\
+	if (!nospawnnull_seen) {\
+		nospawnnull_seen = true;\
+		CONS_Alert(CONS_WARNING,"Spawning an \"MT_NULL\" mobj is deprecated and will be removed.\nUse \"MT_RAY\" instead.\n");\
+	}\
+type = MT_RAY;\
+}
+static boolean nospawnnull_seen = false; // TODO: 2.3: Delete
+// TODO: 2.3: Use the below NOSPAWNNULL define instead. P_SpawnMobj used to say "if MT_NULL, use MT_RAY instead", so the above define maintains Lua script compatibility until v2.3
+/*#define NOSPAWNNULL if (type <= MT_NULL || type >= NUMMOBJTYPES)\
+return luaL_error(L, "mobj type %d out of range (1 - %d)", type, NUMMOBJTYPES-1);*/
+
 boolean luaL_checkboolean(lua_State *L, int narg) {
 	luaL_checktype(L, narg, LUA_TBOOLEAN);
 	return lua_toboolean(L, narg);
@@ -625,8 +640,7 @@ static int lib_pSpawnMobj(lua_State *L)
 	mobjtype_t type = luaL_checkinteger(L, 4);
 	NOHUD
 	INLEVEL
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
+	NOSPAWNNULL
 	LUA_PushUserdata(L, P_SpawnMobj(x, y, z, type), META_MOBJ);
 	return 1;
 }
@@ -640,10 +654,9 @@ static int lib_pSpawnMobjFromMobj(lua_State *L)
 	mobjtype_t type = luaL_checkinteger(L, 5);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SpawnMobjFromMobj(actor, x, y, z, type), META_MOBJ);
 	return 1;
 }
@@ -661,17 +674,15 @@ static int lib_pRemoveMobj(lua_State *L)
 	return 0;
 }
 
-// P_IsValidSprite2 technically doesn't exist, and probably never should... but too much would need to be exposed to allow this to be checked by other methods.
-
 static int lib_pIsValidSprite2(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	UINT8 spr2 = (UINT8)luaL_checkinteger(L, 2);
+	UINT16 spr2 = (UINT16)luaL_checkinteger(L, 2);
 	//HUDSAFE
 	INLEVEL
 	if (!mobj)
 		return LUA_ErrInvalid(L, "mobj_t");
-	lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes)));
+	lua_pushboolean(L, mobj->skin && P_IsValidSprite2(mobj->skin, spr2));
 	return 1;
 }
 
@@ -708,10 +719,9 @@ static int lib_pSpawnMissile(lua_State *L)
 	mobjtype_t type = luaL_checkinteger(L, 3);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!source || !dest)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SpawnMissile(source, dest, type), META_MOBJ);
 	return 1;
 }
@@ -726,10 +736,9 @@ static int lib_pSpawnXYZMissile(lua_State *L)
 	fixed_t z = luaL_checkfixed(L, 6);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!source || !dest)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SpawnXYZMissile(source, dest, type, x, y, z), META_MOBJ);
 	return 1;
 }
@@ -746,10 +755,9 @@ static int lib_pSpawnPointMissile(lua_State *L)
 	fixed_t z = luaL_checkfixed(L, 8);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!source)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SpawnPointMissile(source, xa, ya, za, type, x, y, z), META_MOBJ);
 	return 1;
 }
@@ -764,10 +772,9 @@ static int lib_pSpawnAlteredDirectionMissile(lua_State *L)
 	INT32 shiftingAngle = (INT32)luaL_checkinteger(L, 5);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!source)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SpawnAlteredDirectionMissile(source, type, x, y, z, shiftingAngle), META_MOBJ);
 	return 1;
 }
@@ -795,10 +802,9 @@ static int lib_pSPMAngle(lua_State *L)
 	UINT32 flags2 = (UINT32)luaL_optinteger(L, 5, 0);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!source)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SPMAngle(source, type, angle, allowaim, flags2), META_MOBJ);
 	return 1;
 }
@@ -810,10 +816,9 @@ static int lib_pSpawnPlayerMissile(lua_State *L)
 	UINT32 flags2 = (UINT32)luaL_optinteger(L, 3, 0);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!source)
 		return LUA_ErrInvalid(L, "mobj_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	LUA_PushUserdata(L, P_SpawnPlayerMissile(source, type, flags2), META_MOBJ);
 	return 1;
 }
@@ -844,8 +849,7 @@ static int lib_pWeaponOrPanel(lua_State *L)
 {
 	mobjtype_t type = luaL_checkinteger(L, 1);
 	//HUDSAFE
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
+	NOSPAWNNULL
 	lua_pushboolean(L, P_WeaponOrPanel(type));
 	return 1;
 }
@@ -888,8 +892,7 @@ static int lib_pSpawnParaloop(lua_State *L)
 	boolean spawncenter = lua_optboolean(L, 9);
 	NOHUD
 	INLEVEL
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
+	NOSPAWNNULL
 	if (nstate >= NUMSTATES)
 		return luaL_error(L, "state %d out of range (0 - %d)", nstate, NUMSTATES-1);
 	P_SpawnParaloop(x, y, z, radius, number, type, nstate, rotangle, spawncenter);
@@ -924,13 +927,14 @@ static int lib_pSetScale(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	fixed_t newscale = luaL_checkfixed(L, 2);
+	boolean instant = lua_optboolean(L, 3);
 	NOHUD
 	INLEVEL
 	if (!mobj)
 		return LUA_ErrInvalid(L, "mobj_t");
 	if (newscale < FRACUNIT/100)
 		newscale = FRACUNIT/100;
-	P_SetScale(mobj, newscale);
+	P_SetScale(mobj, newscale, instant);
 	return 0;
 }
 
@@ -1762,10 +1766,9 @@ static int lib_pSpawnSpinMobj(lua_State *L)
 	mobjtype_t type = luaL_checkinteger(L, 2);
 	NOHUD
 	INLEVEL
+	NOSPAWNNULL
 	if (!player)
 		return LUA_ErrInvalid(L, "player_t");
-	if (type >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
 	P_SpawnSpinMobj(player, type);
 	return 0;
 }
@@ -2497,6 +2500,17 @@ static int lib_pDoSuperTransformation(lua_State *L)
 	return 0;
 }
 
+static int lib_pDoSuperDetransformation(lua_State *L)
+{
+	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
+	NOHUD
+	INLEVEL
+	if (!player)
+		return LUA_ErrInvalid(L, "player_t");
+	P_DoSuperDetransformation(player);
+	return 0;
+}
+
 static int lib_pExplodeMissile(lua_State *L)
 {
 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@@ -2711,12 +2725,11 @@ static int lib_pFadeLight(lua_State *L)
 
 static int lib_pIsFlagAtBase(lua_State *L)
 {
-	mobjtype_t flag = luaL_checkinteger(L, 1);
+	mobjtype_t type = luaL_checkinteger(L, 1);
 	//HUDSAFE
 	INLEVEL
-	if (flag >= NUMMOBJTYPES)
-		return luaL_error(L, "mobj type %d out of range (0 - %d)", flag, NUMMOBJTYPES-1);
-	lua_pushboolean(L, P_IsFlagAtBase(flag));
+	NOSPAWNNULL
+	lua_pushboolean(L, P_IsFlagAtBase(type));
 	return 1;
 }
 
@@ -3017,6 +3030,9 @@ static int lib_rFrame2Char(lua_State *L)
 	//HUDSAFE
 
 	c[0] = R_Frame2Char(ch);
+	if (c[0] == '\xFF')
+		return luaL_error(L, "frame %u cannot be represented by a character", ch);
+
 	c[1] = 0;
 
 	lua_pushstring(L, c);
@@ -3024,6 +3040,9 @@ static int lib_rFrame2Char(lua_State *L)
 	return 2;
 }
 
+// R_SKINS
+////////////
+
 // R_SetPlayerSkin technically doesn't exist either, although it's basically just SetPlayerSkin and SetPlayerSkinByNum handled in one place for convenience
 static int lib_rSetPlayerSkin(lua_State *L)
 {
@@ -3086,6 +3105,47 @@ static int lib_rSkinUsable(lua_State *L)
 	return 1;
 }
 
+static int lib_pGetStateSprite2(lua_State *L)
+{
+	int statenum = luaL_checkinteger(L, 1);
+	if (statenum < 0 || statenum >= NUMSTATES)
+		return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
+
+	lua_pushinteger(L, P_GetStateSprite2(&states[statenum]));
+	return 1;
+}
+
+static int lib_pGetSprite2StateFrame(lua_State *L)
+{
+	int statenum = luaL_checkinteger(L, 1);
+	if (statenum < 0 || statenum >= NUMSTATES)
+		return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
+
+	lua_pushinteger(L, P_GetSprite2StateFrame(&states[statenum]));
+	return 1;
+}
+
+static int lib_pIsStateSprite2Super(lua_State *L)
+{
+	int statenum = luaL_checkinteger(L, 1);
+	if (statenum < 0 || statenum >= NUMSTATES)
+		return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
+
+	lua_pushboolean(L, P_IsStateSprite2Super(&states[statenum]));
+	return 1;
+}
+
+// Not a real function. Who cares? I know I don't.
+static int lib_pGetSuperSprite2(lua_State *L)
+{
+	int animID = luaL_checkinteger(L, 1) & SPR2F_MASK;
+	if (animID < 0 || animID >= NUMPLAYERSPRITES)
+		return luaL_error(L, "sprite2 %d out of range (0 - %d)", animID, NUMPLAYERSPRITES-1);
+
+	lua_pushinteger(L, animID | SPR2F_SUPER);
+	return 1;
+}
+
 // R_DATA
 ////////////
 
@@ -4450,6 +4510,7 @@ static luaL_Reg lib[] = {
 	{"P_VectorInstaThrust",lib_pVectorInstaThrust},
 	{"P_SetMobjStateNF",lib_pSetMobjStateNF},
 	{"P_DoSuperTransformation",lib_pDoSuperTransformation},
+	{"P_DoSuperDetransformation",lib_pDoSuperDetransformation},
 	{"P_ExplodeMissile",lib_pExplodeMissile},
 	{"P_MobjTouchingSectorSpecial",lib_pMobjTouchingSectorSpecial},
 	{"P_ThingOnSpecial3DFloor",lib_pThingOnSpecial3DFloor},
@@ -4490,7 +4551,13 @@ static luaL_Reg lib[] = {
 	{"R_Char2Frame",lib_rChar2Frame},
 	{"R_Frame2Char",lib_rFrame2Char},
 	{"R_SetPlayerSkin",lib_rSetPlayerSkin},
+
+	// r_skins
 	{"R_SkinUsable",lib_rSkinUsable},
+	{"P_GetStateSprite2",lib_pGetStateSprite2},
+	{"P_GetSprite2StateFrame",lib_pGetSprite2StateFrame},
+	{"P_IsStateSprite2Super",lib_pIsStateSprite2Super},
+	{"P_GetSuperSprite2",lib_pGetSuperSprite2},
 
 	// r_data
 	{"R_CheckTextureNumForName",lib_rCheckTextureNumForName},
diff --git a/src/lua_hook.h b/src/lua_hook.h
index 026e5c4aaf97c54326a22d5de56f4e44cbddd09f..17e0e99a0787d43fa12f817018b29acaac723495 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -86,6 +86,8 @@ automatically.
 	X (title),/* titlescreen */\
 	X (titlecard),\
 	X (intermission),\
+	X (continue),\
+	X (playersetup),\
 
 /*
 I chose to access the hook enums through a macro as well. This could provide
@@ -117,6 +119,13 @@ extern boolean hook_cmd_running;
 
 void LUA_HookVoid(int hook);
 void LUA_HookHUD(int hook, huddrawlist_h drawlist);
+int LUA_HookCharacterHUD
+(
+	int hook, huddrawlist_h drawlist, player_t *player,
+	fixed_t x, fixed_t y, fixed_t scale,
+	INT32 skinIndex, UINT8 sprite2, UINT8 frame, UINT8 rotation, skincolornum_t color,
+	INT32 ticker, boolean mode
+);
 
 int  LUA_HookMobj(mobj_t *, int hook);
 int  LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook);
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 529c189ff7883bbd377327ad5b44d2ae5af4e196..54381e4aedc47a64d89190f5582c3c5856634ba6 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -375,6 +375,17 @@ static boolean prepare_string_hook
 		return false;
 }
 
+static boolean prepare_hud_hook
+(
+		Hook_State * hook,
+		int default_status,
+		int hook_type
+){
+	return init_hook_type(hook, default_status,
+			hook_type, 0, NULL,
+			hudHookIds[hook_type].numHooks);
+}
+
 static void init_hook_call
 (
 		Hook_State * hook,
@@ -490,6 +501,21 @@ static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type)
 	return call_mapped(hook, &mobjHookIds[mobj_type][hook->hook_type]);
 }
 
+static void call_hud_hooks
+(
+		Hook_State * hook,
+		int        results,
+		Hook_Callback results_handler
+){
+	hud_running = true; // local hook
+	init_hook_call(hook, results, results_handler);
+	call_mapped(hook, &hudHookIds[hook->hook_type]);
+	hud_running = false;
+
+	lua_pushnil(gL);
+	lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
+}
+
 static int call_hooks
 (
 		Hook_State * hook,
@@ -648,23 +674,39 @@ int LUA_HookKey(event_t *event, int hook_type)
 
 void LUA_HookHUD(int hook_type, huddrawlist_h list)
 {
-	const hook_t * map = &hudHookIds[hook_type];
 	Hook_State hook;
-	if (map->numHooks > 0)
+	if (prepare_hud_hook(&hook, 0, hook_type))
 	{
-		start_hook_stack();
-		begin_hook_values(&hook);
-
 		LUA_SetHudHook(hook_type, list);
+		call_hud_hooks(&hook, 0, res_none);
+	}
+}
 
-		hud_running = true; // local hook
-		init_hook_call(&hook, 0, res_none);
-		call_mapped(&hook, map);
-		hud_running = false;
-
-		lua_pushnil(gL);
-		lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
+int LUA_HookCharacterHUD
+(
+	int hook_type, huddrawlist_h list, player_t *player,
+	fixed_t x, fixed_t y, fixed_t scale,
+	INT32 skinIndex, UINT8 sprite2, UINT8 frame, UINT8 rotation, skincolornum_t color,
+	INT32 ticker, boolean mode
+){
+	Hook_State hook;
+	if (prepare_hud_hook(&hook, false, hook_type))
+	{
+		LUA_SetHudHook(hook_type, list);
+		LUA_PushUserdata(gL, player, META_PLAYER);
+		lua_pushfixed(gL, x);
+		lua_pushfixed(gL, y);
+		lua_pushfixed(gL, scale);
+		lua_pushstring(gL, skins[skinIndex]->name);
+		lua_pushinteger(gL, sprite2);
+		lua_pushinteger(gL, frame);
+		lua_pushinteger(gL, rotation);
+		lua_pushinteger(gL, color);
+		lua_pushinteger(gL, ticker);
+		lua_pushboolean(gL, mode);
+		call_hud_hooks(&hook, 1, res_true);
 	}
+	return hook.status;
 }
 
 /* =========================================================================
diff --git a/src/lua_hud.h b/src/lua_hud.h
index ba102f2f4a13d6c1606e71b08b0198cd742d212b..36ce230ed2a384a73e1f988c41ef79d6d91986a5 100644
--- a/src/lua_hud.h
+++ b/src/lua_hud.h
@@ -19,11 +19,13 @@ enum hud {
 	hud_stagetitle = 0,
 	hud_textspectator,
 	hud_crosshair,
+	hud_powerups,
 	// Singleplayer / Co-op
 	hud_score,
 	hud_time,
 	hud_rings,
 	hud_lives,
+	hud_input,
 	// Match / CTF / Tag / Ringslinger
 	hud_weaponrings,
 	hud_powerstones,
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 52a875e50c0c550f2c10dbb1acd56647955baf01..d6771f1082a635e2bcb9e26ffb4349398113397c 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -41,11 +41,13 @@ static const char *const hud_disable_options[] = {
 	"stagetitle",
 	"textspectator",
 	"crosshair",
+	"powerups",
 
 	"score",
 	"time",
 	"rings",
 	"lives",
+	"input",
 
 	"weaponrings",
 	"powerstones",
@@ -69,6 +71,10 @@ static const char *const hud_disable_options[] = {
 	"intermissionemeralds",
 	NULL};
 
+// you know, let's actually make sure that the table is synced.
+// because fuck knows how many times this has happened at this point. :v
+I_StaticAssert(sizeof(hud_disable_options) / sizeof(*hud_disable_options) == hud_MAX+1);
+
 enum hudinfo {
 	hudinfo_x = 0,
 	hudinfo_y,
@@ -486,9 +492,7 @@ static int libd_getSpritePatch(lua_State *L)
 	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "THOK"
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < NUMSPRITES; i++)
-			if (fastcmp(name, sprnames[i]))
-				break;
+		i = R_GetSpriteNumByName(name);
 		if (i >= NUMSPRITES)
 			return 0;
 	}
@@ -550,7 +554,7 @@ static int libd_getSprite2Patch(lua_State *L)
 	UINT8 angle = 0;
 	spritedef_t *sprdef;
 	spriteframe_t *sprframe;
-	boolean super = false; // add FF_SPR2SUPER to sprite2 if true
+	boolean super = false; // add SPR2F_SUPER to sprite2 if true
 	HUDONLY
 
 	// get skin first!
@@ -577,11 +581,12 @@ static int libd_getSprite2Patch(lua_State *L)
 	if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR2_STND
 	{
 		j = lua_tonumber(L, 1);
-		if (j & FF_SPR2SUPER) // e.g. SPR2_STND|FF_SPR2SUPER
+		if (j & SPR2F_SUPER) // e.g. SPR2_STND|SPR2F_SUPER
 		{
 			super = true;
-			j &= ~FF_SPR2SUPER; // remove flag so the next check doesn't fail
+			j &= ~SPR2F_SUPER; // remove flag so the next check doesn't fail
 		}
+
 		if (j >= free_spr2)
 			return 0;
 	}
@@ -600,17 +605,15 @@ static int libd_getSprite2Patch(lua_State *L)
 
 	if (lua_isboolean(L, 2)) // optional boolean for superness
 	{
-		super = lua_toboolean(L, 2); // note: this can override FF_SPR2SUPER from sprite number
+		super = lua_toboolean(L, 2); // note: this can override SPR2F_SUPER from sprite number
 		lua_remove(L, 2); // remove
 	}
 	// if it's not boolean then just assume it's the frame number
 
 	if (super)
-		j |= FF_SPR2SUPER;
-
-	j = P_GetSkinSprite2(skins[i], j, NULL); // feed skin and current sprite2 through to change sprite2 used if necessary
+		j |= SPR2F_SUPER;
 
-	sprdef = &skins[i]->sprites[j];
+	sprdef = P_GetSkinSpritedef(skins[i], j);
 
 	// set frame number
 	frame = luaL_optinteger(L, 2, 0);
@@ -638,7 +641,7 @@ static int libd_getSprite2Patch(lua_State *L)
 		INT32 rot = R_GetRollAngle(rollangle);
 
 		if (rot) {
-			patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), &skins[i]->sprinfo[j], rot);
+			patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), P_GetSkinSpriteInfo(skins[i], j), rot);
 			LUA_PushUserdata(L, rotsprite, META_PATCH);
 			lua_pushboolean(L, false);
 			lua_pushboolean(L, true);
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index 767477d0bac75e7b9bada5367cb223a37a33f8cd..eeb1067a335f121f23d89bcf817a0b54f53f4f41 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -88,12 +88,12 @@ static int lib_getSprname(lua_State *L)
 	else if (lua_isstring(L, 1))
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < NUMSPRITES; i++)
-			if (fastcmp(name, sprnames[i]))
-			{
-				lua_pushinteger(L, i);
-				return 1;
-			}
+		i = R_GetSpriteNumByName(name);
+		if (i != NUMSPRITES)
+		{
+			lua_pushinteger(L, i);
+			return 1;
+		}
 	}
 	return 0;
 }
@@ -165,7 +165,7 @@ static int lib_getSpr2default(lua_State *L)
 static int lib_setSpr2default(lua_State *L)
 {
 	playersprite_t i;
-	UINT8 j = 0;
+	UINT16 j = 0;
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!");
@@ -245,22 +245,15 @@ static int lib_getSpriteInfo(lua_State *L)
 	if (lua_isstring(L, 1))
 	{
 		const char *name = lua_tostring(L, 1);
-		INT32 spr;
-		for (spr = 0; spr < NUMSPRITES; spr++)
-		{
-			if (fastcmp(name, sprnames[spr]))
-			{
-				i = spr;
-				break;
-			}
-		}
-		if (i == NUMSPRITES)
+		INT32 spr = R_GetSpriteNumByName(name);
+		if (spr == NUMSPRITES)
 		{
 			char *check;
 			i = strtol(name, &check, 10);
 			if (check == name || *check != '\0')
 				return luaL_error(L, "unknown sprite name %s", name);
 		}
+		i = spr;
 	}
 	else
 		i = luaL_checkinteger(L, 1);
@@ -359,8 +352,8 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
 			default:
 				TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1));
 		}
-		if ((idx < 0) || (idx >= 64))
-			return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63);
+		if ((idx < 0) || (idx >= MAXFRAMENUM))
+			return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, MAXFRAMENUM - 1);
 		// the values in pivot[] are also tables
 		if (PopPivotSubTable(info->pivot, L, stk+2, idx))
 			info->available = true;
@@ -555,7 +548,7 @@ static int pivotlist_set(lua_State *L)
 
 static int pivotlist_num(lua_State *L)
 {
-	lua_pushinteger(L, 64);
+	lua_pushinteger(L, MAXFRAMENUM);
 	return 1;
 }
 
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 7fd16b32b2c0806f06d2f557823aeabbc5bb4c76..de7065790abb137e82f505c961215ca6acb10429 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -564,7 +564,7 @@ static int mobj_set(lua_State *L)
 		mo->frame = (UINT32)luaL_checkinteger(L, 3);
 		break;
 	case mobj_sprite2:
-		mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT8)luaL_checkinteger(L, 3), mo->player);
+		mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT16)luaL_checkinteger(L, 3), mo->player);
 		break;
 	case mobj_anim_duration:
 		mo->anim_duration = (UINT16)luaL_checkinteger(L, 3);
@@ -762,7 +762,7 @@ static int mobj_set(lua_State *L)
 			return luaL_error(L, "mobj.type %d out of range (0 - %d).", newtype, NUMMOBJTYPES-1);
 		mo->type = newtype;
 		mo->info = &mobjinfo[newtype];
-		P_SetScale(mo, mo->scale);
+		P_SetScale(mo, mo->scale, false);
 		break;
 	}
 	case mobj_info:
@@ -836,9 +836,7 @@ static int mobj_set(lua_State *L)
 		fixed_t scale = luaL_checkfixed(L, 3);
 		if (scale < FRACUNIT/100)
 			scale = FRACUNIT/100;
-		mo->destscale = scale;
-		P_SetScale(mo, scale);
-		mo->old_scale = scale;
+		P_SetScale(mo, scale, true);
 		break;
 	}
 	case mobj_destscale:
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index b6ef2579c131d8de29a521615cb6a74acc94f5a0..744a56f7fe528031dd0777c06da35067fb59dde4 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -190,6 +190,7 @@ enum player_e
 	player_marelap,
 	player_marebonuslap,
 	player_marebegunat,
+	player_lastmaretime,
 	player_startedtime,
 	player_finishedtime,
 	player_lapbegunat,
@@ -337,6 +338,7 @@ static const char *const player_opt[] = {
 	"marelap",
 	"marebonuslap",
 	"marebegunat",
+	"lastmaretime",
 	"startedtime",
 	"finishedtime",
 	"lapbegunat",
@@ -725,6 +727,9 @@ static int player_get(lua_State *L)
 	case player_marebegunat:
 		lua_pushinteger(L, plr->marebegunat);
 		break;
+	case player_lastmaretime:
+		lua_pushinteger(L, plr->lastmaretime);
+		break;
 	case player_startedtime:
 		lua_pushinteger(L, plr->startedtime);
 		break;
@@ -1219,6 +1224,9 @@ static int player_set(lua_State *L)
 	case player_marebegunat:
 		plr->marebegunat = (tic_t)luaL_checkinteger(L, 3);
 		break;
+	case player_lastmaretime:
+		plr->lastmaretime = (tic_t)luaL_checkinteger(L, 3);
+		break;
 	case player_startedtime:
 		plr->startedtime = (tic_t)luaL_checkinteger(L, 3);
 		break;
diff --git a/src/lua_script.c b/src/lua_script.c
index b62fa675e2e7193da3a688d89d2f1cf377298a51..057899555480383611652c552e41bf41398b0e2b 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -622,9 +622,6 @@ static inline boolean LUA_LoadFile(MYFILE *f, char *name)
 	if (!gL) // Lua needs to be initialized
 		LUA_ClearState();
 
-	lua_pushinteger(gL, f->wad);
-	lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
-
 	lua_pushcfunction(gL, LUA_GetErrorMessage);
 	errorhandlerindex = lua_gettop(gL);
 
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index e183d8dda4a08b4c64dcc2429937cf919d743f67..24d948a6735c3c723dcbf86c285a23c8367090dd 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -55,6 +55,7 @@ enum skin {
 	skin_contangle,
 	skin_soundsid,
 	skin_sprites,
+	skin_supersprites,
 	skin_natkcolor
 };
 
@@ -95,6 +96,7 @@ static const char *const skin_opt[] = {
 	"contangle",
 	"soundsid",
 	"sprites",
+	"supersprites",
 	"natkcolor",
 	NULL};
 
@@ -220,6 +222,9 @@ static int skin_get(lua_State *L)
 	case skin_sprites:
 		LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
 		break;
+	case skin_supersprites:
+		LUA_PushUserdata(L, skin->super.sprites, META_SKINSPRITES);
+		break;
 	case skin_natkcolor:
 		lua_pushinteger(L, skin->natkcolor);
 		break;
@@ -347,17 +352,17 @@ static int lib_getSkinSprite(lua_State *L)
 	spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
 	playersprite_t i = luaL_checkinteger(L, 2);
 
-	if (i < 0 || i >= NUMPLAYERSPRITES*2)
-		return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
+	if (i < 0 || i >= NUMPLAYERSPRITES)
+		return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
 
 	LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST);
 	return 1;
 }
 
-// #skin.sprites -> NUMPLAYERSPRITES*2
+// #skin.sprites -> NUMPLAYERSPRITES
 static int lib_numSkinsSprites(lua_State *L)
 {
-	lua_pushinteger(L, NUMPLAYERSPRITES*2);
+	lua_pushinteger(L, NUMPLAYERSPRITES);
 	return 1;
 }
 
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 36438a47575ab2028223245096424ad04b398119..07f10071711025f93f91d7b7ea2d9d65f3d5ad1d 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -1432,14 +1432,22 @@ void OP_ObjectplaceMovement(player_t *player)
 //
 // Objectplace related commands.
 //
-/*void Command_Writethings_f(void)
+void Command_Writethings_f(void)
 {
 	REQUIRE_INLEVEL;
 	REQUIRE_SINGLEPLAYER;
 	REQUIRE_OBJECTPLACE;
 
-	P_WriteThings();
-}*/
+	if (COM_Argc() > 1)
+	{
+		P_WriteThings(COM_Argv(1));
+	}
+	else
+	{
+		CONS_Printf(M_GetText("writethings <filename>: write out map things to a file, .txt or .lmp automatically appended.\n"));
+		return;
+	}
+}
 
 void Command_ObjectPlace_f(void)
 {
diff --git a/src/m_cheat.h b/src/m_cheat.h
index f4ac01d842eba583da08a2d1634bd09ad11f1b84..564c6da77ff7e0761faaff529ac4ed7a87ff3734 100644
--- a/src/m_cheat.h
+++ b/src/m_cheat.h
@@ -26,7 +26,7 @@ void cht_Init(void);
 // ObjectPlace
 //
 void Command_ObjectPlace_f(void);
-//void Command_Writethings_f(void);
+void Command_Writethings_f(void);
 
 extern consvar_t cv_opflags, cv_ophoopflags, cv_mapthingnum, cv_speed;
 //extern consvar_t cv_snapto, cv_grid;
diff --git a/src/m_menu.c b/src/m_menu.c
index 3c6ef0fe3a145837ef1401603b99d8e321ee1b97..4d8ee17e8a50c582b910a1748d741997515d9457 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -184,6 +184,9 @@ static fixed_t char_scroll = 0;
 
 static tic_t keydown = 0;
 
+// Lua
+static huddrawlist_h luahuddrawlist_playersetup;
+
 //
 // PROTOTYPES
 //
@@ -1068,9 +1071,9 @@ static menuitem_t OP_ChangeControlsMenu[] =
 	{IT_CALL | IT_STRING2, NULL, "Move Backward",    M_ChangeControl, GC_BACKWARD    },
 	{IT_CALL | IT_STRING2, NULL, "Move Left",        M_ChangeControl, GC_STRAFELEFT  },
 	{IT_CALL | IT_STRING2, NULL, "Move Right",       M_ChangeControl, GC_STRAFERIGHT },
-	{IT_CALL | IT_STRING2, NULL, "Jump",             M_ChangeControl, GC_JUMP      },
-	{IT_CALL | IT_STRING2, NULL, "Spin",             M_ChangeControl, GC_SPIN     },
-	{IT_CALL | IT_STRING2, NULL, "Shield",           M_ChangeControl, GC_SHIELD    },
+	{IT_CALL | IT_STRING2, NULL, "Jump",             M_ChangeControl, GC_JUMP        },
+	{IT_CALL | IT_STRING2, NULL, "Spin",             M_ChangeControl, GC_SPIN        },
+	{IT_CALL | IT_STRING2, NULL, "Shield Ability",   M_ChangeControl, GC_SHIELD      },
 	{IT_HEADER, NULL, "Camera", NULL, 0},
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
 	{IT_CALL | IT_STRING2, NULL, "Look Up",        M_ChangeControl, GC_LOOKUP      },
@@ -1119,13 +1122,15 @@ static menuitem_t OP_ChangeControlsMenu[] =
 
 static menuitem_t OP_Joystick1Menu[] =
 {
-	{IT_STRING | IT_CALL,  NULL, "Select Gamepad...", M_Setup1PJoystickMenu, 10},
-	{IT_STRING | IT_CVAR,  NULL, "Move \x17 Axis"    , &cv_moveaxis         , 30},
-	{IT_STRING | IT_CVAR,  NULL, "Move \x18 Axis"    , &cv_sideaxis         , 40},
-	{IT_STRING | IT_CVAR,  NULL, "Camera \x17 Axis"  , &cv_lookaxis         , 50},
-	{IT_STRING | IT_CVAR,  NULL, "Camera \x18 Axis"  , &cv_turnaxis         , 60},
-	{IT_STRING | IT_CVAR,  NULL, "Jump Axis"         , &cv_jumpaxis         , 70},
-	{IT_STRING | IT_CVAR,  NULL, "Spin Axis"         , &cv_spinaxis         , 80},
+	{IT_STRING | IT_CALL,  NULL, "Select Gamepad...", M_Setup1PJoystickMenu,  0},
+
+	{IT_STRING | IT_CVAR,  NULL, "Move \x17 Axis"    , &cv_moveaxis         , 20},
+	{IT_STRING | IT_CVAR,  NULL, "Move \x18 Axis"    , &cv_sideaxis         , 30},
+	{IT_STRING | IT_CVAR,  NULL, "Camera \x17 Axis"  , &cv_lookaxis         , 40},
+	{IT_STRING | IT_CVAR,  NULL, "Camera \x18 Axis"  , &cv_turnaxis         , 50},
+	{IT_STRING | IT_CVAR,  NULL, "Jump Axis"         , &cv_jumpaxis         , 60},
+	{IT_STRING | IT_CVAR,  NULL, "Spin Axis"         , &cv_spinaxis         , 70},
+	{IT_STRING | IT_CVAR,  NULL, "Shield Axis"       , &cv_shieldaxis       , 80},
 	{IT_STRING | IT_CVAR,  NULL, "Fire Axis"         , &cv_fireaxis         , 90},
 	{IT_STRING | IT_CVAR,  NULL, "Fire Normal Axis"  , &cv_firenaxis        ,100},
 
@@ -1137,13 +1142,15 @@ static menuitem_t OP_Joystick1Menu[] =
 
 static menuitem_t OP_Joystick2Menu[] =
 {
-	{IT_STRING | IT_CALL,  NULL, "Select Gamepad...", M_Setup2PJoystickMenu, 10},
-	{IT_STRING | IT_CVAR,  NULL, "Move \x17 Axis"    , &cv_moveaxis2        , 30},
-	{IT_STRING | IT_CVAR,  NULL, "Move \x18 Axis"    , &cv_sideaxis2        , 40},
-	{IT_STRING | IT_CVAR,  NULL, "Camera \x17 Axis"  , &cv_lookaxis2        , 50},
-	{IT_STRING | IT_CVAR,  NULL, "Camera \x18 Axis"  , &cv_turnaxis2        , 60},
-	{IT_STRING | IT_CVAR,  NULL, "Jump Axis"         , &cv_jumpaxis2        , 70},
-	{IT_STRING | IT_CVAR,  NULL, "Spin Axis"         , &cv_spinaxis2        , 80},
+	{IT_STRING | IT_CALL,  NULL, "Select Gamepad...", M_Setup2PJoystickMenu,  0},
+
+	{IT_STRING | IT_CVAR,  NULL, "Move \x17 Axis"    , &cv_moveaxis2        , 20},
+	{IT_STRING | IT_CVAR,  NULL, "Move \x18 Axis"    , &cv_sideaxis2        , 30},
+	{IT_STRING | IT_CVAR,  NULL, "Camera \x17 Axis"  , &cv_lookaxis2        , 40},
+	{IT_STRING | IT_CVAR,  NULL, "Camera \x18 Axis"  , &cv_turnaxis2        , 50},
+	{IT_STRING | IT_CVAR,  NULL, "Jump Axis"         , &cv_jumpaxis2        , 60},
+	{IT_STRING | IT_CVAR,  NULL, "Spin Axis"         , &cv_spinaxis2        , 70},
+	{IT_STRING | IT_CVAR,  NULL, "Shield Axis"       , &cv_shieldaxis2      , 80},
 	{IT_STRING | IT_CVAR,  NULL, "Fire Axis"         , &cv_fireaxis2        , 90},
 	{IT_STRING | IT_CVAR,  NULL, "Fire Normal Axis"  , &cv_firenaxis2       ,100},
 
@@ -2095,6 +2102,12 @@ menu_t OP_PlaystyleDef = {
 	0, 0, 0, NULL
 };
 
+static void M_UpdateItemOn(void)
+{
+	I_SetTextInputMode((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING ||
+		(currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER);
+}
+
 static void M_VideoOptions(INT32 choice)
 {
 	(void)choice;
@@ -2322,6 +2335,7 @@ void Nextmap_OnChange(void)
 		{
 			currentMenu->lastOn = itemOn;
 			itemOn = nastart;
+			M_UpdateItemOn();
 		}
 	}
 	else if (currentMenu == &SP_TimeAttackDef)
@@ -2371,6 +2385,7 @@ void Nextmap_OnChange(void)
 		{
 			currentMenu->lastOn = itemOn;
 			itemOn = tastart;
+			M_UpdateItemOn();
 		}
 
 		if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0')
@@ -2692,7 +2707,7 @@ static boolean MIT_SetCurTitlePics(UINT32 menutype, INT32 level, INT32 *retval,
 			curhidepics = menupres[menutype].hidetitlepics;
 			curttmode = menupres[menutype].ttmode;
 			curttscale = (menupres[menutype].ttscale != UINT8_MAX ? menupres[menutype].ttscale : ttscale);
-			strncpy(curttname, menupres[menutype].ttname, 9);
+			strncpy(curttname, menupres[menutype].ttname, sizeof(curttname)-1);
 			curttx = (menupres[menutype].ttx != INT16_MAX ? menupres[menutype].ttx : ttx);
 			curtty = (menupres[menutype].tty != INT16_MAX ? menupres[menutype].tty : tty);
 			curttloop = (menupres[menutype].ttloop != INT16_MAX ? menupres[menutype].ttloop : ttloop);
@@ -3121,6 +3136,7 @@ static void M_NextOpt(void)
 		else
 			itemOn++;
 	} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
+	M_UpdateItemOn();
 }
 
 static void M_PrevOpt(void)
@@ -3133,6 +3149,7 @@ static void M_PrevOpt(void)
 		else
 			itemOn--;
 	} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
+	M_UpdateItemOn();
 }
 
 // lock out further input in a tic when important buttons are pressed
@@ -3426,7 +3443,7 @@ boolean M_Responder(event_t *ev)
 			// ignore ev_keydown events if the key maps to a character, since
 			// the ev_text event will follow immediately after in that case.
 			if (ev->type == ev_keydown && ch >= 32 && ch <= 127)
-				return false;
+				return true;
 
 			if (M_ChangeStringCvar(ch))
 				return true;
@@ -3644,12 +3661,14 @@ void M_StartControlPanel(void)
 
 		currentMenu = &MainDef;
 		itemOn = singleplr;
+		M_UpdateItemOn();
 	}
 	else if (modeattacking)
 	{
 		currentMenu = &MAPauseDef;
 		MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 		itemOn = mapause_continue;
+		M_UpdateItemOn();
 	}
 	else if (!(netgame || multiplayer)) // Single Player
 	{
@@ -3696,6 +3715,7 @@ void M_StartControlPanel(void)
 
 		currentMenu = &SPauseDef;
 		itemOn = spause_continue;
+		M_UpdateItemOn();
 	}
 	else // multiplayer
 	{
@@ -3737,6 +3757,7 @@ void M_StartControlPanel(void)
 
 		currentMenu = &MPauseDef;
 		itemOn = mpause_continue;
+		M_UpdateItemOn();
 	}
 
 	CON_ToggleOff(); // move away console
@@ -3830,6 +3851,7 @@ void M_SetupNextMenu(menu_t *menudef)
 			}
 		}
 	}
+	M_UpdateItemOn();
 
 	hidetitlemap = false;
 }
@@ -4099,53 +4121,6 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines)
 {
 	// Solid color textbox.
 	V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 159);
-	//V_DrawFill(x+8, y+8, width*8, boxlines*8, 31);
-/*
-	patch_t *p;
-	INT32 cx, cy, n;
-	INT32 step, boff;
-
-	step = 8;
-	boff = 8;
-
-	// draw left side
-	cx = x;
-	cy = y;
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TL], PU_PATCH));
-	cy += boff;
-	p = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH);
-	for (n = 0; n < boxlines; n++)
-	{
-		V_DrawScaledPatch(cx, cy, 0, p);
-		cy += step;
-	}
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_PATCH));
-
-	// draw middle
-	V_DrawFlatFill(x + boff, y + boff, width*step, boxlines*step, st_borderpatchnum);
-
-	cx += boff;
-	cy = y;
-	while (width > 0)
-	{
-		V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH));
-		V_DrawScaledPatch(cx, y + boff + boxlines*step, 0, W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH));
-		width--;
-		cx += step;
-	}
-
-	// draw right side
-	cy = y;
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TR], PU_PATCH));
-	cy += boff;
-	p = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH);
-	for (n = 0; n < boxlines; n++)
-	{
-		V_DrawScaledPatch(cx, cy, 0, p);
-		cy += step;
-	}
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_PATCH));
-*/
 }
 
 //
@@ -4999,22 +4974,6 @@ static void M_DrawCenteredMenu(void)
 	}
 }
 
-//
-// M_StringHeight
-//
-// Find string height from hu_font chars
-//
-static inline size_t M_StringHeight(const char *string)
-{
-	size_t h = 8, i;
-
-	for (i = 0; i < strlen(string); i++)
-		if (string[i] == '\n')
-			h += 8;
-
-	return h;
-}
-
 // ==========================================================================
 // Extraneous menu patching functions
 // ==========================================================================
@@ -6132,56 +6091,16 @@ menu_t MessageDef =
 	NULL
 };
 
-
-void M_StartMessage(const char *string, void *routine,
-	menumessagetype_t itemtype)
+void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype)
 {
-	size_t max = 0, start = 0, i, strlines;
-	static char *message = NULL;
+	static char *message;
 	Z_Free(message);
-	message = Z_StrDup(string);
+	message = V_WordWrap(0,0,V_ALLOWLOWERCASE,string);
 	DEBFILE(message);
 
-	// Rudementary word wrapping.
-	// Simple and effective. Does not handle nonuniform letter sizes, colors, etc. but who cares.
-	strlines = 0;
-	for (i = 0; message[i]; i++)
-	{
-		if (message[i] == ' ')
-		{
-			start = i;
-			max += 4;
-		}
-		else if (message[i] == '\n')
-		{
-			strlines = i;
-			start = 0;
-			max = 0;
-			continue;
-		}
-		else
-			max += 8;
-
-		// Start trying to wrap if presumed length exceeds the screen width.
-		if (max >= BASEVIDWIDTH && start > 0)
-		{
-			message[start] = '\n';
-			max -= (start-strlines)*8;
-			strlines = start;
-			start = 0;
-		}
-	}
-
-	start = 0;
-	max = 0;
-
 	M_StartControlPanel(); // can't put menuactive to true
 
-	if (currentMenu == &MessageDef) // Prevent recursion
-		MessageDef.prevMenu = &MainDef;
-	else
-		MessageDef.prevMenu = currentMenu;
-
+	MessageDef.prevMenu = (currentMenu == &MessageDef) ? &MainDef : currentMenu; // Prevent recursion
 	MessageDef.menuitems[0].text     = message;
 	MessageDef.menuitems[0].alphaKey = (UINT8)itemtype;
 	if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING;
@@ -6200,51 +6119,18 @@ void M_StartMessage(const char *string, void *routine,
 			MessageDef.menuitems[0].itemaction = routine;
 			break;
 	}
-	//added : 06-02-98: now draw a textbox around the message
-	// compute lenght max and the numbers of lines
-	for (strlines = 0; *(message+start); strlines++)
-	{
-		for (i = 0;i < strlen(message+start);i++)
-		{
-			if (*(message+start+i) == '\n')
-			{
-				if (i > max)
-					max = i;
-				start += i;
-				i = (size_t)-1; //added : 07-02-98 : damned!
-				start++;
-				break;
-			}
-		}
-
-		if (i == strlen(message+start))
-			start += i;
-	}
-
-	MessageDef.x = (INT16)((BASEVIDWIDTH  - 8*max-16)/2);
-	MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2);
-
-	MessageDef.lastOn = (INT16)((strlines<<8)+max);
+	MessageDef.x = (INT16)((BASEVIDWIDTH  - V_StringWidth(message, 0)-32)/2);
+	MessageDef.y = (INT16)((BASEVIDHEIGHT - V_StringHeight(message, V_RETURN8))/2);
 
-	//M_SetupNextMenu();
 	currentMenu = &MessageDef;
 	itemOn = 0;
+	M_UpdateItemOn();
 }
 
-#define MAXMSGLINELEN 256
-
 static void M_DrawMessageMenu(void)
 {
-	INT32 y = currentMenu->y;
-	size_t i, start = 0;
-	INT16 max;
-	char string[MAXMSGLINELEN];
-	INT32 mlines;
 	const char *msg = currentMenu->menuitems[0].text;
 
-	mlines = currentMenu->lastOn>>8;
-	max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
-
 	// hack: draw RA background in RA menus
 	if (gamestate == GS_TIMEATTACK)
 	{
@@ -6268,51 +6154,8 @@ static void M_DrawMessageMenu(void)
 			V_DrawFadeScreen(0xFF00, curfadevalue);
 	}
 
-	M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
-
-	while (*(msg+start))
-	{
-		size_t len = strlen(msg+start);
-
-		for (i = 0; i < len; i++)
-		{
-			if (*(msg+start+i) == '\n')
-			{
-				memset(string, 0, MAXMSGLINELEN);
-				if (i >= MAXMSGLINELEN)
-				{
-					CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
-					return;
-				}
-				else
-				{
-					strncpy(string,msg+start, i);
-					string[i] = '\0';
-					start += i;
-					i = (size_t)-1; //added : 07-02-98 : damned!
-					start++;
-				}
-				break;
-			}
-		}
-
-		if (i == strlen(msg+start))
-		{
-			if (i >= MAXMSGLINELEN)
-			{
-				CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
-				return;
-			}
-			else
-			{
-				strcpy(string, msg + start);
-				start += i;
-			}
-		}
-
-		V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string);
-		y += 8; //hu_font[0]->height;
-	}
+	M_DrawTextBox(currentMenu->x, currentMenu->y - 8, 2+V_StringWidth(msg, 0)/8, V_StringHeight(msg, V_RETURN8)/8);
+	V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, V_ALLOWLOWERCASE|V_RETURN8, msg);
 }
 
 // default message handler
@@ -6356,6 +6199,7 @@ static void M_HandleImageDef(INT32 choice)
 			if (itemOn >= (INT16)(currentMenu->numitems-1))
 				itemOn = 0;
             else itemOn++;
+			M_UpdateItemOn();
 			break;
 
 		case KEY_LEFTARROW:
@@ -6366,6 +6210,7 @@ static void M_HandleImageDef(INT32 choice)
 			if (!itemOn)
 				itemOn = currentMenu->numitems - 1;
 			else itemOn--;
+			M_UpdateItemOn();
 			break;
 
 		case KEY_ESCAPE:
@@ -7562,6 +7407,7 @@ static void M_EmblemHints(INT32 choice)
 	SR_EmblemHintDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&SR_EmblemHintDef);
 	itemOn = 2; // always start on back.
+	M_UpdateItemOn();
 }
 
 static void M_DrawEmblemHints(void)
@@ -7999,7 +7845,7 @@ static void M_DrawSoundTest(void)
 				{
 					V_DrawFill(165+140-9, y-4, 8, 16, 150);
 					//V_DrawCharacter(165+140-8, y, '\x19' | V_YELLOWMAP, false);
-					V_DrawFixedPatch((165+140-9)<<FRACBITS, (y<<FRACBITS)-(bounce*4), FRACUNIT, 0, hu_font['\x19'-HU_FONTSTART], V_GetStringColormap(V_YELLOWMAP));
+					V_DrawFixedPatch((165+140-9)<<FRACBITS, (y<<FRACBITS)-(bounce*4), FRACUNIT, 0, hu_font.chars['\x19'-FONTSTART], V_GetStringColormap(V_YELLOWMAP));
 				}
 			}
 			t++;
@@ -10223,6 +10069,7 @@ static void M_TimeAttack(INT32 choice)
 		Nextmap_OnChange();
 
 	itemOn = tastart; // "Start" is selected.
+	M_UpdateItemOn();
 }
 
 // Drawing function for Nights Attack
@@ -10461,6 +10308,7 @@ static void M_NightsAttack(INT32 choice)
 		Nextmap_OnChange();
 
 	itemOn = nastart; // "Start" is selected.
+	M_UpdateItemOn();
 }
 
 // Player has selected the "START" from the nights attack screen
@@ -10780,6 +10628,7 @@ static void M_ModeAttackEndGame(INT32 choice)
 		break;
 	}
 	itemOn = currentMenu->lastOn;
+	M_UpdateItemOn();
 	G_SetGamestate(GS_TIMEATTACK);
 	modeattacking = ATTACKING_NONE;
 	M_ChangeMenuMusic("_title", true);
@@ -10861,6 +10710,7 @@ static void M_Marathon(INT32 choice)
 	titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
 	M_SetupNextMenu(&SP_MarathonDef);
 	itemOn = marathonstart; // "Start" is selected.
+	M_UpdateItemOn();
 	recatkdrawtimer = (50-8) * FRACUNIT;
 	char_scroll = 0;
 }
@@ -11282,7 +11132,8 @@ static void M_DrawRoomMenu(void)
 			if (dot_frame < 0)
 				dot_frame = 0;
 
-			strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
+			if (dot_frame != 3)
+				strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
 		}
 
 		frame += renderdeltatics;
@@ -11573,6 +11424,7 @@ static void M_ConnectMenu(INT32 choice)
 	else
 		M_SetupNextMenu(&MP_ConnectDef);
 	itemOn = 0;
+	M_UpdateItemOn();
 	M_Refresh(0);
 }
 
@@ -11832,6 +11684,7 @@ static void M_StartServerMenu(INT32 choice)
 	Newgametype_OnChange();
 	M_SetupNextMenu(&MP_ServerDef);
 	itemOn = 1;
+	M_UpdateItemOn();
 }
 
 // ==============
@@ -12014,15 +11867,21 @@ static void M_HandleConnectIP(INT32 choice)
 					case KEY_INS:
 					case 'c':
 					case 'C': // ctrl+c, ctrl+insert, copying
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+						}
 						break;
 
 					case 'x':
 					case 'X': // ctrl+x, cutting
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
-						setupm_ip[0] = 0;
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+							setupm_ip[0] = 0;
+						}
 						break;
 
 					default: // otherwise do nothing
@@ -12046,9 +11905,12 @@ static void M_HandleConnectIP(INT32 choice)
 							break;
 						}
 					case KEY_DEL: // shift+delete, cutting
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
-						setupm_ip[0] = 0;
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+							setupm_ip[0] = 0;
+						}
 						break;
 					default: // otherwise do nothing.
 						break;
@@ -12098,9 +11960,22 @@ static void M_HandleConnectIP(INT32 choice)
 
 static fixed_t    multi_tics;
 static UINT8      multi_frame;
-static UINT8      multi_spr2;
+static UINT16     multi_spr2;
 static boolean    multi_paused;
 static boolean    multi_invcolor;
+static boolean    multi_override;
+
+static spritedef_t *multi_followitem_sprdef;
+static INT32        multi_followitem_skinnum;
+static UINT8        multi_followitem_numframes;
+static UINT8        multi_followitem_startframe;
+static UINT8        multi_followitem_frame;
+static fixed_t      multi_followitem_duration;
+static fixed_t      multi_followitem_tics;
+static fixed_t      multi_followitem_scale;
+static fixed_t      multi_followitem_yoffset;
+
+#define MULTI_DURATION (4*FRACUNIT)
 
 // this is set before entering the MultiPlayer setup menu,
 // for either player 1 or 2
@@ -12245,9 +12120,92 @@ static menucolor_t *M_GridIndexToMenuColor(UINT16 index)
 	}
 }
 
+static void M_SetPlayerSetupFollowItem(void)
+{
+	const mobjtype_t followitem = skins[setupm_fakeskin]->followitem;
+
+	switch (followitem)
+	{
+		case MT_TAILSOVERLAY:
+		{
+			const state_t *state = &states[S_TAILSOVERLAY_MINUS30DEGREES];
+			const UINT8 sprite2 = P_GetSkinSprite2(skins[setupm_fakeskin], state->frame & FF_FRAMEMASK, NULL);
+
+			if (state->sprite != SPR_PLAY)
+				break;
+
+			multi_followitem_sprdef = &skins[setupm_fakeskin]->sprites[sprite2];
+			multi_followitem_skinnum = setupm_fakeskin;
+			multi_followitem_numframes = multi_followitem_sprdef->numframes;
+			multi_followitem_startframe = 0;
+			multi_followitem_frame = multi_frame;
+			multi_followitem_duration = MULTI_DURATION;
+			multi_followitem_tics = multi_tics;
+			multi_followitem_scale = FRACUNIT;
+			multi_followitem_yoffset = 0;
+
+			if ((state->frame & FF_SPR2MIDSTART) && (multi_followitem_numframes > 0) && M_RandomChance(FRACUNIT / 2))
+			{
+				multi_followitem_frame += multi_followitem_numframes / 2;
+			}
+			break;
+		}
+		case MT_METALJETFUME:
+		{
+			const state_t *state = &states[S_JETFUME1];
+
+			if (!(state->frame & FF_ANIMATE))
+				break;
+
+			multi_followitem_sprdef = &sprites[state->sprite];
+			multi_followitem_skinnum = TC_DEFAULT;
+			multi_followitem_numframes = state->var1 + 1;
+			multi_followitem_startframe = state->frame & FF_FRAMEMASK;
+			multi_followitem_frame = multi_followitem_startframe;
+			multi_followitem_duration = state->var2 * FRACUNIT;
+			multi_followitem_tics = multi_tics % multi_followitem_duration;
+			multi_followitem_scale = 2 * FRACUNIT / 3;
+			multi_followitem_yoffset = (skins[setupm_fakeskin]->height - FixedMul(mobjinfo[followitem].height, multi_followitem_scale)) >> 1;
+			break;
+		}
+		default:
+			multi_followitem_sprdef = NULL;
+			break;
+	}
+}
+
+static void M_DrawPlayerSetupFollowItem(INT32 x, INT32 y, fixed_t scale, INT32 flags)
+{
+	spriteframe_t *sprframe;
+	patch_t *patch;
+	UINT8 *colormap;
+
+	if (multi_followitem_sprdef == NULL)
+		return;
+
+	if (multi_followitem_frame >= multi_followitem_startframe + multi_followitem_numframes)
+		multi_followitem_frame = multi_followitem_startframe;
+
+	colormap = R_GetTranslationColormap(multi_followitem_skinnum, setupm_fakecolor->color, GTC_CACHE);
+
+	sprframe = &multi_followitem_sprdef->spriteframes[multi_followitem_frame];
+	patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
+	if (sprframe->flip & 1) // Only for first sprite
+		flags |= V_FLIP; // This sprite is left/right flipped!
+
+	x <<= FRACBITS;
+	y <<= FRACBITS;
+	y -= FixedMul(multi_followitem_yoffset, scale);
+
+	scale = FixedMul(scale, multi_followitem_scale);
+
+	V_DrawFixedPatch(x, y, scale, flags, patch, colormap);
+}
+
 static void M_DrawSetupMultiPlayerMenu(void)
 {
 	INT32 x, y, cursory = 0, flags = 0;
+	fixed_t scale;
 	spritedef_t *sprdef;
 	spriteframe_t *sprframe;
 	patch_t *patch;
@@ -12297,11 +12255,24 @@ static void M_DrawSetupMultiPlayerMenu(void)
 	y += 11;
 
 	// anim the player in the box
-	multi_tics -= renderdeltatics;
-	while (!multi_paused && multi_tics <= 0)
+	if (!multi_paused)
 	{
-		multi_frame++;
-		multi_tics += 4*FRACUNIT;
+		multi_tics -= renderdeltatics;
+		while (multi_tics <= 0)
+		{
+			multi_frame++;
+			multi_tics += MULTI_DURATION;
+		}
+
+		if (multi_followitem_sprdef != NULL)
+		{
+			multi_followitem_tics -= renderdeltatics;
+			while (multi_followitem_tics <= 0)
+			{
+				multi_followitem_frame++;
+				multi_followitem_tics += multi_followitem_duration;
+			}
+		}
 	}
 
 #define charw 74
@@ -12316,17 +12287,38 @@ static void M_DrawSetupMultiPlayerMenu(void)
 		goto faildraw;
 
 	// ok, draw player sprite for sure now
-	colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_CACHE);
-
 	if (multi_frame >= sprdef->numframes)
 		multi_frame = 0;
 
+	scale = FixedDiv(skins[setupm_fakeskin]->highresscale, skins[setupm_fakeskin]->shieldscale);
+
+#define chary (y+64)
+
+	if (renderisnewtic)
+	{
+		LUA_HUD_ClearDrawList(luahuddrawlist_playersetup);
+		multi_override = LUA_HookCharacterHUD
+		(
+			HUD_HOOK(playersetup), luahuddrawlist_playersetup, setupm_player,
+			x << FRACBITS, chary << FRACBITS, scale,
+			setupm_fakeskin, multi_spr2, multi_frame, 1, setupm_fakecolor->color,
+			(multi_tics >> FRACBITS) + 1, multi_paused
+		);
+	}
+
+	LUA_HUD_DrawList(luahuddrawlist_playersetup);
+
+	if (multi_override == true)
+		goto colordraw;
+
+	colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_CACHE);
+
 	sprframe = &sprdef->spriteframes[multi_frame];
 	patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
 	if (sprframe->flip & 1) // Only for first sprite
 		flags |= V_FLIP; // This sprite is left/right flipped!
 
-#define chary (y+64)
+	M_DrawPlayerSetupFollowItem(x, chary, scale, flags & ~V_FLIP);
 
 	V_DrawFixedPatch(
 		x<<FRACBITS,
@@ -12519,6 +12511,20 @@ static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t colo
 		V_DrawFill(x, y+(i*h), w, h, color.ramp[i]);
 }
 
+static void M_InitPlayerSetupLua(void)
+{
+	// I'd really like to assume that the drawlist has been destroyed,
+	// but it appears M_ClearMenus has options not to call exit routines...
+	// so that doesn't seem safe to me??
+	if (!LUA_HUD_IsDrawListValid(luahuddrawlist_playersetup))
+	{
+		LUA_HUD_DestroyDrawList(luahuddrawlist_playersetup);
+		luahuddrawlist_playersetup = LUA_HUD_CreateDrawList();
+	}
+	LUA_HUD_ClearDrawList(luahuddrawlist_playersetup);
+	multi_override = false;
+}
+
 // Handle 1P/2P MP Setup
 static void M_HandleSetupMultiPlayer(INT32 choice)
 {
@@ -12564,6 +12570,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
 				}
 				while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin)));
 				multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+				M_SetPlayerSetupFollowItem();
 			}
 			else if (itemOn == 2) // player color
 			{
@@ -12604,6 +12611,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
 				}
 				while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin)));
 				multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+				M_SetPlayerSetupFollowItem();
 			}
 			else if (itemOn == 2) // player color
 			{
@@ -12724,7 +12732,7 @@ static void M_SetupMultiPlayer(INT32 choice)
 	(void)choice;
 
 	multi_frame = 0;
-	multi_tics = 4*FRACUNIT;
+	multi_tics = MULTI_DURATION;
 
 	strcpy(setupm_name, cv_playername.string);
 
@@ -12754,6 +12762,10 @@ static void M_SetupMultiPlayer(INT32 choice)
 	MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
 
 	multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+	M_SetPlayerSetupFollowItem();
+
+	// allocate and/or clear Lua player setup draw list
+	M_InitPlayerSetupLua();
 
 	MP_PlayerSetupDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&MP_PlayerSetupDef);
@@ -12765,7 +12777,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
 	(void)choice;
 
 	multi_frame = 0;
-	multi_tics = 4*FRACUNIT;
+	multi_tics = MULTI_DURATION;
 
 	strcpy (setupm_name, cv_playername2.string);
 
@@ -12795,6 +12807,10 @@ static void M_SetupMultiPlayer2(INT32 choice)
 	MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
 
 	multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+	M_SetPlayerSetupFollowItem();
+
+	// allocate and/or clear Lua player setup draw list
+	M_InitPlayerSetupLua();
 
 	MP_PlayerSetupDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&MP_PlayerSetupDef);
@@ -12816,6 +12832,12 @@ static boolean M_QuitMultiPlayerMenu(void)
 	// send color if changed
 	if (setupm_fakecolor->color != setupm_cvcolor->value)
 		COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor->color));
+
+	// de-allocate Lua player setup drawlist
+	LUA_HUD_DestroyDrawList(luahuddrawlist_playersetup);
+	luahuddrawlist_playersetup = NULL;
+	multi_override = false;
+
 	return true;
 }
 
@@ -13083,7 +13105,10 @@ static void M_SetupScreenshotMenu(void)
 	{
 		item->status = IT_GRAYEDOUT;
 		if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that
+		{
 			itemOn = op_screenshot_storagelocation;
+			M_UpdateItemOn();
+		}
 	}
 	else
 #endif
@@ -13673,23 +13698,14 @@ static void M_VideoModeMenu(INT32 choice)
 
 	memset(modedescs, 0, sizeof(modedescs));
 
-#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)
 	VID_PrepareModeList(); // FIXME: hack
-#endif
+
 	vidm_nummodes = 0;
 	vidm_selected = 0;
 	nummodes = VID_NumModes();
 
-#ifdef _WINDOWS
-	// clean that later: skip windowed mode 0, video modes menu only shows FULL SCREEN modes
-	if (nummodes <= NUMSPECIALMODES)
-		i = 0; // unless we have nothing
-	else
-		i = NUMSPECIALMODES;
-#else
-	// DOS does not skip mode 0, because mode 0 is ALWAYS present
 	i = 0;
-#endif
+
 	for (; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++)
 	{
 		desc = VID_GetModeName(i);
diff --git a/src/m_menu.h b/src/m_menu.h
index 3cd2f66d37c78a2c6d7c6e14ff4e48c3f9cc56ec..99a5b6de4266be02b1cba0e98a26addac5524548 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -378,7 +378,7 @@ typedef struct
 	char displayname[SKINNAMESIZE+1];
 	INT16 skinnum[2];
 	UINT16 oppositecolor;
-	char nametag[8];
+	char nametag[8+1];
 	patch_t *namepic;
 	UINT16 tagtextcolor;
 	UINT16 tagoutlinecolor;
diff --git a/src/m_misc.c b/src/m_misc.c
index 55c5485a149a2b2c43e48fab973c5ad898091036..a60bbea98d2e2b47cf3fea0dae652d26b6aa4763 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2208,6 +2208,8 @@ int M_JumpWordReverse(const char *line, int offset)
 {
 	int (*is)(int);
 	int c;
+	if (offset == 0) // Don't let "--offset" later result in a negative value
+		return 0;
 	c = line[--offset];
 	if (isspace(c))
 		is = isspace;
diff --git a/src/netcode/client_connection.c b/src/netcode/client_connection.c
index 36ed718265b3cfa42acc3ef238c436882bb918a1..917e32b598e03d86f8540b997329069f279817fb 100644
--- a/src/netcode/client_connection.c
+++ b/src/netcode/client_connection.c
@@ -307,7 +307,7 @@ boolean CL_SendJoin(void)
 	else
 		player2name = cv_playername2.zstring;
 
-	strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME);
+	strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, sizeof(netbuffer->u.clientcfg.names[0])-1);
 	strncpy(netbuffer->u.clientcfg.names[1], player2name, MAXPLAYERNAME);
 
 	return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak));
diff --git a/src/netcode/commands.c b/src/netcode/commands.c
index 46dfbc741d9c8f036bf53e0ba6d77bed60ac39f3..f3bbc8a8616224b65a481559bd96eccbb3577f5e 100644
--- a/src/netcode/commands.c
+++ b/src/netcode/commands.c
@@ -41,6 +41,8 @@ typedef struct banreason_s
 static banreason_t *reasontail = NULL; //last entry, use prev
 static banreason_t *reasonhead = NULL; //1st entry, use next
 
+static boolean bans_loaded = false;
+
 void Ban_Add(const char *reason)
 {
 	banreason_t *reasonlist = malloc(sizeof(*reasonlist));
@@ -85,6 +87,8 @@ void Ban_Load_File(boolean warning)
 	if (!I_ClearBans)
 		return;
 
+	bans_loaded = true;
+
 	f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r");
 
 	if (!f)
@@ -124,6 +128,12 @@ void D_SaveBan(void)
 	const char *address, *mask;
 	const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt");
 
+	if (!bans_loaded)
+	{
+		// don't save bans if they were never loaded.
+		return;
+	}
+
 	if (!reasonhead)
 	{
 		remove(path);
diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c
index d735e8132172e66a5c808ef572b7edca1ae8a8cc..2bf9d2dde7cb60266687282748142af5e676c917 100644
--- a/src/netcode/d_clisrv.c
+++ b/src/netcode/d_clisrv.c
@@ -1362,7 +1362,7 @@ static void IdleUpdate(void)
 
 	for (i = 1; i < MAXPLAYERS; i++)
 	{
-		if (cv_idletime.value && playeringame[i] && playernode[i] != UINT8_MAX && !players[i].quittime && !players[i].spectator && !players[i].bot && !IsPlayerAdmin(i) && i != serverplayer)
+		if (cv_idletime.value && playeringame[i] && playernode[i] != UINT8_MAX && !players[i].quittime && !players[i].spectator && !players[i].bot && !IsPlayerAdmin(i) && i != serverplayer && gamestate == GS_LEVEL)
 		{
 			if (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons)
 				players[i].lastinputtime = 0;
diff --git a/src/netcode/d_net.c b/src/netcode/d_net.c
index 5a2e229d3f47c9eadf66729a1250a1d2b0719343..b24409db158909970a73fb5bd7630500a4f3d63f 100644
--- a/src/netcode/d_net.c
+++ b/src/netcode/d_net.c
@@ -940,7 +940,7 @@ void Command_Droprate(void)
 static boolean ShouldDropPacket(void)
 {
 	return (packetdropquantity[netbuffer->packettype])
-		|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
+		|| (packetdroprate != 0 && rand() < (((double)RAND_MAX) * (packetdroprate / 100.f))) || packetdroprate == 100;
 }
 #endif
 
diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c
index 66a30637f301942b0b78dc762b1f9c8f9a15916f..e073a863c90bbe88025fd6f7ed9f4d0decac23d0 100644
--- a/src/netcode/d_netcmd.c
+++ b/src/netcode/d_netcmd.c
@@ -149,6 +149,10 @@ static void Command_Teamchange_f(void);
 static void Command_Teamchange2_f(void);
 static void Command_ServerTeamChange_f(void);
 
+static void Command_MutePlayer_f(void);
+static void Command_UnmutePlayer_f(void);
+static void Got_MutePlayer(UINT8 **cp, INT32 playernum);
+
 static void Command_Clearscores_f(void);
 
 // Remote Administration
@@ -209,6 +213,7 @@ static CV_PossibleValue_t matchboxes_cons_t[] = {{0, "Normal"}, {1, "Mystery"},
 static CV_PossibleValue_t chances_cons_t[] = {{0, "MIN"}, {9, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t pause_cons_t[] = {{0, "Server"}, {1, "All"}, {0, NULL}};
 
+consvar_t cv_showinput = CVAR_INIT ("showinput", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_showinputjoy = CVAR_INIT ("showinputjoy", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
 
 #ifdef NETGAME_DEVMODE
@@ -487,6 +492,10 @@ void D_RegisterServerCommands(void)
 	RegisterNetXCmd(XD_TEAMCHANGE, Got_Teamchange);
 	COM_AddCommand("serverchangeteam", Command_ServerTeamChange_f, COM_LUA);
 
+	RegisterNetXCmd(XD_MUTEPLAYER, Got_MutePlayer);
+	COM_AddCommand("muteplayer", Command_MutePlayer_f, COM_LUA);
+	COM_AddCommand("unmuteplayer", Command_UnmutePlayer_f, COM_LUA);
+
 	RegisterNetXCmd(XD_CLEARSCORES, Got_Clearscores);
 	COM_AddCommand("clearscores", Command_Clearscores_f, COM_LUA);
 	COM_AddCommand("map", Command_Map_f, COM_LUA);
@@ -662,6 +671,13 @@ void D_RegisterClientCommands(void)
 	for (i = 0; i < MAXPLAYERS; i++)
 		sprintf(player_names[i], "Player %d", 1 + i);
 
+	CV_RegisterVar(&cv_gravity);
+	CV_RegisterVar(&cv_tailspickup);
+	CV_RegisterVar(&cv_allowmlook);
+	CV_RegisterVar(&cv_flipcam);
+	CV_RegisterVar(&cv_flipcam2);
+	CV_RegisterVar(&cv_movebob);
+
 	if (dedicated)
 		return;
 
@@ -736,6 +752,7 @@ void D_RegisterClientCommands(void)
 	CV_RegisterVar(&cv_timetic);
 	CV_RegisterVar(&cv_powerupdisplay);
 	CV_RegisterVar(&cv_itemfinder);
+	CV_RegisterVar(&cv_showinput);
 	CV_RegisterVar(&cv_showinputjoy);
 
 	// time attack ghost options are also saved to config
@@ -805,6 +822,8 @@ void D_RegisterClientCommands(void)
 	CV_RegisterVar(&cv_jumpaxis2);
 	CV_RegisterVar(&cv_spinaxis);
 	CV_RegisterVar(&cv_spinaxis2);
+	CV_RegisterVar(&cv_shieldaxis);
+	CV_RegisterVar(&cv_shieldaxis2);
 	CV_RegisterVar(&cv_fireaxis);
 	CV_RegisterVar(&cv_fireaxis2);
 	CV_RegisterVar(&cv_firenaxis);
@@ -889,10 +908,6 @@ void D_RegisterClientCommands(void)
 
 	// screen.c
 	CV_RegisterVar(&cv_fullscreen);
-	CV_RegisterVar(&cv_renderview);
-	CV_RegisterVar(&cv_renderhitboxinterpolation);
-	CV_RegisterVar(&cv_renderhitboxgldepth);
-	CV_RegisterVar(&cv_renderhitbox);
 	CV_RegisterVar(&cv_renderer);
 	CV_RegisterVar(&cv_scr_depth);
 	CV_RegisterVar(&cv_scr_width);
@@ -908,13 +923,11 @@ void D_RegisterClientCommands(void)
 
 	// ingame object placing
 	COM_AddCommand("objectplace", Command_ObjectPlace_f, COM_LUA);
-	//COM_AddCommand("writethings", Command_Writethings_f);
+	COM_AddCommand("writethings", Command_Writethings_f, COM_LUA);
 	CV_RegisterVar(&cv_speed);
 	CV_RegisterVar(&cv_opflags);
 	CV_RegisterVar(&cv_ophoopflags);
 	CV_RegisterVar(&cv_mapthingnum);
-//	CV_RegisterVar(&cv_grid);
-//	CV_RegisterVar(&cv_snapto);
 
 	CV_RegisterVar(&cv_freedemocamera);
 
@@ -1310,7 +1323,7 @@ static void SendNameAndColor(void)
 		CV_StealthSet(&cv_playername, player_names[consoleplayer]);
 		HU_AddChatText("\x85*You must wait to change your name again", false);
 	}
-	else if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
+	else if ((cv_mute.value || players[consoleplayer].muted) && !(server || IsPlayerAdmin(consoleplayer)))
 		CV_StealthSet(&cv_playername, player_names[consoleplayer]);
 	else // Cleanup name if changing it
 		CleanupPlayerName(consoleplayer, cv_playername.zstring);
@@ -2485,6 +2498,91 @@ static void Command_Teamchange2_f(void)
 	SendNetXCmd2(XD_TEAMCHANGE, &usvalue, sizeof(usvalue));
 }
 
+static void MutePlayer(boolean mute)
+{
+	UINT8 data[2];
+	if (!(server || (IsPlayerAdmin(consoleplayer))))
+	{
+		CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
+		return;
+	}
+
+	if (COM_Argc() < 2)
+	{
+		CONS_Printf(M_GetText("muteplayer <playernum>: mute a player\n"));
+		return;
+	}
+
+	data[0] = atoi(COM_Argv(1));
+	if (data[0] >= MAXPLAYERS || !playeringame[data[0]])
+	{
+		CONS_Alert(CONS_NOTICE, M_GetText("There is no player %u!\n"), (unsigned int)data[0]);
+		return;
+	}
+
+	if (players[data[0]].muted && mute)
+	{
+		CONS_Printf(M_GetText("%s is already muted!\n"), player_names[data[0]]);
+		return;
+	}
+	else if (!players[data[0]].muted && !mute)
+	{
+		CONS_Printf(M_GetText("%s is not muted!\n"), player_names[data[0]]);
+		return;
+	}
+
+	data[1] = mute;
+	SendNetXCmd(XD_MUTEPLAYER, &data, sizeof(data));
+}
+
+static void Command_MutePlayer_f(void)
+{
+	MutePlayer(true);
+}
+
+static void Command_UnmutePlayer_f(void)
+{
+	MutePlayer(false);
+}
+
+static void Got_MutePlayer(UINT8 **cp, INT32 playernum)
+{
+	UINT8 player = READUINT8(*cp);
+	UINT8 muted = READUINT8(*cp);
+	if (playernum != serverplayer && !IsPlayerAdmin(playernum))
+	{
+		CONS_Alert(CONS_WARNING, M_GetText("Illegal mute received from player %s\n"), player_names[playernum]);
+		if (server)
+			SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
+		return;
+	}
+
+	if (player >= MAXPLAYERS || !playeringame[player])
+	{
+		CONS_Alert(CONS_WARNING, M_GetText("Illegal mute received from player %s\n"), player_names[playernum]);
+		if (server)
+			SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
+		return;
+	}
+
+	if (!players[player].muted && muted)
+	{
+		if (player == consoleplayer)
+			CONS_Printf(M_GetText("You have been muted.\n"));
+		else
+			CONS_Printf(M_GetText("%s has been muted.\n"), player_names[player]);
+	}
+	else if (players[player].muted && !muted)
+	{
+		if (player == consoleplayer)
+			CONS_Printf(M_GetText("You are no longer muted.\n"));
+		else
+			CONS_Printf(M_GetText("%s is no longer muted.\n"), player_names[player]);
+	}
+
+	players[player].muted = muted;
+}
+
 static void Command_ServerTeamChange_f(void)
 {
 	changeteam_union NetPacket;
@@ -4782,7 +4880,7 @@ static void ForceSkin_OnChange(void)
 //Allows the player's name to be changed if cv_mute is off.
 static void Name_OnChange(void)
 {
-	if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
+	if ((cv_mute.value || players[consoleplayer].muted) && !(server || IsPlayerAdmin(consoleplayer)))
 	{
 		CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n"));
 		CV_StealthSet(&cv_playername, player_names[consoleplayer]);
@@ -4793,7 +4891,7 @@ static void Name_OnChange(void)
 
 static void Name2_OnChange(void)
 {
-	if (cv_mute.value) //Secondary player can't be admin.
+	if (cv_mute.value || players[consoleplayer].muted) //Secondary player can't be admin.
 	{
 		CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n"));
 		CV_StealthSet(&cv_playername2, player_names[secondarydisplayplayer]);
diff --git a/src/netcode/d_netcmd.h b/src/netcode/d_netcmd.h
index e30fa4a0245b1dd2b54617b1f7df4f3700c75188..f92878a4e2e87efdae9c441ca30d61bcdb511ee5 100644
--- a/src/netcode/d_netcmd.h
+++ b/src/netcode/d_netcmd.h
@@ -94,7 +94,10 @@ extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_p
 extern consvar_t cv_overtime;
 extern consvar_t cv_startinglives;
 
-// for F_finale.c
+extern consvar_t cv_gravity, cv_movebob;
+extern consvar_t cv_tailspickup;
+
+// for f_finale.c
 extern consvar_t cv_rollingdemos;
 
 extern consvar_t cv_ringslinger, cv_soundtest;
@@ -105,7 +108,6 @@ extern consvar_t cv_maxping;
 extern consvar_t cv_pingtimeout;
 extern consvar_t cv_showping;
 
-
 extern consvar_t cv_skipmapcheck;
 
 extern consvar_t cv_sleep;
@@ -147,6 +149,7 @@ typedef enum
 	XD_LUACMD,      // 22
 	XD_LUAVAR,      // 23
 	XD_LUAFILE,     // 24
+	XD_MUTEPLAYER,  // 25
 	MAXNETXCMD
 } netxcmd_t;
 
diff --git a/src/netcode/http-mserv.c b/src/netcode/http-mserv.c
index 2b52380cf506f00f119dc01b5f0ab3b47ff4e6f6..b8c662a51e215965470310d758331236359378b7 100644
--- a/src/netcode/http-mserv.c
+++ b/src/netcode/http-mserv.c
@@ -134,7 +134,7 @@ HMS_on_read (char *s, size_t _1, size_t n, void *userdata)
 	return n;
 }
 
-static struct HMS_buffer *
+FUNCDEBUG static struct HMS_buffer *
 HMS_connect (int proto, const char *format, ...)
 {
 	va_list ap;
diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c
index 0148c485ab1fd5fd29cd4ca0bc6effca93ff69f1..6a50f440be80cfee5a591ed757ae1c79414c6455 100644
--- a/src/netcode/i_tcp.c
+++ b/src/netcode/i_tcp.c
@@ -114,16 +114,10 @@ typedef union
 } mysockaddr_t;
 
 	#ifdef HAVE_MINIUPNPC
-	#ifdef MINIUPNP_STATICLIB
-		#include "miniwget.h"
-		#include "miniupnpc.h"
-		#include "upnpcommands.h"
-	#else
-		#include "miniupnpc/miniwget.h"
-		#include "miniupnpc/miniupnpc.h"
-		#include "miniupnpc/upnpcommands.h"
-	#endif
-		static boolean UPNP_support = true;
+	#include "miniupnpc/miniwget.h"
+	#include "miniupnpc/miniupnpc.h"
+	#include "miniupnpc/upnpcommands.h"
+	static boolean UPNP_support = true;
 	#endif // HAVE_MINIUPNC
 
 #define MAXBANS 100
diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c
index bbabc8f1dc9a5d82030159a281c2ffae137d1054..f4601e4acac08a187b982f8e286e9e53d46b2396 100644
--- a/src/netcode/server_connection.c
+++ b/src/netcode/server_connection.c
@@ -115,12 +115,12 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
 	netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
 
 	strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
-			sizeof netbuffer->u.serverinfo.gametypename);
+			sizeof(netbuffer->u.serverinfo.gametypename)-1);
 	netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
 	netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
 	netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0);
 	strncpy(netbuffer->u.serverinfo.servername, cv_servername.string,
-		MAXSERVERNAME);
+		sizeof(netbuffer->u.serverinfo.servername)-1);
 	strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
 
 	M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
@@ -184,7 +184,9 @@ static void SV_SendPlayerInfo(INT32 node)
 		}
 
 		netbuffer->u.playerinfo[i].num = i;
-		strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1);
+		memset(netbuffer->u.playerinfo[i].name, 0x00, sizeof(netbuffer->u.playerinfo[i].name));
+		memcpy(netbuffer->u.playerinfo[i].name, player_names[i], sizeof(player_names[i]));
+
 		netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0';
 
 		//fetch IP address
diff --git a/src/p_enemy.c b/src/p_enemy.c
index a386d8ee93d75a47c24e90bf67ccdc08220bab43..4990db6fd50a2f96102056984b4d02e3c0205ddb 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -541,7 +541,7 @@ boolean P_Move(mobj_t *actor, fixed_t speed)
 
 	if (!P_TryMove(actor, tryx, tryy, false))
 	{
-		if (actor->flags & MF_FLOAT && floatok)
+		if (!P_MobjWasRemoved(actor) && actor->flags & MF_FLOAT && floatok)
 		{
 			// must adjust height
 			if (actor->z < tmfloorz)
@@ -585,6 +585,7 @@ void P_NewChaseDir(mobj_t *actor)
 	dirtype_t d[3];
 	dirtype_t tdir = DI_NODIR, olddir, turnaround;
 
+	I_Assert(!P_MobjWasRemoved(actor));
 	I_Assert(actor->target != NULL);
 	I_Assert(!P_MobjWasRemoved(actor->target));
 
@@ -623,7 +624,7 @@ void P_NewChaseDir(mobj_t *actor)
 		dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)];
 
 		actor->movedir = newdir;
-		if ((newdir != turnaround) && P_TryWalk(actor))
+		if ((newdir != turnaround) && (P_TryWalk(actor) || P_MobjWasRemoved(actor)))
 			return;
 	}
 
@@ -644,7 +645,7 @@ void P_NewChaseDir(mobj_t *actor)
 	{
 		actor->movedir = d[1];
 
-		if (P_TryWalk(actor))
+		if (P_TryWalk(actor) || P_MobjWasRemoved(actor))
 			return; // either moved forward or attacked
 	}
 
@@ -652,7 +653,7 @@ void P_NewChaseDir(mobj_t *actor)
 	{
 		actor->movedir = d[2];
 
-		if (P_TryWalk(actor))
+		if (P_TryWalk(actor) || P_MobjWasRemoved(actor))
 			return;
 	}
 
@@ -661,7 +662,7 @@ void P_NewChaseDir(mobj_t *actor)
 	{
 		actor->movedir =olddir;
 
-		if (P_TryWalk(actor))
+		if (P_TryWalk(actor) || P_MobjWasRemoved(actor))
 			return;
 	}
 
@@ -674,7 +675,7 @@ void P_NewChaseDir(mobj_t *actor)
 			{
 				actor->movedir = tdir;
 
-				if (P_TryWalk(actor))
+				if (P_TryWalk(actor) || P_MobjWasRemoved(actor))
 					return;
 			}
 		}
@@ -687,7 +688,7 @@ void P_NewChaseDir(mobj_t *actor)
 			{
 				actor->movedir = tdir;
 
-				if (P_TryWalk(actor))
+				if (P_TryWalk(actor) || P_MobjWasRemoved(actor))
 					return;
 			}
 		}
@@ -697,7 +698,7 @@ void P_NewChaseDir(mobj_t *actor)
 	{
 		actor->movedir = turnaround;
 
-		if (P_TryWalk(actor))
+		if (P_TryWalk(actor) || P_MobjWasRemoved(actor))
 			return;
 	}
 
@@ -1100,7 +1101,7 @@ nomissile:
 		return; // got a new target
 
 	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+	if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 		P_NewChaseDir(actor);
 }
 
@@ -1188,7 +1189,7 @@ nomissile:
 		return; // got a new target
 
 	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+	if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 		P_NewChaseDir(actor);
 }
 
@@ -1221,8 +1222,7 @@ static void P_FaceStabFlume(mobj_t *actor)
 	if (P_MobjWasRemoved(flume))
 		return;
 
-	flume->destscale = actor->scale*3;
-	P_SetScale(flume, flume->destscale);
+	P_SetScale(flume, 3*actor->scale, true);
 	P_SetTarget(&flume->target, actor);
 	flume->sprite = SPR_JETF;
 	flume->frame = FF_FULLBRIGHT;
@@ -1267,7 +1267,8 @@ void A_FaceStabRev(mobj_t *actor)
 		else
 		{
 			P_TryMove(actor, actor->x - P_ReturnThrustX(actor, actor->angle, 2<<FRACBITS), actor->y - P_ReturnThrustY(actor, actor->angle, 2<<FRACBITS), false);
-			P_FaceStabFlume(actor);
+			if (!P_MobjWasRemoved(actor))
+				P_FaceStabFlume(actor);
 		}
 	}
 }
@@ -1333,16 +1334,30 @@ void A_FaceStabHurl(mobj_t *actor)
 
 				while (step > 0)
 				{
-					if (!hwork->hnext)
+					if (P_MobjWasRemoved(hwork->hnext))
 						P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR));
+
 					if (!P_MobjWasRemoved(hwork->hnext))
 					{
 						hwork = hwork->hnext;
 						hwork->angle = actor->angle + ANGLE_90;
-						hwork->destscale = FixedSqrt(step*basesize);
-						P_SetScale(hwork, hwork->destscale);
+						P_SetScale(hwork, FixedSqrt(step*basesize), true);
 						hwork->fuse = 2;
 						P_MoveOrigin(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS)));
+						if (P_MobjWasRemoved(hwork))
+						{
+							// if one of the sections are removed, erase the entire damn thing.
+							mobj_t *hnext = actor->hnext;
+							hwork = actor;
+							do
+							{
+								hnext = hwork->hnext;
+								P_RemoveMobj(hwork);
+								hwork = hnext;
+							}
+							while (!P_MobjWasRemoved(hwork));
+							return;
+						}
 					}
 					step -= NUMGRADS;
 				}
@@ -1359,11 +1374,14 @@ void A_FaceStabHurl(mobj_t *actor)
 #undef NUMGRADS
 #undef NUMSTEPS
 			}
+			if (P_MobjWasRemoved(actor))
+				return;
 		}
 	}
 
 	P_SetMobjState(actor, locvar2);
-	actor->reactiontime = actor->info->reactiontime;
+	if (!P_MobjWasRemoved(actor))
+		actor->reactiontime = actor->info->reactiontime;
 }
 
 // Function: A_FaceStabMiss
@@ -1393,6 +1411,8 @@ void A_FaceStabMiss(mobj_t *actor)
 		actor->y + P_ReturnThrustY(actor, actor->angle, actor->extravalue2<<FRACBITS),
 		false))
 	{
+		if (P_MobjWasRemoved(actor))
+			return;
 		actor->extravalue2 = 0;
 		P_SetMobjState(actor, locvar2);
 	}
@@ -1425,6 +1445,8 @@ void A_StatueBurst(mobj_t *actor)
 	P_SetTarget(&new->target, actor->target);
 	if (locvar2)
 		P_SetMobjState(new, (statenum_t)locvar2);
+	if (P_MobjWasRemoved(new))
+		return;
 	S_StartSound(new, new->info->attacksound);
 	S_StopSound(actor);
 	S_StartSound(actor, sfx_s3k96);
@@ -1520,7 +1542,7 @@ void A_JetJawChomp(mobj_t *actor)
 	}
 
 	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+	if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 		P_NewChaseDir(actor);
 }
 
@@ -1941,14 +1963,15 @@ void A_SharpChase(mobj_t *actor)
 		}
 
 		// chase towards player
-		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 			P_NewChaseDir(actor);
 	}
 	else
 	{
 		actor->threshold = actor->info->painchance;
 		P_SetMobjState(actor, actor->info->missilestate);
-		S_StartSound(actor, actor->info->attacksound);
+		if (!P_MobjWasRemoved(actor))
+			S_StartSound(actor, actor->info->attacksound);
 	}
 }
 
@@ -2034,6 +2057,8 @@ void A_CrushstaceanWalk(mobj_t *actor)
 		false)
 	|| (actor->reactiontime-- <= 0))
 	{
+		if (P_MobjWasRemoved(actor))
+			return;
 		actor->flags2 ^= MF2_AMBUSH;
 		P_SetTarget(&actor->target, NULL);
 		P_SetMobjState(actor, locvar2);
@@ -2215,6 +2240,8 @@ void A_CrushclawLaunch(mobj_t *actor)
 		true)
 		&& !locvar1)
 	{
+		if (P_MobjWasRemoved(actor))
+			return;
 		actor->extravalue1 = 0;
 		actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS;
 		P_SetMobjState(actor, locvar2);
@@ -2223,6 +2250,8 @@ void A_CrushclawLaunch(mobj_t *actor)
 	}
 	else
 	{
+		if (P_MobjWasRemoved(actor))
+			return;
 		actor->z = actor->target->z;
 		if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16)))
 		{
@@ -2455,7 +2484,7 @@ void A_VultureBlast(mobj_t *actor)
 		if (P_MobjWasRemoved(dust))
 			continue;
 
-		P_SetScale(dust, 4*FRACUNIT);
+		P_SetScale(dust, 4*FRACUNIT, true);
 		dust->destscale = FRACUNIT;
 		dust->scalespeed = 4*FRACUNIT/TICRATE;
 		dust->fuse = TICRATE;
@@ -2525,7 +2554,7 @@ void A_VultureFly(mobj_t *actor)
 	dust = P_SpawnMobj(actor->x + P_RandomFixed() - FRACUNIT/2, actor->y + P_RandomFixed() - FRACUNIT/2, actor->z + actor->height/2 + P_RandomFixed() - FRACUNIT/2, MT_PARTICLE);
 	if (!P_MobjWasRemoved(dust))
 	{
-		P_SetScale(dust, 2*FRACUNIT);
+		P_SetScale(dust, 2*FRACUNIT, true);
 		dust->destscale = FRACUNIT/3;
 		dust->scalespeed = FRACUNIT/40;
 		dust->fuse = TICRATE*2;
@@ -2648,7 +2677,7 @@ nomissile:
 		return; // got a new target
 
 	// chase towards player
-	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+	if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 		P_NewChaseDir(actor);
 }
 
@@ -2734,15 +2763,9 @@ void A_LobShot(mobj_t *actor)
 		return;
 
 	if (actor->type == MT_BLACKEGGMAN)
-	{
-		shot->destscale = actor->scale/2;
-		P_SetScale(shot, actor->scale/2);
-	}
+		P_SetScale(shot, actor->scale/2, true);
 	else
-	{
-		shot->destscale = actor->scale;
-		P_SetScale(shot, actor->scale);
-	}
+		P_SetScale(shot, actor->scale, true);
 
 	P_SetTarget(&shot->target, actor); // where it came from
 
@@ -3187,8 +3210,7 @@ void A_Boss1Laser(mobj_t *actor)
 		if (!P_MobjWasRemoved(point))
 		{
 			point->angle = actor->angle;
-			point->destscale = actor->scale;
-			P_SetScale(point, point->destscale);
+			P_SetScale(point, actor->scale, true);
 			P_SetTarget(&point->target, actor);
 			P_MobjCheckWater(point);
 			if (point->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))
@@ -3199,7 +3221,8 @@ void A_Boss1Laser(mobj_t *actor)
 					mobj_t *steam = P_SpawnMobj(x, y, point->watertop - size*mobjinfo[MT_DUST].height, MT_DUST);
 					if (P_MobjWasRemoved(steam))
 						continue;
-					P_SetScale(steam, size*actor->scale);
+					P_SetScale(steam, size*actor->scale, false);
+					steam->old_scale = steam->scale;
 					P_SetObjectMomZ(steam, FRACUNIT + 2*P_RandomFixed(), true);
 					P_InstaThrust(steam, FixedAngle(P_RandomKey(360)*FRACUNIT), 2*P_RandomFixed());
 					if (point->info->painsound)
@@ -3572,8 +3595,7 @@ void A_BossScream(mobj_t *actor)
 		return;
 	if (actor->eflags & MFE_VERTICALFLIP)
 		mo->flags2 |= MF2_OBJECTFLIP;
-	mo->destscale = actor->scale;
-	P_SetScale(mo, mo->destscale);
+	P_SetScale(mo, actor->scale, true);
 	if (actor->info->deathsound)
 		S_StartSound(mo, actor->info->deathsound);
 }
@@ -4166,9 +4188,11 @@ static void P_DoBoss5Death(mobj_t *mo)
 				MT_FSGNB);
 			if (!P_MobjWasRemoved(pole))
 			{
-				P_SetScale(pole, (pole->destscale = 2*FRACUNIT));
+				P_SetScale(pole, 2*FRACUNIT, true);
+				pole->angle = mo->tracer->angle;
 				pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
 				pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
+				
 				P_SetTarget(&pole->tracer, P_SpawnMobj(
 					pole->x, pole->y,
 					pole->z - 256*FRACUNIT,
@@ -4176,8 +4200,8 @@ static void P_DoBoss5Death(mobj_t *mo)
 				if (!P_MobjWasRemoved(pole->tracer))
 				{
 					pole->tracer->flags |= MF_NOCLIPTHING;
-					P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT));
-					pole->angle = pole->tracer->angle = mo->tracer->angle;
+					P_SetScale(pole->tracer, 2*FRACUNIT, true);
+					pole->tracer->angle = mo->tracer->angle;
 					pole->tracer->momx = pole->momx;
 					pole->tracer->momy = pole->momy;
 
@@ -4715,10 +4739,7 @@ void A_BubbleSpawn(mobj_t *actor)
 		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_MEDIUMBUBBLE);
 
 	if (bubble)
-	{
-		bubble->destscale = actor->scale;
-		P_SetScale(bubble, actor->scale);
-	}
+		P_SetScale(bubble, actor->scale, true);
 }
 
 // Function: A_FanBubbleSpawn
@@ -4761,10 +4782,7 @@ void A_FanBubbleSpawn(mobj_t *actor)
 		bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_MEDIUMBUBBLE);
 
 	if (bubble)
-	{
-		bubble->destscale = actor->scale;
-		P_SetScale(bubble, actor->scale);
-	}
+		P_SetScale(bubble, actor->scale, true);
 }
 
 // Function: A_BubbleRise
@@ -5041,8 +5059,7 @@ void A_ThrownRing(mobj_t *actor)
 			P_SetTarget(&ring->target, actor);
 			ring->color = actor->color; //copy color
 			*/
-			ring->destscale = actor->scale;
-			P_SetScale(ring, actor->scale);
+			P_SetScale(ring, actor->scale, true);
 		}
 	}
 
@@ -5177,7 +5194,7 @@ void A_SetSolidSteam(mobj_t *actor)
 		return;
 
 	actor->flags &= ~MF_NOCLIP;
-	actor->flags |= MF_SOLID;
+	actor->flags |= MF_SPECIAL;
 	if (!(actor->flags2 & MF2_AMBUSH))
 	{
 		if (P_RandomChance(FRACUNIT/8))
@@ -5207,7 +5224,7 @@ void A_UnsetSolidSteam(mobj_t *actor)
 	if (LUA_CallAction(A_UNSETSOLIDSTEAM, actor))
 		return;
 
-	actor->flags &= ~MF_SOLID;
+	actor->flags &= ~MF_SPECIAL;
 	actor->flags |= MF_NOCLIP;
 }
 
@@ -5621,8 +5638,7 @@ void A_JetbThink(mobj_t *actor)
 			if (!P_MobjWasRemoved(bomb))
 			{
 				P_SetTarget(&bomb->target, actor);
-				bomb->destscale = actor->scale;
-				P_SetScale(bomb, actor->scale);
+				P_SetScale(bomb, actor->scale, true);
 				actor->reactiontime = TICRATE; // one second
 				S_StartSound(actor, actor->info->attacksound);
 			}
@@ -5788,7 +5804,11 @@ void A_MinusDigging(mobj_t *actor)
 	if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < actor->radius*2)
 	{
 		P_SetMobjState(actor, actor->info->meleestate);
+		if (P_MobjWasRemoved(actor))
+			return;
 		P_TryMove(actor, actor->target->x, actor->target->y, false);
+		if (P_MobjWasRemoved(actor))
+			return;
 		S_StartSound(actor, actor->info->attacksound);
 
 		// Spawn growing dirt pile.
@@ -5796,7 +5816,10 @@ void A_MinusDigging(mobj_t *actor)
 		if (P_MobjWasRemoved(par))
 			return;
 		P_SetMobjState(par, actor->info->raisestate);
-		P_SetScale(par, actor->scale*2);
+		if (P_MobjWasRemoved(par))
+			return;
+		P_SetScale(par, actor->scale*2, false);
+		par->old_scale = par->scale;
 		if (actor->eflags & MFE_VERTICALFLIP)
 			par->eflags |= MFE_VERTICALFLIP;
 		return;
@@ -5809,6 +5832,8 @@ void A_MinusDigging(mobj_t *actor)
 	// Move
 	var1 = 3;
 	A_Chase(actor);
+	if (P_MobjWasRemoved(actor))
+		return;
 
 	// Carry over shit, maybe
 	if (P_MobjWasRemoved(actor->tracer) || !actor->tracer->health)
@@ -5832,7 +5857,7 @@ void A_MinusDigging(mobj_t *actor)
 	{
 		if (P_TryMove(actor->tracer, actor->x, actor->y, false))
 			actor->tracer->z = mz;
-		else
+		else if (!P_MobjWasRemoved(actor))
 			P_SetTarget(&actor->tracer, NULL);
 	}
 }
@@ -5866,7 +5891,8 @@ void A_MinusPopup(mobj_t *actor)
 			continue;
 		P_Thrust(rock, ani*i, FRACUNIT);
 		P_SetObjectMomZ(rock, 3*FRACUNIT, false);
-		P_SetScale(rock, rock->scale/3);
+		P_SetScale(rock, rock->scale/3, false);
+		rock->old_scale = rock->scale;
 	}
 	P_RadiusAttack(actor, actor, 2*actor->radius, 0, true);
 	if (actor->tracer)
@@ -5905,7 +5931,8 @@ void A_MinusCheck(mobj_t *actor)
 					continue;
 				P_Thrust(rock, ani*i, FRACUNIT);
 				P_SetObjectMomZ(rock, 3*FRACUNIT, false);
-				P_SetScale(rock, rock->scale/3);
+				P_SetScale(rock, rock->scale/3, false);
+				rock->old_scale = rock->scale;
 			}
 		}
 	}
@@ -7304,7 +7331,7 @@ nomissile:
 	// chase towards player
 	if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) > actor->radius+actor->target->radius)
 	{
-		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 			P_NewChaseDir(actor);
 	}
 	// too close, don't want to chase.
@@ -7661,7 +7688,7 @@ void A_Boss7Chase(mobj_t *actor)
 	if (leveltime & 1)
 	{
 		// chase towards player
-		if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+		if (--actor->movecount < 0 || (!P_Move(actor, actor->info->speed) && !P_MobjWasRemoved(actor)))
 			P_NewChaseDir(actor);
 	}
 }
@@ -8119,6 +8146,8 @@ void A_GuardChase(mobj_t *actor)
 			false)
 		&& speed > 0) // can't be the same check as previous so that P_TryMove gets to happen.
 		{
+			if (P_MobjWasRemoved(actor))
+				return;
 			INT32 direction = actor->spawnpoint ? actor->spawnpoint->args[0] : TMGD_BACK;
 
 			switch (direction)
@@ -8135,6 +8164,8 @@ void A_GuardChase(mobj_t *actor)
 					break;
 			}
 		}
+		if (P_MobjWasRemoved(actor))
+			return;
 
 		if (actor->extravalue1 < actor->info->speed)
 			actor->extravalue1++;
@@ -8171,7 +8202,11 @@ void A_GuardChase(mobj_t *actor)
 		// chase towards player
 		if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed))
 		{
+			if (P_MobjWasRemoved(actor))
+				return;
 			P_NewChaseDir(actor);
+			if (P_MobjWasRemoved(actor))
+				return;
 			actor->movecount += 5; // Increase tics before change in direction allowed.
 		}
 	}
@@ -8226,8 +8261,9 @@ void A_EggShield(mobj_t *actor)
 	else
 		actor->z = actor->target->z;
 
+	P_SetScale(actor, actor->target->scale, false);
 	actor->destscale = actor->target->destscale;
-	P_SetScale(actor, actor->target->scale);
+	actor->old_scale = actor->target->old_scale;
 
 	actor->floorz = actor->target->floorz;
 	actor->ceilingz = actor->target->ceilingz;
@@ -8508,7 +8544,7 @@ void A_Boss3ShockThink(mobj_t *actor)
 				P_SetTarget(&snew->target, actor->target);
 				snew->fuse = actor->fuse;
 
-				P_SetScale(snew, actor->scale);
+				P_SetScale(snew, actor->scale, true);
 				snew->destscale = actor->destscale;
 				snew->scalespeed = actor->scalespeed;
 
@@ -8641,6 +8677,9 @@ void A_PlaySeeSound(mobj_t *actor)
 	if (LUA_CallAction(A_PLAYSEESOUND, actor))
 		return;
 
+	if (P_MobjWasRemoved(actor))
+		return;
+
 	if (actor->info->seesound)
 		S_StartScreamSound(actor, actor->info->seesound);
 }
@@ -8707,8 +8746,7 @@ void A_SmokeTrailer(mobj_t *actor)
 	if (P_MobjWasRemoved(th))
 		return;
 	P_SetObjectMomZ(th, FRACUNIT, false);
-	th->destscale = actor->scale;
-	P_SetScale(th, actor->scale);
+	P_SetScale(th, actor->scale, true);
 	th->tics -= P_RandomByte() & 3;
 	if (th->tics < 1)
 		th->tics = 1;
@@ -9472,8 +9510,7 @@ void A_BossJetFume(mobj_t *actor)
 		if (!P_MobjWasRemoved(filler))
 		{
 			P_SetTarget(&filler->target, actor);
-			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->fuse = 56;
@@ -9490,8 +9527,7 @@ void A_BossJetFume(mobj_t *actor)
 		if (!P_MobjWasRemoved(filler))
 		{
 			P_SetTarget(&filler->target, actor);
-			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->fuse = 57;
@@ -9504,7 +9540,7 @@ void A_BossJetFume(mobj_t *actor)
 		{
 			P_SetTarget(&filler->target, actor);
 			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->fuse = 58;
@@ -9525,8 +9561,7 @@ void A_BossJetFume(mobj_t *actor)
 
 		filler = P_SpawnMobj(jetx, jety, jetz, MT_PROPELLER);
 		P_SetTarget(&filler->target, actor);
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
+		P_SetScale(filler, actor->scale, true);
 		if (actor->eflags & MFE_VERTICALFLIP)
 			filler->flags2 |= MF2_OBJECTFLIP;
 		filler->angle = actor->angle - ANGLE_180;
@@ -9541,7 +9576,7 @@ void A_BossJetFume(mobj_t *actor)
 			P_SetTarget(&filler->target, actor);
 			filler->fuse = 59;
 			P_SetTarget(&actor->tracer, filler);
-			P_SetScale(filler, (filler->destscale = actor->scale/3));
+			P_SetScale(filler, actor->scale/3, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->color = SKINCOLOR_ICY;
@@ -9560,8 +9595,7 @@ void A_BossJetFume(mobj_t *actor)
 		{
 			P_SetTarget(&filler->target, actor);
 			// Boss 4 already uses its tracer for other things
-			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 		}
@@ -9583,8 +9617,7 @@ void A_BossJetFume(mobj_t *actor)
 			{
 				filler->movefactor = movefactor;
 				P_SetTarget(&filler->target, actor);
-				filler->destscale = actor->scale;
-				P_SetScale(filler, filler->destscale);
+				P_SetScale(filler, actor->scale, true);
 				if (actor->eflags & MFE_VERTICALFLIP)
 					filler->flags2 |= MF2_OBJECTFLIP;
 			}
@@ -9830,12 +9863,13 @@ void A_ToggleFlameJet(mobj_t* actor)
 // var1 = Angle adjustment (aka orbit speed)
 // var2:
 //        Bits 1-10: height offset, max 1023
-//        Bits 11-16: X radius factor (max 63, default 20)
+//        Bits 11-16: X radius factor (max 63, default 32)
 //        Bit 17: set if object is Nightopian Helper
 //        Bit 18: set to define X/Y/Z rotation factor
-//        Bits 19-20: Unused
+//        Bit 19: set to not sync scale to player
+//        Bit 20: Unused
 //        Bits 21-26: Y radius factor (max 63, default 32)
-//        Bits 27-32: Z radius factor (max 63, default 32)
+//        Bits 27-32: Z radius factor (max 63, default 20)
 //
 // If MF_GRENADEBOUNCE is flagged on mobj, use actor->threshold to define X/Y/Z radius factor, max 1023 each:
 //        Bits 1-10: X factor
@@ -9876,6 +9910,12 @@ void A_OrbitNights(mobj_t* actor)
 	}
 	else
 	{
+		if (!donotrescale)
+		{
+			P_SetScale(actor, actor->target->scale, true);
+			actor->old_scale = actor->target->old_scale;
+		}
+
 		actor->extravalue1 += var1;
 		P_UnsetThingPosition(actor);
 		{
@@ -9903,9 +9943,6 @@ void A_OrbitNights(mobj_t* actor)
 			else
 				actor->flags2 &= ~MF2_DONTDRAW;
 		}
-
-		if (!donotrescale && actor->destscale != actor->target->destscale)
-			actor->destscale = actor->target->destscale;
 	}
 }
 
@@ -11154,9 +11191,10 @@ void A_SetScale(mobj_t *actor)
 		return;
 	}
 
-	target->destscale = locvar1; // destination scale
-	if (!(locvar2 & 65535))
-		P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway
+	if ((locvar2 & 65535) == 0)
+		P_SetScale(target, locvar1, true); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 over time
+	else
+		target->destscale = locvar1; // destination scale
 }
 
 // Function: A_RemoteDamage
@@ -11300,8 +11338,7 @@ void A_TrapShot(mobj_t *actor)
 	if (actor->eflags & MFE_VERTICALFLIP)
 		missile->flags2 |= MF2_OBJECTFLIP;
 
-	missile->destscale = actor->scale;
-	P_SetScale(missile, actor->scale);
+	P_SetScale(missile, actor->scale, true);
 
 	if (missile->info->seesound)
 		S_StartSound(missile, missile->info->seesound);
@@ -11375,8 +11412,7 @@ void A_VileTarget(mobj_t *actor)
 				fog->eflags |= MFE_VERTICALFLIP;
 				fog->flags2 |= MF2_OBJECTFLIP;
 			}
-			fog->destscale = actor->target->scale;
-			P_SetScale(fog, fog->destscale);
+			P_SetScale(fog, actor->target->scale, true);
 
 			P_SetTarget(&actor->tracer, fog);
 			P_SetTarget(&fog->target, actor);
@@ -11409,8 +11445,7 @@ void A_VileTarget(mobj_t *actor)
 					fog->eflags |= MFE_VERTICALFLIP;
 					fog->flags2 |= MF2_OBJECTFLIP;
 				}
-				fog->destscale = players[i].mo->scale;
-				P_SetScale(fog, fog->destscale);
+				P_SetScale(fog, players[i].mo->scale, true);
 
 				if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now
 					P_SetTarget(&actor->tracer, fog);
@@ -11567,8 +11602,8 @@ void A_VileFire(mobj_t *actor)
 		return;
 
 	// keep to same scale and gravity as tracer ALWAYS
-	actor->destscale = dest->scale;
-	P_SetScale(actor, actor->destscale);
+	P_SetScale(actor, dest->scale, true);
+	actor->old_scale = dest->old_scale;
 	if (dest->eflags & MFE_VERTICALFLIP)
 	{
 		actor->eflags |= MFE_VERTICALFLIP;
@@ -11735,7 +11770,13 @@ void A_BrakChase(mobj_t *actor)
 
 	// chase towards player
 	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
+	{
+		if (P_MobjWasRemoved(actor))
+			return;
 		P_NewChaseDir(actor);
+		if (P_MobjWasRemoved(actor))
+			return;
+	}
 
 	// Optionally play a sound effect
 	if (locvar2 > 0 && locvar2 < NUMSFX)
@@ -12748,8 +12789,7 @@ void A_LightBeamReset(mobj_t *actor)
 	if (LUA_CallAction(A_LIGHTBEAMRESET, actor))
 		return;
 
-	actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256;
-	P_SetScale(actor, actor->destscale);
+	P_SetScale(actor, FRACUNIT + P_SignedRandom()*FRACUNIT/256, true);
 
 	if (!actor->spawnpoint)
 		return; // this can't work properly welp
@@ -13314,6 +13354,8 @@ void A_DoNPCSkid(mobj_t *actor)
 	if ((FixedHypot(actor->momx, actor->momy) < locvar2)
 	|| !P_TryMove(actor, actor->x + actor->momx, actor->y + actor->momy, false))
 	{
+		if (P_MobjWasRemoved(actor))
+			return;
 		actor->momx = actor->momy = 0;
 		P_SetMobjState(actor, locvar1);
 		return;
@@ -13334,7 +13376,7 @@ void A_DoNPCSkid(mobj_t *actor)
 		{
 			particle->tics = 10;
 
-			P_SetScale(particle, 2*actor->scale/3);
+			P_SetScale(particle, 2*actor->scale/3, true);
 			particle->destscale = actor->scale;
 			P_SetObjectMomZ(particle, FRACUNIT, false);
 		}
@@ -13757,7 +13799,7 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi
 			continue;
 
 		dust->angle = ang*i + ANGLE_90;
-		P_SetScale(dust, FixedMul(initscale, scale));
+		P_SetScale(dust, FixedMul(initscale, scale), true);
 		dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale);
 		dust->scalespeed = scale/24;
 		P_Thrust(dust, ang*i, speed + FixedMul(P_RandomFixed(), scale));
@@ -13856,6 +13898,8 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing)
 				y = dustdevil->y;
 			}
 			P_TryMove(thing, x - thing->momx, y - thing->momy, true);
+			if (P_MobjWasRemoved(thing))
+				return false;
 		}
 		else
 		{ //Player on the top of the tornado.
@@ -13896,7 +13940,8 @@ void A_DustDevilThink(mobj_t *actor)
 	while (layer && !P_MobjWasRemoved(layer)) {
 		angle_t fa = layer->angle >> ANGLETOFINESHIFT;
 		P_MoveOrigin(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z);
-		layer->scale = scale;
+		P_SetScale(layer, scale, true);
+		layer->old_scale = actor->old_scale;
 		layer->angle += ANG10 / 2;
 		layer->momx = actor->momx;
 		layer->momy = actor->momy;
@@ -13910,8 +13955,7 @@ void A_DustDevilThink(mobj_t *actor)
 		if (!P_MobjWasRemoved(dust))
 		{
 			P_SetMobjState(dust, dust->info->spawnstate + P_RandomRange(0, 2));
-			dust->destscale = scale * 3;
-			P_SetScale(dust, dust->destscale);
+			P_SetScale(dust, 3 * scale, true);
 		}
 	}
 
@@ -13930,6 +13974,7 @@ void A_DustDevilThink(mobj_t *actor)
 			layer = P_SpawnMobj(px, py, pz, MT_DUSTLAYER);
 			if (P_MobjWasRemoved(layer))
 				continue;
+			P_SetScale(layer, scale, true);
 			layer->momz = 5 * scale;
 			layer->angle = ANGLE_90 + ANGLE_90*i;
 			layer->extravalue1 = TICRATE * 3;
@@ -14260,6 +14305,8 @@ static void P_SnapperLegPlace(mobj_t *mo)
 
 	seg->z = mo->z + ((mo->eflags & MFE_VERTICALFLIP) ? (((mo->height<<1)/3) - seg->height) : mo->height/3);
 	P_TryMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, true);
+	if (P_MobjWasRemoved(seg))
+		return;
 	seg->angle = a;
 
 	// Move as many legs as available.
@@ -14281,6 +14328,8 @@ static void P_SnapperLegPlace(mobj_t *mo)
 			y = s*o2 - c*o1;
 			seg->z = mo->z + (((mo->eflags & MFE_VERTICALFLIP) ? (mo->height - seg->height) : 0));
 			P_TryMove(seg, mo->x + x, mo->y + y, true);
+			if (P_MobjWasRemoved(seg))
+				return;
 			P_SetMobjState(seg, seg->info->raisestate);
 		}
 		else
@@ -14424,6 +14473,8 @@ void A_SnapperThinker(mobj_t *actor)
 		s = FINESINE(fa);
 
 		P_TryMove(actor, actor->x + c*speed, actor->y + s*speed, false);
+		if (P_MobjWasRemoved(actor))
+			return;
 
 		// The snapper spawns dust if going fast!
 		if (actor->reactiontime < 4)
@@ -14544,8 +14595,7 @@ void A_MinecartSparkThink(mobj_t *actor)
 			continue;
 		trail->tics = 2;
 		trail->sprite = actor->sprite;
-		P_SetScale(trail, trail->scale/4);
-		trail->destscale = trail->scale;
+		P_SetScale(trail, trail->scale/4, true);
 	}
 }
 
@@ -14668,8 +14718,16 @@ void A_FireShrink(mobj_t *actor)
 	if (LUA_CallAction(A_FIRESHRINK, actor))
 		return;
 
-	actor->destscale = locvar1;
-	actor->scalespeed = FRACUNIT/locvar2;
+	if (locvar2 == 0)
+	{
+		P_SetScale(actor, locvar1, true);
+		actor->scalespeed = FRACUNIT/12; // Reset scalespeed to the default
+	}
+	else
+	{
+		actor->destscale = locvar1;
+		actor->scalespeed = FRACUNIT/locvar2;
+	}
 }
 
 // Function: A_SpawnPterabytes
diff --git a/src/p_inter.c b/src/p_inter.c
index 82169bc54304782f940fdac535456d18dc047150..e73cd1fce675ee17721e6236e7dc764ede8e9d69 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -392,17 +392,50 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 		}
 	}
 
+	// Ignore multihits in "ouchie" mode
+	if (special->flags & (MF_ENEMY | MF_BOSS) && special->flags2 & MF2_FRET)
+		return;
+
 	player = toucher->player;
-	I_Assert(player != NULL); // Only players can touch stuff!
 
-	if (player->spectator)
-		return;
+	if (player)
+	{
+		if (player->spectator)
+			return;
 
-	// Ignore multihits in "ouchie" mode
-	if (special->flags & (MF_ENEMY|MF_BOSS) && special->flags2 & MF2_FRET)
-		return;
+		// Some hooks may assume that the toucher is a player, so we keep it in here.
+		if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special))
+			return;
+	}
+
+	if (player || (toucher->flags & MF_PUSHABLE)) // Special area for objects that are interactable by both player AND MF_PUSHABLE.
+	{
+		if (special->type == MT_STEAM)
+		{
+			if (player && player->mo->state == &states[player->mo->info->painstate]) // can't use gas jets when player is in pain!
+				return;
+
+			fixed_t speed = special->info->mass; // gas jets use this for the vertical thrust
+			SINT8 flipval = P_MobjFlip(special); // virtually everything here centers around the thruster's gravity, not the object's!
 
-	if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special))
+			if (special->state != &states[S_STEAM1]) // Only when it bursts
+				return;
+
+			toucher->eflags |= MFE_SPRUNG;
+			toucher->momz = flipval * FixedMul(speed, FixedSqrt(FixedMul(special->scale, toucher->scale))); // scale the speed with both objects' scales, just like with springs!
+
+			if (player)
+			{
+				P_ResetPlayer(player);
+				if (player->panim != PA_FALL)
+					P_SetMobjState(toucher, S_PLAY_FALL);
+			}
+
+			return; // Don't collect it!
+		}
+	}
+
+	if (!player) // Only players can touch stuff!
 		return;
 
 	// 0 = none, 1 = elemental pierce, 2 = bubble bounce
@@ -1332,7 +1365,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			}
 			break;
 		case MT_NIGHTSEXTRATIME:
-			if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
+			if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE || (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS))))
 				return;
 			if (!G_IsSpecialStage(gamemap))
 			{
@@ -1344,7 +1377,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			else
 			{
 				for (i = 0; i < MAXPLAYERS; i++)
-					if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
+					if (playeringame[i] && (player->powers[pw_carry] == CR_NIGHTSMODE || (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS))))
 					{
 						players[i].nightstime += special->info->speed;
 						players[i].startedtime += special->info->speed;
@@ -1397,11 +1430,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			i = 0;
 			for (; special->type == MT_HOOP; special = special->hnext)
 			{
-				special->fuse = 11;
-				special->movedir = i;
-				special->extravalue1 = special->target->extravalue1;
-				special->extravalue2 = special->target->extravalue2;
-				special->target->threshold = 4242;
+				if (!P_MobjWasRemoved(special->target))
+				{
+					special->fuse = 11;
+					special->movedir = i;
+					special->extravalue1 = special->target->extravalue1;
+					special->extravalue2 = special->target->extravalue2;
+					special->target->threshold = 4242;
+				}
 				i++;
 			}
 			// Make the collision detectors disappear.
@@ -1878,6 +1914,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				toucher->tracer->flags2 = (toucher->tracer->flags2 & ~MF2_AMBUSH) | destambush;
 			}
 			return;
+
 		default: // SOC or script pickup
 			if (player->bot && player->bot != BOT_MPAI)
 				return;
@@ -2771,8 +2808,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 				mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE);
 			if (P_MobjWasRemoved(mo))
 				break;
-			mo->destscale = target->scale;
-			P_SetScale(mo, mo->destscale);
+			P_SetScale(mo, target->scale, true);
 			P_SetMobjState(mo, mo->info->raisestate);
 			break;
 
@@ -3604,7 +3640,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
 		if (player->nightstime > 5*TICRATE)
 			player->nightstime -= 5*TICRATE;
 		else
-			player->nightstime = 0;
+			player->nightstime = 1;
 	}
 
 	P_DoPlayerPain(player, inflictor, source);
@@ -3963,8 +3999,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
 		mo->fuse = 8*TICRATE;
 		P_SetTarget(&mo->target, player->mo);
 
-		mo->destscale = player->mo->scale;
-		P_SetScale(mo, player->mo->scale);
+		P_SetScale(mo, player->mo->scale, true);
 
 		// Angle offset by player angle, then slightly offset by amount of rings
 		fa = ((i*FINEANGLES/16) + va - ((num_rings-1)*FINEANGLES/32)) & FINEMASK;
@@ -4100,8 +4135,7 @@ void P_PlayerWeaponPanelBurst(player_t *player)
 		mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT);
 		P_SetTarget(&mo->target, player->mo);
 		mo->fuse = 12*TICRATE;
-		mo->destscale = player->mo->scale;
-		P_SetScale(mo, player->mo->scale);
+		P_SetScale(mo, player->mo->scale, true);
 
 		// Angle offset by player angle
 		fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK;
@@ -4189,8 +4223,7 @@ void P_PlayerWeaponAmmoBurst(player_t *player)
 		player->powers[power] = 0;
 		mo->fuse = 12*TICRATE;
 
-		mo->destscale = player->mo->scale;
-		P_SetScale(mo, player->mo->scale);
+		P_SetScale(mo, player->mo->scale, true);
 
 		// Angle offset by player angle
 		fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK;
@@ -4237,8 +4270,7 @@ void P_PlayerWeaponPanelOrAmmoBurst(player_t *player)
 			mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \
 			P_SetTarget(&mo->target, player->mo); \
 			mo->fuse = 12*TICRATE; \
-			mo->destscale = player->mo->scale; \
-			P_SetScale(mo, player->mo->scale); \
+			P_SetScale(mo, player->mo->scale, true); \
 			mo->momx = FixedMul(FINECOSINE(fa),ns); \
 			if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \
 				mo->momy = FixedMul(FINESINE(fa),ns); \
@@ -4260,8 +4292,7 @@ void P_PlayerWeaponPanelOrAmmoBurst(player_t *player)
 			mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \
 			P_SetTarget(&mo->target, player->mo); \
 			mo->fuse = 12*TICRATE; \
-			mo->destscale = player->mo->scale; \
-			P_SetScale(mo, player->mo->scale); \
+			P_SetScale(mo, player->mo->scale, true); \
 			mo->momx = FixedMul(FINECOSINE(fa),ns); \
 			if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \
 				mo->momy = FixedMul(FINESINE(fa),ns); \
diff --git a/src/p_local.h b/src/p_local.h
index 9644e7a244d434bf6f44d26d4a90e9cbf2fea656..249c3cd4b6de5248140c00e2dfc2332081a5d00e 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -283,7 +283,6 @@ void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, b
 extern mapthing_t *itemrespawnque[ITEMQUESIZE];
 extern tic_t itemrespawntime[ITEMQUESIZE];
 extern size_t iquehead, iquetail;
-extern consvar_t cv_gravity, cv_movebob;
 
 mobjtype_t P_GetMobjtype(UINT16 mthingtype);
 
@@ -308,21 +307,19 @@ void P_PushableThinker(mobj_t *mobj);
 void P_SceneryThinker(mobj_t *mobj);
 
 
-fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(mobj, sector, NULL, x, y, line, false, false)
-#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(mobj, sector, NULL, x, y, line, true, false)
-#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
-#define P_GetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false)
-#define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(mobj, src, bound, mobj->x, mobj->y, NULL, src != bound, true)
-#define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(mobj, src, bound, mobj->x, mobj->y, NULL, src == bound, true)
+fixed_t P_MobjFloorZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect);
+fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect);
+#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(sector, NULL, x, y, mobj->radius, line, false, false)
+#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(sector, NULL, x, y, mobj->radius, line, true, false)
+#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, false, false)
+#define P_GetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, true, false)
+#define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(src, bound, mobj->x, mobj->y, mobj->radius, NULL, src != bound, true)
+#define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(src, bound, mobj->x, mobj->y, mobj->radius, NULL, src == bound, true)
 
-fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-#define P_CameraGetFloorZ(mobj, sector, x, y, line) P_CameraFloorZ(mobj, sector, NULL, x, y, line, false, false)
-#define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_CameraCeilingZ(mobj, sector, NULL, x, y, line, true, false)
-#define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_CameraCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
-#define P_CameraGetFOFBottomZ(mobj, sector, fof, x, y, line) P_CameraFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false)
+#define P_CameraGetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(sector, NULL, x, y, mobj->radius, line, false, false)
+#define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(sector, NULL, x, y, mobj->radius, line, true, false)
+#define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, false, false)
+#define P_CameraGetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, true, false)
 
 boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
 boolean P_CheckDeathPitCollide(mobj_t *mo);
@@ -552,6 +549,7 @@ void P_ThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
 void P_VectorInstaThrust(fixed_t xa, fixed_t xb, fixed_t xc, fixed_t ya, fixed_t yb, fixed_t yc,
             fixed_t za, fixed_t zb, fixed_t zc, fixed_t momentum, mobj_t *mo);
 void P_DoSuperTransformation(player_t *player, boolean giverings);
+void P_DoSuperDetransformation(player_t *player);
 void P_ExplodeMissile(mobj_t *mo);
 void P_CheckGravity(mobj_t *mo, boolean affect);
 void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope);
diff --git a/src/p_map.c b/src/p_map.c
index 7887c117de56907d7a51eccb3715ec0a32e14d61..f97ddfa3cd8aa3fa9f7e9dbb3e6d76b041aca164 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -502,72 +502,56 @@ springstate:
 	return final;
 }
 
-static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
+static void P_DoFan(mobj_t *fan, mobj_t *object)
 {
 	player_t *p = object->player; // will be NULL if not a player
 	fixed_t zdist; // distance between bottoms
-	fixed_t speed = spring->info->mass; // conveniently, both fans and gas jets use this for the vertical thrust
-	SINT8 flipval = P_MobjFlip(spring); // virtually everything here centers around the thruster's gravity, not the object's!
+	fixed_t speed = fan->info->mass; // fans use this for the vertical thrust
+	SINT8 flipval = P_MobjFlip(fan); // virtually everything here centers around the thruster's gravity, not the object's!
 
-	if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
+	if (p && object->state == &states[object->info->painstate]) // can't use fans when player is in pain!
 		return;
 
 	// is object's top below thruster's position? if not, calculate distance between their bottoms
-	if (spring->eflags & MFE_VERTICALFLIP)
+	if (fan->eflags & MFE_VERTICALFLIP)
 	{
-		if (object->z > spring->z + spring->height)
+		if (object->z > fan->z + fan->height)
 			return;
-		zdist = (spring->z + spring->height) - (object->z + object->height);
+		zdist = (fan->z + fan->height) - (object->z + object->height);
 	}
 	else
 	{
-		if (object->z + object->height < spring->z)
+		if (object->z + object->height < fan->z)
 			return;
-		zdist = object->z - spring->z;
+		zdist = object->z - fan->z;
 	}
 
 	object->standingslope = NULL; // No launching off at silly angles for you.
 
-	switch (spring->type)
+	switch (fan->type)
 	{
 		case MT_FAN: // fan
-			if (zdist > (spring->health << FRACBITS)) // max z distance determined by health (set by map thing args[0])
+			if (zdist > (fan->health << FRACBITS)) // max z distance determined by health (set by map thing args[0])
 				break;
-			if (flipval*object->momz >= FixedMul(speed, spring->scale)) // if object's already moving faster than your best, don't bother
+			if (flipval*object->momz >= FixedMul(speed, fan->scale)) // if object's already moving faster than your best, don't bother
 				break;
 			if (p && (p->climbing || p->pflags & PF_GLIDING)) // doesn't affect Knux when he's using his abilities!
 				break;
 
-			object->momz += flipval*FixedMul(speed/4, spring->scale);
+			object->momz += flipval*FixedMul(speed/4, fan->scale);
 
 			// limit the speed if too high
-			if (flipval*object->momz > FixedMul(speed, spring->scale))
-				object->momz = flipval*FixedMul(speed, spring->scale);
+			if (flipval*object->momz > FixedMul(speed, fan->scale))
+				object->momz = flipval*FixedMul(speed, fan->scale);
 
 			if (p && !p->powers[pw_tailsfly] && !p->powers[pw_carry]) // doesn't reset anim for Tails' flight
 			{
 				P_ResetPlayer(p);
 				P_SetMobjState(object, S_PLAY_FALL);
-				P_SetTarget(&object->tracer, spring);
+				P_SetTarget(&object->tracer, fan);
 				p->powers[pw_carry] = CR_FAN;
 			}
 			break;
-		case MT_STEAM: // Steam
-			if (zdist > FixedMul(16*FRACUNIT, spring->scale))
-				break;
-			if (spring->state != &states[S_STEAM1]) // Only when it bursts
-				break;
-
-			object->eflags |= MFE_SPRUNG;
-			object->momz = flipval*FixedMul(speed, FixedSqrt(FixedMul(spring->scale, object->scale))); // scale the speed with both objects' scales, just like with springs!
-
-			if (p)
-			{
-				P_ResetPlayer(p);
-				if (p->panim != PA_FALL)
-					P_SetMobjState(object, S_PLAY_FALL);
-			}
-			break;
 		default:
 			break;
 	}
@@ -1484,13 +1468,13 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 	}
 
 	// check for special pickup
-	if (thing->flags & MF_SPECIAL && tmthing->player)
+	if (thing->flags & MF_SPECIAL)
 	{
 		P_TouchSpecialThing(thing, tmthing, true); // can remove thing
 		return CHECKTHING_COLLIDE;
 	}
 	// check again for special pickup
-	if (tmthing->flags & MF_SPECIAL && thing->player)
+	if (tmthing->flags & MF_SPECIAL)
 	{
 		P_TouchSpecialThing(tmthing, thing, true); // can remove thing
 		return CHECKTHING_COLLIDE;
@@ -1578,15 +1562,15 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 
 	if (thing->flags & MF_PUSHABLE)
 	{
-		if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM)
-			P_DoFanAndGasJet(tmthing, thing);
+		if (tmthing->type == MT_FAN)
+			P_DoFan(tmthing, thing);
 	}
 
 	if (tmthing->flags & MF_PUSHABLE)
 	{
-		if (thing->type == MT_FAN || thing->type == MT_STEAM)
+		if (thing->type == MT_FAN)
 		{
-			P_DoFanAndGasJet(thing, tmthing);
+			P_DoFan(thing, tmthing);
 			return CHECKTHING_COLLIDE;
 		}
 		else if (thing->flags & MF_SPRING)
@@ -1679,8 +1663,8 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 			}
 		}
 
-		if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM)
-			P_DoFanAndGasJet(tmthing, thing);
+		if (tmthing->type == MT_FAN)
+			P_DoFan(tmthing, thing);
 	}
 
 	if (tmthing->player) // Is the moving/interacting object the player?
@@ -1688,8 +1672,8 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 		if (!tmthing->health)
 			return CHECKTHING_IGNORE;
 
-		if (thing->type == MT_FAN || thing->type == MT_STEAM)
-			P_DoFanAndGasJet(thing, tmthing);
+		if (thing->type == MT_FAN)
+			P_DoFan(thing, tmthing);
 		else if (thing->flags & MF_SPRING && tmthing->player->powers[pw_carry] != CR_MINECART)
 		{
 			if ( thing->z <= tmthing->z + tmthing->height
@@ -1755,8 +1739,8 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 	// not solid not blocked
 	unsigned collide = CHECKTHING_NOCOLLIDE;
 
-	if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
-		; // springs, gas jets and springs should never be able to step up onto a player
+	if ((tmthing->flags & MF_SPRING || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
+		; // springs and spikes should never be able to step up onto a player
 	// z checking at last
 	// Treat noclip things as non-solid!
 	else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID
@@ -2734,7 +2718,7 @@ increment_move
 				tryy = y;
 		}
 
-		if (!P_CheckPosition(thing, tryx, tryy))
+		if (!P_CheckPosition(thing, tryx, tryy) || P_MobjWasRemoved(thing))
 			return false; // solid wall or thing
 
 		if (!(thing->flags & MF_NOCLIP))
@@ -2958,6 +2942,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
 {
 	fixed_t tryx, tryy;
+	I_Assert(!P_MobjWasRemoved(thing));
 
 	tryx = thing->x;
 	tryy = thing->y;
@@ -2975,7 +2960,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
 		else
 			tryy = y;
 
-		if (!P_CheckPosition(thing, tryx, tryy))
+		if (!P_CheckPosition(thing, tryx, tryy) || P_MobjWasRemoved(thing))
 			return false; // solid wall or thing
 
 		if (!(thing->flags & MF_NOCLIP))
@@ -3714,6 +3699,12 @@ static void P_CheckLavaWall(mobj_t *mo, sector_t *sec)
 	}
 }
 
+static inline void P_StairStepSlideMove(mobj_t *mo)
+{
+	if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true) && !P_MobjWasRemoved(mo)) //Allow things to drop off.
+		P_TryMove(mo, mo->x + mo->momx, mo->y, true);
+}
+
 //
 // P_SlideMove
 // The momx / momy move is bad, so try to slide
@@ -3735,6 +3726,8 @@ void P_SlideMove(mobj_t *mo)
 
 	memset(&junk, 0x00, sizeof(junk));
 
+	I_Assert(!P_MobjWasRemoved(mo));
+
 	if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height)
 	{
 		// Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already.
@@ -3869,7 +3862,10 @@ void P_SlideMove(mobj_t *mo)
 
 retry:
 	if ((++hitcount == 3) || papercol)
-		goto stairstep; // don't loop forever
+	{
+		P_StairStepSlideMove(mo);
+		return;
+	}
 
 	// trace along the three leading corners
 	if (mo->momx > 0)
@@ -3921,9 +3917,7 @@ papercollision:
 	if (bestslidefrac == FRACUNIT+1)
 	{
 		// the move must have hit the middle, so stairstep
-stairstep:
-		if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true)) //Allow things to drop off.
-			P_TryMove(mo, mo->x + mo->momx, mo->y, true);
+		P_StairStepSlideMove(mo);
 		return;
 	}
 
@@ -3935,7 +3929,13 @@ stairstep:
 		newy = FixedMul(mo->momy, bestslidefrac);
 
 		if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true))
-			goto stairstep;
+		{
+			if (!P_MobjWasRemoved(mo))
+				P_StairStepSlideMove(mo);
+			return;
+		}
+		if (P_MobjWasRemoved(mo))
+			return;
 	}
 
 	// Now continue along the wall.
@@ -3986,11 +3986,13 @@ stairstep:
 			tmymove = 0;
 		}
 		if (!P_TryMove(mo, newx, newy, true)) {
-			if (success)
+			if (success || P_MobjWasRemoved(mo))
 				return; // Good enough!!
 			else
 				goto retry;
 		}
+		if (P_MobjWasRemoved(mo))
+			return;
 		success = true;
 	} while(tmxmove || tmymove);
 }
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 82b86471522ee3b2cbeebbedfb1e28c1c4438501..242bc559e8d31ba398bb5dd563b5da909e31fc28 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -1026,23 +1026,35 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *))
 //
 boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *))
 {
-	mobj_t *mobj;
-	blocknode_t *block;
+	mobj_t *bnext = NULL;
+	blocknode_t *block, *next = NULL;
 
 	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
 		return true;
 
 	// Check interaction with the objects in the blockmap.
-	for (block = blocklinks[y*bmapwidth + x]; block; block = block->mnext)
+	for (block = blocklinks[y*bmapwidth + x]; block; block = next)
 	{
-		mobj = block->mobj;
+		next = block->mnext;
+		if (next)
+			P_SetTarget(&bnext, next->mobj); // We want to note our reference to bnext here in case it is MF_NOTHINK and gets removed!
 
-		if (!func(mobj))
+		if (!func(block->mobj))
+		{
+			P_SetTarget(&bnext, NULL);
 			return false;
-		if (P_MobjWasRemoved(tmthing)) // func just broke blockmap chain, cannot continue.
+		}
+
+		if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue.
+		|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
+		{
+			P_SetTarget(&bnext, NULL);
 			return true;
+		}
 	}
 
+	P_SetTarget(&bnext, NULL);
+
 	return true;
 }
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 16ca0c6345284f8e3aefac90d04e9d2d1b69c6d4..9cdd2628db8cfec3ee8af83a6f96b3713879b164 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -85,9 +85,15 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum)
 //
 static void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
 {
-	INT32 animlength = (mobj->sprite == SPR_PLAY && mobj->skin)
-		? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1
-		: st->var1;
+	INT32 animlength;
+
+	if (mobj->sprite == SPR_PLAY && mobj->skin)
+	{
+		spritedef_t *spritedef = P_GetSkinSpritedef(mobj->skin, mobj->sprite2);
+		animlength = (INT32)(spritedef->numframes);
+	}
+	else
+		animlength = st->var1;
 
 	if (!(st->frame & FF_ANIMATE))
 		return;
@@ -138,8 +144,13 @@ FUNCINLINE static ATTRINLINE void P_CycleStateAnimation(mobj_t *mobj)
 	}
 
 	// sprite2 version of above
-	if (mobj->skin && (((++mobj->frame) & FF_FRAMEMASK) >= (UINT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes)))
-		mobj->frame &= ~FF_FRAMEMASK;
+	if (mobj->skin)
+	{
+		spritedef_t *spritedef = P_GetSkinSpritedef(mobj->skin, mobj->sprite2);
+		UINT32 anim_length = (UINT32)(spritedef->numframes);
+		if (((++mobj->frame) & FF_FRAMEMASK) >= anim_length)
+			mobj->frame &= ~FF_FRAMEMASK;
+	}
 }
 
 //
@@ -395,31 +406,23 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 		{
 			skin_t *skin = ((skin_t *)mobj->skin);
 			UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
-			UINT8 numframes, spr2;
+			UINT8 numframes;
+			UINT16 spr2;
 
 			if (skin)
 			{
-				UINT16 stateframe = st->frame;
+				spr2 = P_GetStateSprite2(st);
 
-				// Add/Remove FF_SPR2SUPER based on certain conditions
-				if (player->charflags & SF_NOSUPERSPRITES)
-					stateframe = stateframe & ~FF_SPR2SUPER;
-				else if (player->powers[pw_super])
-					stateframe = stateframe | FF_SPR2SUPER;
+				// Add or remove SPR2F_SUPER based on certain conditions
+				spr2 = P_ApplySuperFlagToSprite2(spr2, mobj);
 
-				if (stateframe & FF_SPR2SUPER)
-				{
-					if (mobj->eflags & MFE_FORCENOSUPER)
-						stateframe = stateframe & ~FF_SPR2SUPER;
-				}
-				else if (mobj->eflags & MFE_FORCESUPER)
-					stateframe = stateframe | FF_SPR2SUPER;
+				// Get the needed sprite2 and frame number
+				spr2 = P_GetSkinSprite2(skin, spr2, mobj->player);
 
-				// Get the sprite2 and frame number
-				spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), mobj->player);
-				numframes = skin->sprites[spr2].numframes;
+				spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
+				numframes = sprdef->numframes;
 
-				if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0)
+				if (state == S_PLAY_STND && (spr2 & SPR2F_SUPER) && sprdef[SPR2_WAIT].numframes == 0)
 					mobj->tics = -1;	// If no super wait, don't wait at all
 			}
 			else
@@ -432,12 +435,19 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 			if (mobj->sprite != SPR_PLAY)
 			{
 				mobj->sprite = SPR_PLAY;
-				frame = 0;
+				frame = P_GetSprite2StateFrame(st);
 			}
 			else if (mobj->sprite2 != spr2)
 			{
-				if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2))
-					frame = numframes/2;
+				if (st->frame & FF_SPR2MIDSTART)
+				{
+					if (numframes && P_RandomChance(FRACUNIT/2))
+						frame = numframes/2;
+					else
+						frame = 0;
+				}
+				else if (numframes)
+					frame = P_GetSprite2StateFrame(st) % numframes;
 				else
 					frame = 0;
 			}
@@ -452,6 +462,7 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 					{
 						if (mobj->frame & FF_FRAMEMASK)
 							mobj->frame--;
+
 						return P_SetPlayerMobjState(mobj, st->var1);
 					}
 				}
@@ -539,26 +550,23 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 		{
 			skin_t *skin = ((skin_t *)mobj->skin);
 			UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
-			UINT8 numframes, spr2;
+			UINT8 numframes;
+			UINT16 spr2;
 
 			if (skin)
 			{
-				UINT16 stateframe = st->frame;
+				spr2 = P_GetStateSprite2(st);
 
-				// Add/Remove FF_SPR2SUPER based on certain conditions
-				if (stateframe & FF_SPR2SUPER)
-				{
-					if (mobj->eflags & MFE_FORCENOSUPER)
-						stateframe = stateframe & ~FF_SPR2SUPER;
-				}
-				else if (mobj->eflags & MFE_FORCESUPER)
-					stateframe = stateframe | FF_SPR2SUPER;
+				// Add or remove SPR2F_SUPER based on certain conditions
+				spr2 = P_ApplySuperFlagToSprite2(spr2, mobj);
+
+				// Get the needed sprite2 and frame number
+				spr2 = P_GetSkinSprite2(skin, spr2, NULL);
 
-				// Get the sprite2 and frame number
-				spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), NULL);
-				numframes = skin->sprites[spr2].numframes;
+				spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
+				numframes = sprdef->numframes;
 
-				if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0)
+				if (state == S_PLAY_STND && (spr2 & SPR2F_SUPER) && sprdef[SPR2_WAIT].numframes == 0)
 					mobj->tics = -1;	// If no super wait, don't wait at all
 			}
 			else
@@ -571,12 +579,19 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 			if (mobj->sprite != SPR_PLAY)
 			{
 				mobj->sprite = SPR_PLAY;
-				frame = 0;
+				frame = P_GetSprite2StateFrame(st);
 			}
 			else if (mobj->sprite2 != spr2)
 			{
-				if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2))
-					frame = numframes/2;
+				if (st->frame & FF_SPR2MIDSTART)
+				{
+					if (numframes && P_RandomChance(FRACUNIT/2))
+						frame = numframes/2;
+					else
+						frame = 0;
+				}
+				else if (numframes)
+					frame = P_GetSprite2StateFrame(st) % numframes;
 				else
 					frame = 0;
 			}
@@ -591,6 +606,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 					{
 						if (mobj->frame & FF_FRAMEMASK)
 							mobj->frame--;
+
 						return P_SetMobjState(mobj, st->var1);
 					}
 				}
@@ -917,7 +933,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -926,7 +942,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx += (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy -= (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -935,7 +951,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx -= (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy += (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -944,7 +960,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -1092,9 +1108,8 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line,
 		);
 }
 
-fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+fixed_t P_MobjFloorZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect)
 {
-	I_Assert(mobj != NULL);
 	I_Assert(sector != NULL);
 
 	if (sector->f_slope) {
@@ -1103,14 +1118,14 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 
 		// Get the corner of the object that should be the highest on the slope
 		if (slope->d.x < 0)
-			testx = mobj->radius;
+			testx = radius;
 		else
-			testx = -mobj->radius;
+			testx = -radius;
 
 		if (slope->d.y < 0)
-			testy = mobj->radius;
+			testy = radius;
 		else
-			testy = -mobj->radius;
+			testy = -radius;
 
 		if ((slope->zdelta > 0) ^ !!(lowest)) {
 			testx = -testx;
@@ -1125,7 +1140,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 			return P_GetSlopeZAt(slope, testx, testy);
 
 		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
+		if (perfect && boundsec) {
 			size_t i;
 			line_t *ld;
 			fixed_t bbox[4];
@@ -1136,10 +1151,10 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 			else
 				finalheight = INT32_MIN;
 
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
+			bbox[BOXLEFT] = x-radius;
+			bbox[BOXRIGHT] = x+radius;
+			bbox[BOXTOP] = y+radius;
+			bbox[BOXBOTTOM] = y-radius;
 			for (i = 0; i < boundsec->linecount; i++) {
 				ld = boundsec->lines[i];
 
@@ -1151,9 +1166,9 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 					continue;
 
 				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+					finalheight = min(finalheight, HighestOnLine(radius, x, y, ld, slope, true));
 				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+					finalheight = max(finalheight, HighestOnLine(radius, x, y, ld, slope, false));
 			}
 
 			return finalheight;
@@ -1164,14 +1179,13 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 		if (line == NULL)
 			return P_GetSlopeZAt(slope, x, y);
 
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+		return HighestOnLine(radius, x, y, line, slope, lowest);
 	} else // Well, that makes it easy. Just get the floor height
 		return sector->floorheight;
 }
 
-fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect)
 {
-	I_Assert(mobj != NULL);
 	I_Assert(sector != NULL);
 
 	if (sector->c_slope) {
@@ -1180,14 +1194,14 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 
 		// Get the corner of the object that should be the highest on the slope
 		if (slope->d.x < 0)
-			testx = mobj->radius;
+			testx = radius;
 		else
-			testx = -mobj->radius;
+			testx = -radius;
 
 		if (slope->d.y < 0)
-			testy = mobj->radius;
+			testy = radius;
 		else
-			testy = -mobj->radius;
+			testy = -radius;
 
 		if ((slope->zdelta > 0) ^ !!(lowest)) {
 			testx = -testx;
@@ -1202,7 +1216,7 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 			return P_GetSlopeZAt(slope, testx, testy);
 
 		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
+		if (perfect && boundsec) {
 			size_t i;
 			line_t *ld;
 			fixed_t bbox[4];
@@ -1213,10 +1227,10 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 			else
 				finalheight = INT32_MIN;
 
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
+			bbox[BOXLEFT] = x-radius;
+			bbox[BOXRIGHT] = x+radius;
+			bbox[BOXTOP] = y+radius;
+			bbox[BOXBOTTOM] = y-radius;
 			for (i = 0; i < boundsec->linecount; i++) {
 				ld = boundsec->lines[i];
 
@@ -1228,9 +1242,9 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 					continue;
 
 				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+					finalheight = min(finalheight, HighestOnLine(radius, x, y, ld, slope, true));
 				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+					finalheight = max(finalheight, HighestOnLine(radius, x, y, ld, slope, false));
 			}
 
 			return finalheight;
@@ -1241,165 +1255,11 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 		if (line == NULL)
 			return P_GetSlopeZAt(slope, x, y);
 
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+		return HighestOnLine(radius, x, y, line, slope, lowest);
 	} else // Well, that makes it easy. Just get the ceiling height
 		return sector->ceilingheight;
 }
 
-// Now do the same as all above, but for cameras because apparently cameras are special?
-fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
-{
-	I_Assert(mobj != NULL);
-	I_Assert(sector != NULL);
-
-	if (sector->f_slope) {
-		fixed_t testx, testy;
-		pslope_t *slope = sector->f_slope;
-
-		// Get the corner of the object that should be the highest on the slope
-		if (slope->d.x < 0)
-			testx = mobj->radius;
-		else
-			testx = -mobj->radius;
-
-		if (slope->d.y < 0)
-			testy = mobj->radius;
-		else
-			testy = -mobj->radius;
-
-		if ((slope->zdelta > 0) ^ !!(lowest)) {
-			testx = -testx;
-			testy = -testy;
-		}
-
-		testx += x;
-		testy += y;
-
-		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
-		if (R_IsPointInSector(boundsec ? boundsec : sector, testx, testy))
-			return P_GetSlopeZAt(slope, testx, testy);
-
-		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
-			size_t i;
-			line_t *ld;
-			fixed_t bbox[4];
-			fixed_t finalheight;
-
-			if (lowest)
-				finalheight = INT32_MAX;
-			else
-				finalheight = INT32_MIN;
-
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
-			for (i = 0; i < boundsec->linecount; i++) {
-				ld = boundsec->lines[i];
-
-				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
-				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
-					continue;
-
-				if (P_BoxOnLineSide(bbox, ld) != -1)
-					continue;
-
-				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
-				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
-			}
-
-			return finalheight;
-		}
-
-		// If we're just testing for base sector location (no collision line), just go for the center's spot...
-		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
-		if (line == NULL)
-			return P_GetSlopeZAt(slope, x, y);
-
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
-	} else // Well, that makes it easy. Just get the floor height
-		return sector->floorheight;
-}
-
-fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
-{
-	I_Assert(mobj != NULL);
-	I_Assert(sector != NULL);
-
-	if (sector->c_slope) {
-		fixed_t testx, testy;
-		pslope_t *slope = sector->c_slope;
-
-		// Get the corner of the object that should be the highest on the slope
-		if (slope->d.x < 0)
-			testx = mobj->radius;
-		else
-			testx = -mobj->radius;
-
-		if (slope->d.y < 0)
-			testy = mobj->radius;
-		else
-			testy = -mobj->radius;
-
-		if ((slope->zdelta > 0) ^ !!(lowest)) {
-			testx = -testx;
-			testy = -testy;
-		}
-
-		testx += x;
-		testy += y;
-
-		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
-		if (R_IsPointInSector(boundsec ? boundsec : sector, testx, testy))
-			return P_GetSlopeZAt(slope, testx, testy);
-
-		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
-			size_t i;
-			line_t *ld;
-			fixed_t bbox[4];
-			fixed_t finalheight;
-
-			if (lowest)
-				finalheight = INT32_MAX;
-			else
-				finalheight = INT32_MIN;
-
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
-			for (i = 0; i < boundsec->linecount; i++) {
-				ld = boundsec->lines[i];
-
-				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
-				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
-					continue;
-
-				if (P_BoxOnLineSide(bbox, ld) != -1)
-					continue;
-
-				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
-				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
-			}
-
-			return finalheight;
-		}
-
-		// If we're just testing for base sector location (no collision line), just go for the center's spot...
-		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
-		if (line == NULL)
-			return P_GetSlopeZAt(slope, x, y);
-
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
-	} else // Well, that makes it easy. Just get the ceiling height
-		return sector->ceilingheight;
-}
 static void P_PlayerFlip(mobj_t *mo)
 {
 	if (!mo->player)
@@ -2118,7 +1978,7 @@ void P_RingXYMovement(mobj_t *mo)
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
-	if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy))
+	if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy) && !P_MobjWasRemoved(mo))
 		P_SlideMove(mo);
 }
 
@@ -2132,8 +1992,10 @@ void P_SceneryXYMovement(mobj_t *mo)
 	oldx = mo->x;
 	oldy = mo->y;
 
-	if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy))
+	if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy) && !P_MobjWasRemoved(mo))
 		P_SlideMove(mo);
+	if (P_MobjWasRemoved(mo))
+		return;
 
 	if ((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz))
 		return; // no friction when airborne
@@ -2329,8 +2191,8 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
 	if (mo->player && mo->player->pflags & PF_GODMODE)
 		return false;
 
-	fixed_t sectorFloor = P_GetSectorFloorZAt(mo->subsector->sector, mo->x, mo->y);
-	fixed_t sectorCeiling = P_GetSectorCeilingZAt(mo->subsector->sector, mo->x, mo->y);
+	fixed_t sectorFloor = P_GetSpecialBottomZ(mo, mo->subsector->sector, mo->subsector->sector);
+	fixed_t sectorCeiling = P_GetSpecialTopZ(mo, mo->subsector->sector, mo->subsector->sector);
 
 	if (((mo->z <= sectorFloor
 		&& ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_FLOOR))
@@ -3111,8 +2973,7 @@ boolean P_SceneryZMovement(mobj_t *mo)
 						continue;
 					explodemo->momx += ((prandom & 0x0F) << (FRACBITS-2)) * (i & 2 ? -1 : 1);
 					explodemo->momy += ((prandom & 0xF0) << (FRACBITS-6)) * (i & 1 ? -1 : 1);
-					explodemo->destscale = mo->scale;
-					P_SetScale(explodemo, mo->scale);
+					P_SetScale(explodemo, mo->scale, true);
 				}
 
 				if (mo->threshold != 42) // Don't make pop sound if threshold is 42.
@@ -3138,7 +2999,7 @@ boolean P_SceneryZMovement(mobj_t *mo)
 				mobj_t *flower = P_SpawnMobjFromMobj(mo, 0, 0, 0, flowertype);
 				if (flower)
 				{
-					P_SetScale(flower, mo->scale/16);
+					P_SetScale(flower, mo->scale/16, true);
 					flower->destscale = mo->scale;
 					flower->scalespeed = mo->scale/8;
 				}
@@ -3378,10 +3239,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 				else
 					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype);
 				if (!P_MobjWasRemoved(splish))
-				{
-					splish->destscale = mobj->scale;
-					P_SetScale(splish, mobj->scale);
-				}
+					P_SetScale(splish, mobj->scale, true);
 			}
 
 			// skipping stone!
@@ -3420,10 +3278,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 				else
 					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype);
 				if (!P_MobjWasRemoved(splish))
-				{
-					splish->destscale = mobj->scale;
-					P_SetScale(splish, mobj->scale);
-				}
+					P_SetScale(splish, mobj->scale, true);
 			}
 		}
 
@@ -3474,8 +3329,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 					else
 						bubble->momz = 0;
 
-					bubble->destscale = mobj->scale;
-					P_SetScale(bubble, mobj->scale);
+					P_SetScale(bubble, mobj->scale, true);
 				}
 			}
 		}
@@ -3917,6 +3771,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 	}
 	else
 		P_TryMove(mobj, mobj->x, mobj->y, true);
+	if (P_MobjWasRemoved(mobj))
+		return;
 
 	P_CheckCrumblingPlatforms(mobj);
 
@@ -4711,6 +4567,8 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz)
 		{
 			seg->z = bz + (dz*(9-s));
 			P_TryMove(seg, workx + (dx*s), worky + (dy*s), true);
+			if (P_MobjWasRemoved(seg))
+				return;
 		}
 		angle += ANGLE_MAX/3;
 	}
@@ -4948,6 +4806,8 @@ static void P_Boss4Thinker(mobj_t *mobj)
 				(mobj->spawnpoint->x<<FRACBITS) - P_ReturnThrustX(mobj, mobj->angle, mobj->movefactor),
 				(mobj->spawnpoint->y<<FRACBITS) - P_ReturnThrustY(mobj, mobj->angle, mobj->movefactor),
 				true);
+		if (P_MobjWasRemoved(mobj))
+			return;
 
 		P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
 
@@ -5139,8 +4999,7 @@ static void P_Boss7Thinker(mobj_t *mobj)
 		mobj_t *smoke = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height, MT_SMOKE);
 		if (!P_MobjWasRemoved(smoke))
 		{
-			smoke->destscale = mobj->destscale;
-			P_SetScale(smoke, smoke->destscale);
+			P_SetScale(smoke, mobj->destscale, true);
 			smoke->momz = FixedMul(FRACUNIT, smoke->scale);
 		}
 	}
@@ -5517,6 +5376,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
 	{
 		P_InstaThrust(mobj, mobj->angle, -4*FRACUNIT);
 		P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true);
+		if (P_MobjWasRemoved(mobj))
+			return;
 		mobj->momz -= gravity;
 		if (mobj->z < mobj->watertop || mobj->z < (mobj->floorz + 16*FRACUNIT))
 		{
@@ -5589,7 +5450,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 				if (mobj->hprev)
 				{
 					mobj->hprev->destscale = FRACUNIT + (2*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
-					P_SetScale(mobj->hprev, mobj->hprev->destscale);
+					P_SetScale(mobj->hprev, mobj->hprev->destscale, false);
 
 					P_MoveOrigin(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2);
 					mobj->hprev->momx = mobj->momx;
@@ -5615,8 +5476,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
 						{
 							S_StopSound(missile);
 							if (mobj->extravalue1 >= 2)
-								P_SetScale(missile, FRACUNIT>>1);
-							missile->destscale = missile->scale>>1;
+								P_SetScale(missile, FRACUNIT/2, true);
+							missile->destscale = missile->scale/2;
 							missile->fuse = TICRATE/2;
 							missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse;
 							missile->z -= missile->height/2;
@@ -5639,7 +5500,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 									spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2);
 									P_InstaThrust(spread,spread->angle,-spread->info->speed);
 									spread->momz = missile->momz;
-									P_SetScale(spread, missile->scale);
+									P_SetScale(spread, missile->scale, true);
 									spread->destscale = missile->destscale;
 									spread->scalespeed = missile->scalespeed;
 									spread->fuse = missile->fuse;
@@ -5663,7 +5524,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 										spread = P_SpawnMissile(mobj, mobj->target, missile->type);
 										if (P_MobjWasRemoved(spread))
 											continue;
-										P_SetScale(spread, missile->scale);
+										P_SetScale(spread, missile->scale, true);
 										spread->destscale = missile->destscale;
 										spread->fuse = missile->fuse;
 										spread->z -= spread->height/2;
@@ -5720,12 +5581,12 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					{
 						if (mobj->health > mobj->info->damage)
 						{
-							P_SetScale(missile, FRACUNIT/3);
+							P_SetScale(missile, FRACUNIT/3, true);
 							missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power
 						}
 						else
 						{
-							P_SetScale(missile, FRACUNIT/5);
+							P_SetScale(missile, FRACUNIT/5, true);
 							missile->color = SKINCOLOR_SUNSET; // sonic cd electric power
 						}
 						missile->destscale = missile->scale*2;
@@ -5788,10 +5649,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					if (!P_MobjWasRemoved(missile))
 					{
 						if (mobj->extravalue1 >= 2)
-						{
-							missile->destscale = FRACUNIT>>1;
-							P_SetScale(missile, missile->destscale);
-						}
+							P_SetScale(missile, FRACUNIT/2, true);
 						missile->fuse = 3*TICRATE;
 						missile->z -= missile->height/2;
 
@@ -5810,8 +5668,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 								spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2);
 								P_InstaThrust(spread,spread->angle,spread->info->speed);
 								spread->momz = missile->momz;
-								spread->destscale = FRACUNIT>>1;
-								P_SetScale(spread, spread->destscale);
+								P_SetScale(spread, FRACUNIT/2, true);
 								spread->fuse = missile->fuse;
 							}
 							P_InstaThrust(missile,missile->angle,missile->info->speed);
@@ -5828,8 +5685,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 									spread = P_SpawnMissile(mobj, mobj->target, missile->type);
 									if (!P_MobjWasRemoved(spread))
 									{
-										spread->destscale = FRACUNIT>>1;
-										P_SetScale(spread, spread->destscale);
+										P_SetScale(spread, FRACUNIT/2, true);
 										spread->fuse = missile->fuse;
 										spread->z -= spread->height/2;
 									}
@@ -5865,6 +5721,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT);
 				if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true))
 				{ // Hit a wall? Find a direction to bounce
+					if (P_MobjWasRemoved(mobj))
+						return;
 					mobj->threshold--;
 					if (!mobj->threshold) { // failed bounce!
 						S_StartSound(mobj, sfx_mspogo);
@@ -5905,6 +5763,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
 			P_InstaThrust(mobj, mobj->angle, -speed);
 			while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16)
 			{
+				if (P_MobjWasRemoved(mobj))
+					return;
 				S_StartSound(mobj, sfx_mspogo);
 				P_BounceMove(mobj);
 				mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0);
@@ -6089,8 +5949,12 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					whoosh->flags |= MF_NOCLIPHEIGHT;
 #endif
 
-					P_SetMobjState(mobj->tracer, S_JETFUMEFLASH);
-					P_SetScale(mobj->tracer, mobj->scale << 1);
+					if (!P_MobjWasRemoved(mobj->tracer))
+					{
+						P_SetMobjState(mobj->tracer, S_JETFUMEFLASH);
+						P_SetScale(mobj->tracer, 2*mobj->scale, false);
+						mobj->tracer->old_scale = mobj->tracer->scale;
+					}
 				}
 				else
 				{
@@ -6425,28 +6289,24 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb
 //
 // Sets the sprite scaling
 //
-void P_SetScale(mobj_t *mobj, fixed_t newscale)
+void P_SetScale(mobj_t *mobj, fixed_t newscale, boolean instant)
 {
-	player_t *player;
-	fixed_t oldscale;
-
 	if (!mobj)
 		return;
 
-	oldscale = mobj->scale; //keep for adjusting stuff below
-
-	mobj->scale = newscale;
-
-	mobj->radius = FixedMul(FixedDiv(mobj->radius, oldscale), newscale);
-	mobj->height = FixedMul(FixedDiv(mobj->height, oldscale), newscale);
-
-	player = mobj->player;
-
-	if (player)
+	if (mobj->player)
 	{
 		G_GhostAddScale(newscale);
-		player->viewheight = FixedMul(FixedDiv(player->viewheight, oldscale), newscale); // Nonono don't calculate viewheight elsewhere, this is the best place for it!
+		// Nonono don't calculate viewheight elsewhere, this is the best place for it!
+		mobj->player->viewheight = FixedMul(FixedDiv(mobj->player->viewheight, mobj->scale), newscale);
 	}
+
+	mobj->radius = FixedMul(FixedDiv(mobj->radius, mobj->scale), newscale);
+	mobj->height = FixedMul(FixedDiv(mobj->height, mobj->scale), newscale);
+
+	mobj->scale = newscale;
+	if (instant)
+		mobj->destscale = mobj->old_scale = newscale;
 }
 
 void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on your target
@@ -6801,8 +6661,7 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
 	thing->flags |= MF_NOCLIPHEIGHT;
 	thing->eflags = (thing->eflags & ~MFE_VERTICALFLIP)|(thing->target->eflags & MFE_VERTICALFLIP);
 
-	P_SetScale(thing, FixedMul(thing->target->scale, thing->target->player->shieldscale));
-	thing->destscale = thing->scale;
+	P_SetScale(thing, FixedMul(thing->target->scale, thing->target->player->shieldscale), true);
 	thing->old_scale = FixedMul(thing->target->old_scale, thing->target->player->shieldscale);
 
 #define NewMH(mobj)   mobj->height // Ugly mobj-height and player-height defines, for the sake of prettier code
@@ -7150,11 +7009,11 @@ static void P_MobjScaleThink(mobj_t *mobj)
 		correctionType = 2; // Correct Z position by moving down
 
 	if (abs(mobj->scale - mobj->destscale) < mobj->scalespeed)
-		P_SetScale(mobj, mobj->destscale);
+		P_SetScale(mobj, mobj->destscale, false);
 	else if (mobj->scale < mobj->destscale)
-		P_SetScale(mobj, mobj->scale + mobj->scalespeed);
+		P_SetScale(mobj, mobj->scale + mobj->scalespeed, false);
 	else if (mobj->scale > mobj->destscale)
-		P_SetScale(mobj, mobj->scale - mobj->scalespeed);
+		P_SetScale(mobj, mobj->scale - mobj->scalespeed, false);
 
 	if (correctionType == 1)
 		mobj->z -= (mobj->height - oldheight)/2;
@@ -7247,8 +7106,9 @@ static boolean P_DrownNumbersSceneryThink(mobj_t *mobj)
 	mobj->x = mobj->target->x;
 	mobj->y = mobj->target->y;
 
+	P_SetScale(mobj, mobj->target->scale, false);
 	mobj->destscale = mobj->target->destscale;
-	P_SetScale(mobj, mobj->target->scale);
+	mobj->old_scale = mobj->target->old_scale;
 
 	if (mobj->target->eflags & MFE_VERTICALFLIP)
 	{
@@ -7409,10 +7269,10 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj)
 				(mobjtype_t)mobj->threshold);
 			if (!P_MobjWasRemoved(spawn))
 			{
-				P_SetScale(spawn, mobj->scale);
-				spawn->momz = FixedMul(mobj->movefactor, spawn->scale);
+				P_SetScale(spawn, mobj->scale, true);
 				spawn->destscale = spawn->scale/100;
 				spawn->scalespeed = spawn->scale/mobj->health;
+				spawn->momz = FixedMul(mobj->movefactor, spawn->scale);
 				spawn->tics = (tic_t)mobj->health;
 				spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP);
 				spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
@@ -7504,6 +7364,8 @@ static void P_RosySceneryThink(mobj_t *mobj)
 			fixed_t x = mobj->x, y = mobj->y, z = mobj->z;
 			angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y);
 			boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false);
+			if (P_MobjWasRemoved(mobj))
+				return;
 
 			P_UnsetThingPosition(mobj);
 			mobj->x = x;
@@ -7630,8 +7492,7 @@ static void P_RosySceneryThink(mobj_t *mobj)
 			mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT);
 			if (!P_MobjWasRemoved(cdlhrt))
 			{
-				cdlhrt->destscale = (5*mobj->scale) >> 4;
-				P_SetScale(cdlhrt, cdlhrt->destscale);
+				P_SetScale(cdlhrt, (5*mobj->scale) >> 4, true);
 				cdlhrt->fuse = (5*TICRATE) >> 1;
 				cdlhrt->momz = mobj->scale;
 				P_SetTarget(&cdlhrt->target, mobj);
@@ -7885,8 +7746,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
 
 		mobj->eflags |= (mobj->target->eflags & MFE_VERTICALFLIP);
 
+		P_SetScale(mobj, mobj->target->scale, false);
 		mobj->destscale = mobj->target->destscale;
-		P_SetScale(mobj, mobj->target->scale);
+		mobj->old_scale = mobj->target->old_scale;
 
 		if (!(mobj->eflags & MFE_VERTICALFLIP))
 			mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale);
@@ -8036,7 +7898,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
 		}
 		P_SetThingPosition(mobj);
 
-		P_SetScale(mobj, mobj->target->scale);
+		P_SetScale(mobj, mobj->target->scale, false);
+		mobj->destscale = mobj->target->destscale;
+		mobj->old_scale = mobj->target->old_scale;
 	}
 	break;
 	case MT_TUTORIALFLOWER:
@@ -8067,7 +7931,8 @@ static void P_MobjSceneryThink(mobj_t *mobj)
 		break;
 	}
 
-	P_SceneryThinker(mobj);
+	if (!P_MobjWasRemoved(mobj))
+		P_SceneryThinker(mobj);
 }
 
 static boolean P_MobjPushableThink(mobj_t *mobj)
@@ -8477,8 +8342,8 @@ static void P_ArrowThink(mobj_t *mobj)
 			if (!P_MobjWasRemoved(dust))
 			{
 				dust->tics = 18;
-				dust->scalespeed = 4096;
 				dust->destscale = FRACUNIT/32;
+				dust->scalespeed = FRACUNIT/16;
 			}
 		}
 	}
@@ -9889,9 +9754,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
 			traindust->frame = P_RandomRange(0, 8)|FF_TRANS90;
 			traindust->angle = mobj->angle;
 			traindust->tics = TICRATE*4;
+			P_SetScale(traindust, FRACUNIT*6, true);
 			traindust->destscale = FRACUNIT*64;
 			traindust->scalespeed = FRACUNIT/24;
-			P_SetScale(traindust, FRACUNIT*6);
 		}
 		break;
 	case MT_TRAINSTEAMSPAWNER:
@@ -9902,9 +9767,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
 			P_SetMobjState(steam, S_TRAINSTEAM);
 			steam->frame = P_RandomRange(0, 1)|FF_TRANS90;
 			steam->tics = TICRATE*8;
+			P_SetScale(steam, FRACUNIT*16, true);
 			steam->destscale = FRACUNIT*64;
 			steam->scalespeed = FRACUNIT/8;
-			P_SetScale(steam, FRACUNIT*16);
 			steam->momx = P_SignedRandom()*32;
 			steam->momy = -64*FRACUNIT;
 			steam->momz = 2*FRACUNIT;
@@ -10429,6 +10294,8 @@ void P_MobjThinker(mobj_t *mobj)
 		|| mobj->type == MT_CANNONBALLDECOR
 		|| mobj->type == MT_FALLINGROCK) {
 		P_TryMove(mobj, mobj->x, mobj->y, true); // Sets mo->standingslope correctly
+		if (P_MobjWasRemoved(mobj))
+			return;
 		//if (mobj->standingslope) CONS_Printf("slope physics on mobj\n");
 		P_ButteredSlope(mobj);
 	}
@@ -10530,6 +10397,8 @@ void P_PushableThinker(mobj_t *mobj)
 	// it has to be pushable RIGHT NOW for this part to happen
 	if (mobj->flags & MF_PUSHABLE && !(mobj->momx || mobj->momy))
 		P_TryMove(mobj, mobj->x, mobj->y, true);
+	if (P_MobjWasRemoved(mobj))
+		return;
 
 	if (mobj->type == MT_MINECART && mobj->health)
 	{
@@ -10906,7 +10775,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 			if (titlemapinaction) mobj->flags &= ~MF_NOTHINK;
 			break;
 		case MT_LOCKONINF:
-			P_SetScale(mobj, (mobj->destscale = 3*mobj->scale));
+			P_SetScale(mobj, 3*mobj->scale, true);
 			break;
 		case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE:
 			mobj->fuse = mobj->info->painchance;
@@ -10917,8 +10786,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				if (P_MobjWasRemoved(spawn))
 					break;
 
-				spawn->destscale = mobj->scale;
-				P_SetScale(spawn, mobj->scale);
+				P_SetScale(spawn, mobj->scale, true);
 				P_SetTarget(&spawn->target, mobj);
 			}
 			break;
@@ -10935,8 +10803,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				if (P_MobjWasRemoved(spawn))
 					break;
 
-				spawn->destscale = mobj->scale;
-				P_SetScale(spawn, mobj->scale);
+				P_SetScale(spawn, mobj->scale, true);
 				P_SetTarget(&mobj->tracer, spawn);
 				P_SetTarget(&spawn->target, mobj);
 			}
@@ -10953,8 +10820,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 					if (P_MobjWasRemoved(ball))
 						continue;
 
-					ball->destscale = mobj->scale;
-					P_SetScale(ball, mobj->scale);
+					P_SetScale(ball, mobj->scale, true);
 					P_SetTarget(&ball->target, mobj);
 					ball->movedir = FixedAngle(FixedMul(FixedDiv(i<<FRACBITS, mobj->info->damage<<FRACBITS), 360<<FRACBITS));
 					ball->threshold = ball->radius + mobj->radius + FixedMul(ball->info->painchance, ball->scale);
@@ -10975,8 +10841,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 					if (P_MobjWasRemoved(ball))
 						continue;
 
-					ball->destscale = mobj->scale;
-					P_SetScale(ball, mobj->scale);
+					P_SetScale(ball, mobj->scale, true);
 					P_SetTarget(&lastball->tracer, ball);
 					P_SetTarget(&ball->target, mobj);
 					lastball = ball;
@@ -11188,7 +11053,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 
 	if (mobj->skin) // correct inadequecies above.
 	{
-		mobj->sprite2 = P_GetSkinSprite2(mobj->skin, (mobj->frame & FF_FRAMEMASK), NULL);
+		mobj->sprite2 = P_GetSkinSprite2(mobj->skin, P_GetStateSprite2(mobj->state), NULL);
 		mobj->frame &= ~FF_FRAMEMASK;
 	}
 
@@ -11835,7 +11700,7 @@ void P_SpawnPlayer(INT32 playernum)
 	p->awayviewtics = 0;
 
 	// set the scale to the mobj's destscale so settings get correctly set.  if we don't, they sometimes don't.
-	P_SetScale(mobj, mobj->destscale);
+	P_SetScale(mobj, mobj->destscale, true);
 	P_FlashPal(p, 0, 0); // Resets
 
 	// Set bounds accurately.
@@ -12009,7 +11874,7 @@ void P_MovePlayerToStarpost(INT32 playernum)
 
 	z = p->starpostz << FRACBITS;
 
-	P_SetScale(mobj, (mobj->destscale = abs(p->starpostscale)));
+	P_SetScale(mobj, abs(p->starpostscale), true);
 
 	if (p->starpostscale < 0)
 	{
@@ -13117,8 +12982,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 			if (P_MobjWasRemoved(corona))
 				break;
 
-			P_SetScale(corona, (corona->destscale = mobj->scale*3));
 			P_SetTarget(&mobj->tracer, corona);
+			P_SetScale(corona, 3*mobj->scale, true);
 		}
 		break;
 	case MT_FLAMEHOLDER:
@@ -13136,8 +13001,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				if (P_MobjWasRemoved(corona))
 					break;
 
-				P_SetScale(corona, (corona->destscale = flame->scale*3));
 				P_SetTarget(&flame->tracer, corona);
+				P_SetScale(corona, 3*flame->scale, true);
 			}
 		}
 		break;
@@ -13225,10 +13090,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	case MT_DSZSTALAGMITE:
 	case MT_DSZ2STALAGMITE:
 	case MT_KELP:
-		if (mthing->args[0]) { // make mobj twice as big as normal
-			P_SetScale(mobj, 2*mobj->scale); // not 2*FRACUNIT in case of something like the old ERZ3 mode
-			mobj->destscale = mobj->scale;
-		}
+		if (mthing->args[0]) // make mobj twice as big as normal
+			P_SetScale(mobj, 2*mobj->scale, true); // not 2*FRACUNIT in case of something like the old ERZ3 mode
 		break;
 	case MT_THZTREE:
 	{ // Spawn the branches
@@ -13307,10 +13170,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	case MT_LAVAFALL:
 		mobj->fuse = 30 + mthing->args[0];
 		if (mthing->args[1])
-		{
-			P_SetScale(mobj, 2*mobj->scale);
-			mobj->destscale = mobj->scale;
-		}
+			P_SetScale(mobj, 2*mobj->scale, true);
 		break;
 	case MT_PYREFLY:
 		//start on fire if args[0], otherwise behave normally
@@ -13373,8 +13233,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				break;
 			P_SetTarget(&elecmobj->target, mobj);
 			elecmobj->angle = FixedAngle(mthing->angle << FRACBITS);
-			elecmobj->destscale = mobj->scale*2;
-			P_SetScale(elecmobj, elecmobj->destscale);
+			P_SetScale(elecmobj, 2*mobj->scale, true);
 		}
 		break;
 	case MT_STARPOST:
@@ -13432,8 +13291,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				return false;
 			}
 			base->angle = mobjangle + ANGLE_90;
+			P_SetScale(base, mobj->scale, true);
 			base->destscale = mobj->destscale;
-			P_SetScale(base, mobj->scale);
 			P_SetTarget(&base->target, mobj);
 			P_SetTarget(&mobj->tracer, base);
 		}
@@ -13610,8 +13469,9 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
 		return NULL;
 	mobj->spawnpoint = mthing;
 
-	P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
+	P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale), false);
 	mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
+	mobj->old_scale = FixedMul(mobj->old_scale, mthing->scale);
 
 	mobj->spritexscale = mthing->spritexscale;
 	mobj->spriteyscale = mthing->spriteyscale;
@@ -14032,7 +13892,8 @@ boolean P_CheckMissileSpawn(mobj_t *th)
 
 	if (!P_TryMove(th, th->x, th->y, true))
 	{
-		P_ExplodeMissile(th);
+		if (!P_MobjWasRemoved(th))
+			P_ExplodeMissile(th);
 		return false;
 	}
 	return true;
@@ -14064,8 +13925,7 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type,
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	speed = FixedMul(th->info->speed, th->scale);
 
@@ -14128,8 +13988,7 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	speed = FixedMul(th->info->speed, th->scale);
 
@@ -14195,8 +14054,7 @@ mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za,
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	speed = FixedMul(th->info->speed, th->scale);
 
@@ -14267,8 +14125,7 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	if (source->type == MT_METALSONIC_BATTLE && source->health < 4)
 		speed = FixedMul(FixedMul(th->info->speed, 3*FRACUNIT/2), th->scale);
@@ -14370,8 +14227,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	th->flags2 |= flags2;
 
@@ -14453,8 +14309,8 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
 		newmobj->old_z2 = mobj->old_z2 + zofs;
 	}
 
+	P_SetScale(newmobj, mobj->scale, false);
 	newmobj->destscale = mobj->destscale;
-	P_SetScale(newmobj, mobj->scale);
 
 	newmobj->old_x2 = mobj->old_x2 + xofs;
 	newmobj->old_y2 = mobj->old_y2 + yofs;
@@ -14483,9 +14339,13 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
 
 	newmobj->old_scale2 = mobj->old_scale2;
 	newmobj->old_scale = mobj->old_scale;
+	newmobj->old_spritexscale2 = mobj->old_spritexscale2;
 	newmobj->old_spritexscale = mobj->old_spritexscale;
+	newmobj->old_spriteyscale2 = mobj->old_spriteyscale2;
 	newmobj->old_spriteyscale = mobj->old_spriteyscale;
+	newmobj->old_spritexoffset2 = mobj->old_spritexoffset2;
 	newmobj->old_spritexoffset = mobj->old_spritexoffset;
+	newmobj->old_spriteyoffset2 = mobj->old_spriteyoffset2;
 	newmobj->old_spriteyoffset = mobj->old_spriteyoffset;
 
 	return newmobj;
diff --git a/src/p_mobj.h b/src/p_mobj.h
index f833415ed1d0af3ee377ed6d4ced943d2782f499..2f013a2f30fac7f7d117cb190fcbc5bd1db17e54 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -308,15 +308,15 @@ typedef struct mobj_s
 	angle_t spriteroll, old_spriteroll, old_spriteroll2;
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
-	UINT8 sprite2; // player sprites
+	UINT16 sprite2; // player sprites
 	UINT16 anim_duration; // for FF_ANIMATE states
 
 	UINT32 renderflags; // render flags
 	INT32 blendmode; // blend mode
 	fixed_t spritexscale, spriteyscale;
 	fixed_t spritexoffset, spriteyoffset;
-	fixed_t old_spritexscale, old_spriteyscale;
-	fixed_t old_spritexoffset, old_spriteyoffset;
+	fixed_t old_spritexscale, old_spriteyscale, old_spritexscale2, old_spriteyscale2;
+	fixed_t old_spritexoffset, old_spriteyoffset, old_spritexoffset2, old_spriteyoffset2;
 	struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by
 
 	struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears
@@ -451,15 +451,15 @@ typedef struct precipmobj_s
 	angle_t spriteroll, old_spriteroll, old_spriteroll2;
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
-	UINT8 sprite2; // player sprites
+	UINT16 sprite2; // player sprites
 	UINT16 anim_duration; // for FF_ANIMATE states
 
 	UINT32 renderflags; // render flags
 	INT32 blendmode; // blend mode
 	fixed_t spritexscale, spriteyscale;
 	fixed_t spritexoffset, spriteyoffset;
-	fixed_t old_spritexscale, old_spriteyscale;
-	fixed_t old_spritexoffset, old_spriteyoffset;
+	fixed_t old_spritexscale, old_spriteyscale, old_spritexscale2, old_spriteyscale2;
+	fixed_t old_spritexoffset, old_spriteyoffset, old_spritexoffset2, old_spriteyoffset2;
 	struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by
 
 	struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears
@@ -527,7 +527,7 @@ void P_SnowThinker(precipmobj_t *mobj);
 void P_RainThinker(precipmobj_t *mobj);
 void P_NullPrecipThinker(precipmobj_t *mobj);
 void P_RemovePrecipMobj(precipmobj_t *mobj);
-void P_SetScale(mobj_t *mobj, fixed_t newscale);
+void P_SetScale(mobj_t *mobj, fixed_t newscale, boolean instant);
 void P_XYMovement(mobj_t *mo);
 void P_RingXYMovement(mobj_t *mo);
 void P_SceneryXYMovement(mobj_t *mo);
diff --git a/src/p_pspr.h b/src/p_pspr.h
index 69e5eeeb3fc902e12782cf63672731aa5ebd0c36..6510190f118fb639c52a22576dd911023d3b134c 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -35,11 +35,11 @@
 #pragma interface
 #endif
 
-/// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 63, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER)
+/// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 255, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER)
 #define FF_FRAMEMASK 0xff
 
 /// \brief Frame flags - SPR2: Super sprite2
-#define FF_SPR2SUPER 0x80
+#define FF_SPR2SUPER SPR2F_SUPER //TODO: 2.3: remove this backwards compat hack
 /// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation
 #define FF_SPR2ENDSTATE 0x100
 /// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation
@@ -97,6 +97,11 @@
 /// \brief Frame flags - Animate: Start at a random place in the animation (mutually exclusive with above)
 #define FF_RANDOMANIM 0x40000000
 
+/// \brief Animation flags: Bits used for the animation ID
+#define SPR2F_MASK 0x3FF
+/// \brief Animation flags: "Super" flag
+#define SPR2F_SUPER 0x400
+
 /**	\brief translucency tables
 
 	\todo add another asm routine which use the fg and bg indexes in the
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 6c6548c567f195cfc7bbc884e1e45dea18afde1a..5e4d6d0760441e6bc94c6815824b8b7e1ab38c80 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -170,6 +170,7 @@ static void P_NetArchivePlayers(void)
 		WRITEUINT8(save_p, players[i].panim);
 		WRITEUINT8(save_p, players[i].stronganim);
 		WRITEUINT8(save_p, players[i].spectator);
+		WRITEUINT8(save_p, players[i].muted);
 
 		WRITEUINT16(save_p, players[i].flashpal);
 		WRITEUINT16(save_p, players[i].flashcount);
@@ -260,6 +261,7 @@ static void P_NetArchivePlayers(void)
 		WRITEUINT8(save_p, players[i].marelap);
 		WRITEUINT8(save_p, players[i].marebonuslap);
 		WRITEUINT32(save_p, players[i].marebegunat);
+		WRITEUINT32(save_p, players[i].lastmaretime);
 		WRITEUINT32(save_p, players[i].startedtime);
 		WRITEUINT32(save_p, players[i].finishedtime);
 		WRITEUINT32(save_p, players[i].lapbegunat);
@@ -399,6 +401,7 @@ static void P_NetUnArchivePlayers(void)
 		players[i].panim = READUINT8(save_p);
 		players[i].stronganim = READUINT8(save_p);
 		players[i].spectator = READUINT8(save_p);
+		players[i].muted = READUINT8(save_p);
 
 		players[i].flashpal = READUINT16(save_p);
 		players[i].flashcount = READUINT16(save_p);
@@ -490,6 +493,7 @@ static void P_NetUnArchivePlayers(void)
 		players[i].marelap = READUINT8(save_p);
 		players[i].marebonuslap = READUINT8(save_p);
 		players[i].marebegunat = READUINT32(save_p);
+		players[i].lastmaretime = READUINT32(save_p);
 		players[i].startedtime = READUINT32(save_p);
 		players[i].finishedtime = READUINT32(save_p);
 		players[i].lapbegunat = READUINT32(save_p);
@@ -1880,7 +1884,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 		diff |= MD_TICS;
 	if (mobj->sprite != mobj->state->sprite)
 		diff |= MD_SPRITE;
-	if (mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK))
+	if (mobj->sprite == SPR_PLAY && mobj->sprite2 != P_GetStateSprite2(mobj->state))
 		diff |= MD_SPRITE;
 	if (mobj->frame != mobj->state->frame)
 		diff |= MD_FRAME;
@@ -2064,7 +2068,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 	if (diff & MD_SPRITE) {
 		WRITEUINT16(save_p, mobj->sprite);
 		if (mobj->sprite == SPR_PLAY)
-			WRITEUINT8(save_p, mobj->sprite2);
+			WRITEUINT16(save_p, mobj->sprite2);
 	}
 	if (diff & MD_FRAME)
 	{
@@ -3094,12 +3098,12 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 	if (diff & MD_SPRITE) {
 		mobj->sprite = READUINT16(save_p);
 		if (mobj->sprite == SPR_PLAY)
-			mobj->sprite2 = READUINT8(save_p);
+			mobj->sprite2 = READUINT16(save_p);
 	}
 	else {
 		mobj->sprite = mobj->state->sprite;
 		if (mobj->sprite == SPR_PLAY)
-			mobj->sprite2 = mobj->state->frame&FF_FRAMEMASK;
+			mobj->sprite2 = P_GetStateSprite2(mobj->state);
 	}
 	if (diff & MD_FRAME)
 	{
diff --git a/src/p_setup.c b/src/p_setup.c
index 396639b7263e7801f8bc0b8ce0fc48213c153cff..41487d702f265c7e5164c61be8d0b8f8c059aa38 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -358,6 +358,8 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
 	mapheaderinfo[num]->marathonnext = 0;
 	mapheaderinfo[num]->startrings = 0;
 	mapheaderinfo[num]->sstimer = 90;
+	for (UINT8 n = 0; n < 8; n++)
+		mapheaderinfo[num]->nightstimer[n] = 0;
 	mapheaderinfo[num]->ssspheres = 1;
 	mapheaderinfo[num]->gravity = FRACUNIT/2;
 	mapheaderinfo[num]->keywords[0] = '\0';
@@ -525,6 +527,29 @@ UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade)
 	return score;
 }
 
+void P_AddNiGHTSTimes(INT16 i, char *gtext)
+{
+	char *spos = gtext;
+	
+	for (UINT8 n = 0; n < 8; n++)
+	{
+		if (spos != NULL)
+		{
+			mapheaderinfo[i]->nightstimer[n] = atoi(spos);
+			CONS_Debug(DBG_SETUP, "%u ", atoi(spos));
+			// Grab next comma
+			spos = strchr(spos, ',');
+			if (spos)
+				++spos;
+		}
+		else
+		{
+			mapheaderinfo[i]->nightstimer[n] = 0;
+		}
+	}
+
+}
+
 //
 // levelflats
 //
@@ -877,14 +902,32 @@ static void P_SpawnMapThings(boolean spawnemblems)
 		P_SpawnEmeraldHunt();
 }
 
+static void P_WriteTextmap_Things(FILE *f, const mapthing_t *wmapthings); // proto
+
 // Experimental groovy write function!
-/*void P_WriteThings(void)
+void P_WriteThings(const char *filepath)
 {
 	size_t i, length;
 	mapthing_t *mt;
 	UINT8 *savebuffer, *savebuf_p;
 	INT16 temp;
 
+	if (udmf)
+	{
+		FILE *f = fopen(va("%s.txt", filepath), "w");
+		if (!f)
+		{
+			CONS_Alert(CONS_ERROR, M_GetText("Couldn't write to file %s\n"), filepath);
+			return;
+		}
+
+		P_WriteTextmap_Things(f, mapthings);
+		fclose(f);
+
+		CONS_Printf(M_GetText("%s.txt saved.\n"), filepath);
+		return;
+	}
+
 	savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t));
 
 	if (!savebuf_p)
@@ -908,12 +951,12 @@ static void P_SpawnMapThings(boolean spawnemblems)
 
 	length = savebuf_p - savebuffer;
 
-	FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length);
+	FIL_WriteFile(va("%s.lmp", filepath), savebuffer, length);
 	free(savebuffer);
 	savebuf_p = NULL;
 
-	CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap);
-}*/
+	CONS_Printf(M_GetText("%s.lmp saved.\n"), filepath);
+}
 
 //
 // MAP LOADING FUNCTIONS
@@ -1816,6 +1859,10 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
 		sectors[i].specialflags |= SSF_JUMPFLIP;
 	else if (fastcmp(param, "gravityoverride") && fastcmp("true", val))
 		sectors[i].specialflags |= SSF_GRAVITYOVERRIDE;
+	else if (fastcmp(param, "nophysics_floor") && fastcmp("true", val))
+		sectors[i].specialflags |= SSF_NOPHYSICSFLOOR;
+	else if (fastcmp(param, "nophysics_ceiling") && fastcmp("true", val))
+		sectors[i].specialflags |= SSF_NOPHYSICSCEILING;
 	else if (fastcmp(param, "friction"))
 		sectors[i].friction = FLOAT_TO_FIXED(atof(val));
 	else if (fastcmp(param, "gravity"))
@@ -2150,6 +2197,60 @@ typedef struct
 	mapthing_t *angleanchor;
 } sectorspecialthings_t;
 
+static void P_WriteTextmap_Things(FILE *f, const mapthing_t *wmapthings)
+{
+	size_t i, j;
+	mtag_t firsttag;
+
+	// Actual writing
+	for (i = 0; i < nummapthings; i++)
+	{
+		fprintf(f, "thing // %s\n", sizeu1(i));
+		fprintf(f, "{\n");
+		firsttag = Tag_FGet(&wmapthings[i].tags);
+		if (firsttag != 0)
+			fprintf(f, "id = %d;\n", firsttag);
+		if (wmapthings[i].tags.count > 1)
+		{
+			fprintf(f, "moreids = \"");
+			for (j = 1; j < wmapthings[i].tags.count; j++)
+			{
+				if (j > 1)
+					fprintf(f, " ");
+				fprintf(f, "%d", wmapthings[i].tags.tags[j]);
+			}
+			fprintf(f, "\";\n");
+		}
+		fprintf(f, "x = %d;\n", wmapthings[i].x);
+		fprintf(f, "y = %d;\n", wmapthings[i].y);
+		if (wmapthings[i].z != 0)
+			fprintf(f, "height = %d;\n", wmapthings[i].z);
+		fprintf(f, "angle = %d;\n", wmapthings[i].angle);
+		if (wmapthings[i].pitch != 0)
+			fprintf(f, "pitch = %d;\n", wmapthings[i].pitch);
+		if (wmapthings[i].roll != 0)
+			fprintf(f, "roll = %d;\n", wmapthings[i].roll);
+		if (wmapthings[i].type != 0)
+			fprintf(f, "type = %d;\n", wmapthings[i].type);
+		if (wmapthings[i].spritexscale != FRACUNIT)
+			fprintf(f, "scalex = %f;\n", FIXED_TO_FLOAT(wmapthings[i].spritexscale));
+		if (wmapthings[i].spriteyscale != FRACUNIT)
+			fprintf(f, "scaley = %f;\n", FIXED_TO_FLOAT(wmapthings[i].spriteyscale));
+		if (wmapthings[i].scale != FRACUNIT)
+			fprintf(f, "mobjscale = %f;\n", FIXED_TO_FLOAT(wmapthings[i].scale));
+		if (wmapthings[i].options & MTF_OBJECTFLIP)
+			fprintf(f, "flip = true;\n");
+		for (j = 0; j < NUMMAPTHINGARGS; j++)
+			if (wmapthings[i].args[j] != 0)
+				fprintf(f, "arg%s = %d;\n", sizeu1(j), wmapthings[i].args[j]);
+		for (j = 0; j < NUMMAPTHINGSTRINGARGS; j++)
+			if (mapthings[i].stringargs[j])
+				fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), mapthings[i].stringargs[j]);
+		fprintf(f, "}\n");
+		fprintf(f, "\n");
+	}
+}
+
 static void P_WriteTextmap(void)
 {
 	size_t i, j;
@@ -2417,52 +2518,7 @@ static void P_WriteTextmap(void)
 	}
 
 	fprintf(f, "namespace = \"srb2\";\n");
-	for (i = 0; i < nummapthings; i++)
-	{
-		fprintf(f, "thing // %s\n", sizeu1(i));
-		fprintf(f, "{\n");
-		firsttag = Tag_FGet(&wmapthings[i].tags);
-		if (firsttag != 0)
-			fprintf(f, "id = %d;\n", firsttag);
-		if (wmapthings[i].tags.count > 1)
-		{
-			fprintf(f, "moreids = \"");
-			for (j = 1; j < wmapthings[i].tags.count; j++)
-			{
-				if (j > 1)
-					fprintf(f, " ");
-				fprintf(f, "%d", wmapthings[i].tags.tags[j]);
-			}
-			fprintf(f, "\";\n");
-		}
-		fprintf(f, "x = %d;\n", wmapthings[i].x);
-		fprintf(f, "y = %d;\n", wmapthings[i].y);
-		if (wmapthings[i].z != 0)
-			fprintf(f, "height = %d;\n", wmapthings[i].z);
-		fprintf(f, "angle = %d;\n", wmapthings[i].angle);
-		if (wmapthings[i].pitch != 0)
-			fprintf(f, "pitch = %d;\n", wmapthings[i].pitch);
-		if (wmapthings[i].roll != 0)
-			fprintf(f, "roll = %d;\n", wmapthings[i].roll);
-		if (wmapthings[i].type != 0)
-			fprintf(f, "type = %d;\n", wmapthings[i].type);
-		if (wmapthings[i].spritexscale != FRACUNIT)
-			fprintf(f, "scalex = %f;\n", FIXED_TO_FLOAT(wmapthings[i].spritexscale));
-		if (wmapthings[i].spriteyscale != FRACUNIT)
-			fprintf(f, "scaley = %f;\n", FIXED_TO_FLOAT(wmapthings[i].spriteyscale));
-		if (wmapthings[i].scale != FRACUNIT)
-			fprintf(f, "mobjscale = %f;\n", FIXED_TO_FLOAT(wmapthings[i].scale));
-		if (wmapthings[i].options & MTF_OBJECTFLIP)
-			fprintf(f, "flip = true;\n");
-		for (j = 0; j < NUMMAPTHINGARGS; j++)
-			if (wmapthings[i].args[j] != 0)
-				fprintf(f, "arg%s = %d;\n", sizeu1(j), wmapthings[i].args[j]);
-		for (j = 0; j < NUMMAPTHINGSTRINGARGS; j++)
-			if (mapthings[i].stringargs[j])
-				fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), mapthings[i].stringargs[j]);
-		fprintf(f, "}\n");
-		fprintf(f, "\n");
-	}
+	P_WriteTextmap_Things(f, wmapthings);
 
 	for (i = 0; i < numvertexes; i++)
 	{
@@ -2673,13 +2729,18 @@ static void P_WriteTextmap(void)
 			fprintf(f, "rotationfloor = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].floorangle)));
 		if (wsectors[i].ceilingangle != 0)
 			fprintf(f, "rotationceiling = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].ceilingangle)));
-        if (wsectors[i].extra_colormap)
+		if (wsectors[i].extra_colormap)
 		{
 			INT32 lightcolor = P_RGBAToColor(wsectors[i].extra_colormap->rgba);
 			UINT8 lightalpha = R_GetRgbaA(wsectors[i].extra_colormap->rgba);
 			INT32 fadecolor = P_RGBAToColor(wsectors[i].extra_colormap->fadergba);
 			UINT8 fadealpha = R_GetRgbaA(wsectors[i].extra_colormap->fadergba);
 
+			// For now, convert alpha from new (0-255) to old 'A-Z' (0-25) range
+			// TODO: remove this limitation in a backwards-compatible way (UDMF versioning?)
+			lightalpha /= 10;
+			fadealpha /= 10;
+
 			if (lightcolor != 0)
 				fprintf(f, "lightcolor = %d;\n", lightcolor);
 			if (lightalpha != 25)
@@ -2941,7 +3002,8 @@ static void P_LoadTextmap(void)
 		P_InitializeSector(sc);
 		if (textmap_colormap.used)
 		{
-			// Convert alpha values from old 0-25 (A-Z) range to 0-255 range
+			// Convert alpha values from old 'A-Z' (0-25) range to new UINT8 (0-255) range
+			// TODO: remove this limitation in a backwards-compatible way (UDMF versioning?)
 			UINT8 lightalpha = (textmap_colormap.lightalpha * 102) / 10;
 			UINT8 fadealpha = (textmap_colormap.fadealpha * 102) / 10;
 			
@@ -2954,13 +3016,17 @@ static void P_LoadTextmap(void)
 		{
 			sc->f_slope = P_MakeSlopeViaEquationConstants(textmap_planefloor.a, textmap_planefloor.b, textmap_planefloor.c, textmap_planefloor.d);
 			sc->hasslope = true;
+			if (sc->specialflags & SSF_NOPHYSICSFLOOR)
+				sc->f_slope->flags |= SL_NOPHYSICS;
 		}
 
 		if (textmap_planeceiling.defined == (PD_A|PD_B|PD_C|PD_D))
 		{
 			sc->c_slope = P_MakeSlopeViaEquationConstants(textmap_planeceiling.a, textmap_planeceiling.b, textmap_planeceiling.c, textmap_planeceiling.d);
 			sc->hasslope = true;
-		}
+			if (sc->specialflags & SSF_NOPHYSICSCEILING)
+				sc->c_slope->flags |= SL_NOPHYSICS;
+        }
 
 		TextmapFixFlatOffsets(sc);
 	}
@@ -3301,8 +3367,6 @@ static void P_InitializeSeg(seg_t *seg)
 	seg->lightmaps = NULL; // list of static lightmap for this seg
 #endif
 
-	seg->numlights = 0;
-	seg->rlights = NULL;
 	seg->polyseg = NULL;
 	seg->dontrenderme = false;
 }
diff --git a/src/p_setup.h b/src/p_setup.h
index f9e51024d2dbcf55f61bd193d1e32edc278a31be..da38d4c08b152f87fab59517706c3ccbc7544339 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -71,7 +71,7 @@ boolean P_AddFolder(const char *folderpath);
 boolean P_RunSOC(const char *socfilename);
 void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
 void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);
-//void P_WriteThings(void);
+void P_WriteThings(const char *filepath);
 size_t P_PrecacheLevelFlats(void);
 void P_AllocMapHeader(INT16 i);
 
@@ -87,5 +87,6 @@ UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare);
 UINT8 P_HasGrades(INT16 map, UINT8 mare);
 UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade);
 UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade);
+void P_AddNiGHTSTimes(INT16 i, char *gtext);
 
 #endif
diff --git a/src/p_spec.c b/src/p_spec.c
index 572258165e00386a6f804b65a8fc8e561e0111e4..78cf460632970ac108512f29f1fd2111aea5f462 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -363,7 +363,7 @@ void P_ParseAnimationDefintion(SINT8 istexture)
 		// Increase the size to make room for the new animation definition
 		maxanims++;
 		animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
-		strncpy(animdefs[i].startname, animdefsToken, 9);
+		strncpy(animdefs[i].startname, animdefsToken, sizeof(animdefs[i].startname)-1);
 	}
 
 	// animdefs[i].startname is now set to animdefsToken either way.
@@ -3684,7 +3684,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 
 		case 466: // Set level failure state
 			{
-				if (line->args[1])
+				if (line->args[0])
 				{
 					stagefailed = false;
 					CONS_Debug(DBG_GAMELOGIC, "Stage can be completed successfully!\n");
diff --git a/src/p_tick.c b/src/p_tick.c
index 4ab388486db62be9d1fa36d9289ac2b043219e47..56e0fd897bfbba718885a1104224d1554790f227 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -564,6 +564,12 @@ void P_DoTeamscrambling(void)
 		CV_SetValue(&cv_teamscramble, 0);
 }
 
+
+//
+// P_DoSpecialStageStuff()
+//
+// For old-style (non-NiGHTS) special stages
+//
 static inline void P_DoSpecialStageStuff(void)
 {
 	boolean stillalive = false;
@@ -601,7 +607,15 @@ static inline void P_DoSpecialStageStuff(void)
 				if (--players[i].nightstime > 6)
 				{
 					if (P_IsLocalPlayer(&players[i]) && oldnightstime > 10*TICRATE && players[i].nightstime <= 10*TICRATE)
-						S_ChangeMusicInternal("_drown", false);
+					{
+						if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
+						{
+							S_FadeMusic(0, 10*MUSICRATE);
+							S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
+						}
+						else
+							S_ChangeMusicInternal("_drown", false);
+					}
 					stillalive = true;
 				}
 				else if (!players[i].exiting)
@@ -844,7 +858,7 @@ void P_Ticker(boolean run)
 		if (quake.time)
 			--quake.time;
 
-		if (metalplayback)
+		if (!P_MobjWasRemoved(metalplayback))
 			G_ReadMetalTic(metalplayback);
 		if (metalrecording)
 			G_WriteMetalTic(players[consoleplayer].mo);
diff --git a/src/p_user.c b/src/p_user.c
index 6d83a18e6df9c8d74bbd5c9a5fb6ce4a81016ecd..f789de0d9e30f443d609070fe759b8ef494081bf 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -776,7 +776,7 @@ static void P_DeNightserizePlayer(player_t *player)
 // NiGHTS Time!
 void P_NightserizePlayer(player_t *player, INT32 nighttime)
 {
-	UINT8 oldmare, oldmarelap, oldmarebonuslap;
+	UINT8 oldmare, oldmarelap, oldmarebonuslap, newmare;
 
 	// Bots can't be NiGHTSerized, silly!1 :P
 	if (player->bot)
@@ -797,6 +797,11 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		}
 	}
 
+	// Use mare-specific time limit if specified
+	newmare = P_FindLowestMare();
+	if (mapheaderinfo[gamemap-1]->nightstimer[newmare] > 0)
+		nighttime = mapheaderinfo[gamemap-1]->nightstimer[newmare];
+
 	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_SHIELDDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
 	player->homing = 0;
 	player->mo->fuse = 0;
@@ -867,7 +872,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 				continue;
 
 			players[i].texttimer = (3 * TICRATE) - 10;
-			players[i].textvar = 4; // Score and grades
+			players[i].textvar = NTV_BONUSTIMEEND; // Score and grades
 			players[i].lastmare = players[i].mare;
 			players[i].lastmarelap = players[i].marelap;
 			players[i].lastmarebonuslap = players[i].marebonuslap;
@@ -885,7 +890,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 			}
 
 			// Add score to leaderboards now
-			G_AddTempNightsRecords(player, players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1);
+			player->lastmaretime = leveltime - player->marebegunat;
+			G_AddTempNightsRecords(player, players[i].marescore, player->lastmaretime, players[i].mare + 1);
 
 			// transfer scores anyway
 			players[i].totalmarescore += players[i].marescore;
@@ -906,12 +912,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		player->lastmarelap = oldmarelap;
 		player->lastmarebonuslap = oldmarebonuslap;
 		player->texttimer = 4*TICRATE;
-		player->textvar = 4; // Score and grades
+		player->textvar = NTV_BONUSTIMEEND; // Score and grades
 		player->finishedspheres = (INT16)(player->spheres);
 		player->finishedrings = (INT16)(player->rings);
-
+		
 		// Add score to temp leaderboards
-		G_AddTempNightsRecords(player, player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1));
+		player->lastmaretime = leveltime - player->marebegunat;
+		G_AddTempNightsRecords(player, player->marescore, player->lastmaretime, (UINT8)(oldmare + 1));
 
 		// Starting a new mare, transfer scores
 		player->totalmarescore += player->marescore;
@@ -924,7 +931,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 	}
 	else
 	{
-		player->textvar = 5; // Nothing, just tells it to go to the GET n RINGS/SPHERES text in a bit
+		player->textvar = NTV_NONE; // Nothing, just tells it to go to the GET n RINGS/SPHERES text in a bit
 		player->texttimer = 40;
 
 		// Don't show before title card
@@ -1378,7 +1385,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 // P_DoSuperDetransformation
 //
 // Detransform into regular Sonic!
-static void P_DoSuperDetransformation(player_t *player)
+void P_DoSuperDetransformation(player_t *player)
 {
 	player->powers[pw_emeralds] = 0; // lost the power stones
 	P_SpawnGhostMobj(player->mo);
@@ -1400,7 +1407,7 @@ static void P_DoSuperDetransformation(player_t *player)
 	if (!G_CoopGametype())
 		player->powers[pw_flashing] = flashingtics-1;
 
-	if (player->mo->sprite2 & FF_SPR2SUPER)
+	if (player->mo->sprite2 & SPR2F_SUPER)
 		P_SetMobjState(player->mo, player->mo->state-states);
 
 	// Inform the netgame that the champion has fallen in the heat of battle.
@@ -2038,8 +2045,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 	P_SetTarget(&ghost->target, mobj);
 	P_SetTarget(&ghost->dontdrawforviewmobj, mobj); // Hide the ghost in first-person
 
-	P_SetScale(ghost, mobj->scale);
-	ghost->destscale = mobj->scale;
+	P_SetScale(ghost, mobj->scale, true);
 
 	if (mobj->eflags & MFE_VERTICALFLIP)
 	{
@@ -2098,6 +2104,11 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 	ghost->old_pitch = mobj->old_pitch2;
 	ghost->old_roll = mobj->old_roll2;
 	ghost->old_spriteroll = mobj->old_spriteroll2;
+	ghost->old_spritexscale = mobj->old_spritexscale2;
+	ghost->old_spriteyscale = mobj->old_spriteyscale2;
+	ghost->old_spritexoffset = mobj->old_spritexoffset2;
+	ghost->old_spriteyoffset = mobj->old_spriteyoffset2;
+	ghost->old_scale = mobj->old_scale2;
 
 	return ghost;
 }
@@ -2153,7 +2164,7 @@ void P_SpawnThokMobj(player_t *player)
 		mobj->eflags |= (player->mo->eflags & MFE_VERTICALFLIP);
 
 		// scale
-		P_SetScale(mobj, (mobj->destscale = player->mo->scale));
+		P_SetScale(mobj, player->mo->scale, true);
 
 		if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 		{
@@ -2217,8 +2228,7 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
 		mobj->eflags |= (player->mo->eflags & MFE_VERTICALFLIP);
 
 		// scale
-		P_SetScale(mobj, player->mo->scale);
-		mobj->destscale = player->mo->scale;
+		P_SetScale(mobj, player->mo->scale, true);
 
 		if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 		{
@@ -3041,9 +3051,8 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 					P_SetMobjState(numbermobj, numbermobj->info->spawnstate+timeleft);
 
 				P_SetTarget(&numbermobj->target, player->mo);
+				P_SetScale(numbermobj, player->mo->scale, true);
 				numbermobj->threshold = 40;
-				numbermobj->destscale = player->mo->scale;
-				P_SetScale(numbermobj, player->mo->scale);
 			}
 		}
 	}
@@ -3105,10 +3114,7 @@ static void P_CheckInvincibilityTimer(player_t *player)
 	{
 		mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_IVSP);
 		if (!P_MobjWasRemoved(sparkle))
-		{
-			sparkle->destscale = player->mo->scale;
-			P_SetScale(sparkle, player->mo->scale);
-		}
+			P_SetScale(sparkle, player->mo->scale, true);
 	}
 
 	// Resume normal music stuff.
@@ -3183,8 +3189,7 @@ static void P_DoBubbleBreath(player_t *player)
 	if (bubble)
 	{
 		bubble->threshold = 42;
-		bubble->destscale = player->mo->scale;
-		P_SetScale(bubble, bubble->destscale);
+		P_SetScale(bubble, player->mo->scale, true);
 	}
 
 	// Tails stirs up the water while flying in it
@@ -3206,20 +3211,14 @@ static void P_DoBubbleBreath(player_t *player)
 			player->mo->y + stirwatery,
 			stirwaterz, MT_SMALLBUBBLE);
 		if (!P_MobjWasRemoved(bubble))
-		{
-			bubble->destscale = player->mo->scale;
-			P_SetScale(bubble,bubble->destscale);
-		}
+			P_SetScale(bubble, player->mo->scale, true);
 
 		bubble = P_SpawnMobj(
 			player->mo->x - stirwaterx,
 			player->mo->y - stirwatery,
 			stirwaterz, MT_SMALLBUBBLE);
 		if (!P_MobjWasRemoved(bubble))
-		{
-			bubble->destscale = player->mo->scale;
-			P_SetScale(bubble,bubble->destscale);
-		}
+			P_SetScale(bubble, player->mo->scale, true);
 	}
 }
 
@@ -4189,16 +4188,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
 
 	I_Assert(player != NULL);
 	I_Assert(!P_MobjWasRemoved(player->mo));
-	
-	// Toss a flag
-	if (cmd->buttons & BT_TOSSFLAG && G_GametypeHasTeams()
-		&& !(player->powers[pw_super]) && !(player->tossdelay))
-	{
-		if (!(player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
-			P_PlayerEmeraldBurst(player, true); // Toss emeralds
-		else
-			P_PlayerFlagBurst(player, true);
-	}
 
 	if (!(cmd->buttons & (BT_ATTACK|BT_FIRENORMAL)))
 	{
@@ -4208,7 +4197,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
 		return;
 	}
 
-	if (player->pflags & PF_ATTACKDOWN || player->climbing)
+	if (player->pflags & PF_ATTACKDOWN || player->climbing || (G_TagGametype() && !(player->pflags & PF_TAGIT)))
 		return;
 
 	// Fire a fireball if we have the Fire Flower powerup!
@@ -4224,7 +4213,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
 	}
 
 	// No ringslinging outside of ringslinger!
-	if (!G_RingSlingerGametype() || player->weapondelay || (G_TagGametype() && !(player->pflags & PF_TAGIT)))
+	if (!G_RingSlingerGametype() || player->weapondelay)
 		return;
 
 	player->pflags |= PF_ATTACKDOWN;
@@ -4424,10 +4413,7 @@ static void P_DoSuperStuff(player_t *player)
 		{
 			spark = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK);
 			if (!P_MobjWasRemoved(spark))
-			{
-				spark->destscale = player->mo->scale;
-				P_SetScale(spark, player->mo->scale);
-			}
+				P_SetScale(spark, player->mo->scale, true);
 		}
 
 		// Ran out of rings while super!
@@ -4452,14 +4438,14 @@ boolean P_SuperReady(player_t *player, boolean transform)
 	|| !ALL7EMERALDS(emeralds)
 	|| !(player->rings >= 50)))
 		return false;
-	
+
 	if (player->mo
 	&& !player->powers[pw_tailsfly]
 	&& !player->powers[pw_carry]
 	&& (player->charflags & SF_SUPER)
 	&& !P_PlayerInPain(player)
 	&& !player->climbing
-	&& !(player->pflags & (PF_FULLSTASIS|PF_THOKKED|PF_STARTDASH|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY))
+	&& !(player->pflags & (PF_JUMPSTASIS|PF_THOKKED|PF_STARTDASH|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY))
 	&& ((player->pflags & PF_JUMPED) || (P_IsObjectOnGround(player->mo) && (player->panim == PA_IDLE || player->panim == PA_EDGE
 	|| player->panim == PA_WALK || player->panim == PA_RUN || (player->charflags & SF_DASHMODE && player->panim == PA_DASH))))
 	&& !(maptol & TOL_NIGHTS))
@@ -4677,8 +4663,7 @@ void P_DoSpinDashDust(player_t *player)
 			P_SetMobjState(particle, S_SPINDUST_FIRE1);
 
 		P_SetTarget(&particle->target, player->mo);
-		particle->destscale = (2*player->mo->scale)/3;
-		P_SetScale(particle, particle->destscale);
+		P_SetScale(particle, (2*player->mo->scale)/3, true);
 		if (player->mo->eflags & MFE_VERTICALFLIP) // readjust z position if needed
 			particle->z = player->mo->z + player->mo->height - particle->height;
 		prandom[0] = P_RandomFixed()<<2; // P_RandomByte()<<10
@@ -4977,7 +4962,7 @@ void P_DoJumpShield(player_t *player)
 	}
 	else
 	{
-		player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE);
+		player->pflags |= PF_NOJUMPDAMAGE;
 		P_SetMobjState(player->mo, S_PLAY_FALL);
 		S_StartSound(player->mo, sfx_wdjump);
 	}
@@ -5077,7 +5062,7 @@ void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type)
 		if (!P_MobjWasRemoved(missile))
 		{
 			P_SetTarget(&missile->target, player->mo);
-			P_SetScale(missile, (missile->destscale >>= 1));
+			P_SetScale(missile, missile->destscale/2, true);
 			missile->angle = ang + movang;
 			missile->fuse = TICRATE/2;
 			missile->extravalue2 = (99*FRACUNIT)/100;
@@ -5281,7 +5266,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
 //
 // Handles player jumping
 //
-static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
+static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd, boolean spinshieldhack)
 {
 	mobj_t *lockonthok = NULL, *visual = NULL;
 
@@ -5314,45 +5299,53 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 			;
 		else if (P_PlayerShieldThink(player, cmd, lockonthok, visual))
 			;
-		else if ((cmd->buttons & BT_SPIN) && !LUA_HookPlayer(player, HOOK(JumpSpinSpecial)))
+		else if (cmd->buttons & BT_SPIN)
 		{
-			switch (player->charability)
+			if (spinshieldhack && !(player->pflags & PF_SPINDOWN) && P_SuperReady(player, true)
+			&& !player->powers[pw_invulnerability] && !(player->powers[pw_shield] & SH_NOSTACK)) // These two checks are no longer in P_SuperReady
 			{
-				case CA_THOK:
-					if (player->powers[pw_super]) // Super Sonic float
-					{
-						if ((player->speed > 5*player->mo->scale) // FixedMul(5<<FRACBITS, player->mo->scale), but scale is FRACUNIT-based
-						&& (P_MobjFlip(player->mo)*player->mo->momz <= 0))
+				// If you're using two-button play, can turn Super and aren't already,
+				// and you don't have a shield, then turn Super!
+				P_DoSuperTransformation(player, false);
+			}
+			else if (!LUA_HookPlayer(player, HOOK(JumpSpinSpecial)))
+				switch (player->charability)
+				{
+					case CA_THOK:
+						if (player->powers[pw_super]) // Super Sonic float
 						{
-							if (player->panim != PA_RUN && player->panim != PA_WALK)
+							if ((player->speed > 5*player->mo->scale) // FixedMul(5<<FRACBITS, player->mo->scale), but scale is FRACUNIT-based
+							&& (P_MobjFlip(player->mo)*player->mo->momz <= 0))
 							{
-								if (player->speed >= FixedMul(player->runspeed, player->mo->scale))
-									P_SetMobjState(player->mo, S_PLAY_FLOAT_RUN);
-								else
-									P_SetMobjState(player->mo, S_PLAY_FLOAT);
-							}
+								if (player->panim != PA_RUN && player->panim != PA_WALK)
+								{
+									if (player->speed >= FixedMul(player->runspeed, player->mo->scale))
+										P_SetMobjState(player->mo, S_PLAY_FLOAT_RUN);
+									else
+										P_SetMobjState(player->mo, S_PLAY_FLOAT);
+								}
 
-							player->mo->momz = 0;
-							player->pflags &= ~(PF_STARTJUMP|PF_SPINNING);
-							player->secondjump = 1;
+								player->mo->momz = 0;
+								player->pflags &= ~(PF_STARTJUMP|PF_SPINNING);
+								player->secondjump = 1;
+							}
 						}
-					}
-					break;
-				case CA_TELEKINESIS:
-					if (!(player->pflags & (PF_THOKKED|PF_SPINDOWN)) || (player->charflags & SF_MULTIABILITY))
-					{
-						P_Telekinesis(player,
-							-FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player)
-							FixedMul(384*FRACUNIT, player->mo->scale));
-					}
-					break;
-				case CA_TWINSPIN:
-					if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_SPINDOWN)) || player->charflags & SF_MULTIABILITY))
-						P_DoTwinSpin(player);
-					break;
-				default:
-					break;
-			}
+						break;
+					case CA_TELEKINESIS:
+						if (!(player->pflags & (PF_THOKKED|PF_SPINDOWN)) || (player->charflags & SF_MULTIABILITY))
+						{
+							P_Telekinesis(player,
+								-FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player)
+								FixedMul(384*FRACUNIT, player->mo->scale));
+						}
+						break;
+					case CA_TWINSPIN:
+						if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_SPINDOWN)) || player->charflags & SF_MULTIABILITY))
+							P_DoTwinSpin(player);
+						break;
+					default:
+						break;
+				}
 		}
 	}
 
@@ -7019,7 +7012,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
 					{
 						players[i].bonustime = true;
 						players[i].texttimer = 4*TICRATE;
-						players[i].textvar = 1; // Time Bonus
+						players[i].textvar = NTV_BONUSTIMESTART; // Time Bonus
 						players[i].finishedtime = players[i].nightstime;
 						if (!G_IsSpecialStage(gamemap))
 							P_AddPlayerScore(&players[i], (players[i].finishedtime/TICRATE) * 100);
@@ -7103,12 +7096,12 @@ static void P_DoNiGHTSCapsule(player_t *player)
 			{
 				S_StartScreamSound(player->mo, sfx_lose);
 				player->texttimer = 4*TICRATE;
-				player->textvar = 3; // Get more rings!
+				player->textvar = NTV_GETMORESPHERES; // Get more spheres/chips!
 				player->capsule->reactiontime = 0;
 				player->capsule->extravalue1 = player->capsule->cvmem =\
 				 player->capsule->cusval = player->capsule->movecount =\
 				 player->capsule->lastlook = player->capsule->extravalue2 = -1;
-				P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked rings
+				P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked spheres/chips
 			}
 		}
 	}
@@ -7417,9 +7410,8 @@ static void P_NiGHTSMovement(player_t *player)
 		firstmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle+ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle+ANGLE_90, spawndist), z, MT_NIGHTSPARKLE);
 		if (!P_MobjWasRemoved(firstmobj))
 		{
-			firstmobj->destscale = player->mo->scale;
 			P_SetTarget(&firstmobj->target, player->mo);
-			P_SetScale(firstmobj, player->mo->scale);
+			P_SetScale(firstmobj, player->mo->scale, true);
 			// Superloop turns sparkles red
 			if (player->powers[pw_nights_superloop])
 				P_SetMobjState(firstmobj, mobjinfo[MT_NIGHTSPARKLE].seestate);
@@ -7427,10 +7419,8 @@ static void P_NiGHTSMovement(player_t *player)
 		secondmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle-ANGLE_90, spawndist), z, MT_NIGHTSPARKLE);
 		if (!P_MobjWasRemoved(secondmobj))
 		{
-			secondmobj->destscale = player->mo->scale;
 			P_SetTarget(&secondmobj->target, player->mo);
-			P_SetScale(secondmobj, player->mo->scale);
-
+			P_SetScale(secondmobj, player->mo->scale, true);
 			// Superloop turns sparkles red
 			if (player->powers[pw_nights_superloop])
 				P_SetMobjState(secondmobj, mobjinfo[MT_NIGHTSPARKLE].seestate);
@@ -7445,7 +7435,7 @@ static void P_NiGHTSMovement(player_t *player)
 		{
 			helpermobj->fuse = player->mo->fuse = leveltime;
 			P_SetTarget(&helpermobj->target, player->mo);
-			P_SetScale(helpermobj, player->mo->scale);
+			P_SetScale(helpermobj, player->mo->scale, false);
 		}
 	}
 
@@ -7645,8 +7635,7 @@ static void P_NiGHTSMovement(player_t *player)
 				water->flags2 |= MF2_OBJECTFLIP;
 				water->eflags |= MFE_VERTICALFLIP;
 			}
-			water->destscale = player->mo->scale;
-			P_SetScale(water, player->mo->scale);
+			P_SetScale(water, player->mo->scale, true);
 		}
 	}
 
@@ -7889,8 +7878,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle)
 			P_SetTarget(&flame->target, player->mo);
 			flame->angle = travelangle + i*(ANGLE_MAX/numangles);
 			flame->fuse = TICRATE*7; // takes about an extra second to hit the ground
-			flame->destscale = player->mo->scale;
-			P_SetScale(flame, player->mo->scale);
+			P_SetScale(flame, player->mo->scale, true);
 			if (!(player->mo->flags2 & MF2_OBJECTFLIP) != !(player->powers[pw_gravityboots])) // take gravity boots into account
 				flame->flags2 |= MF2_OBJECTFLIP;
 			flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
@@ -7927,8 +7915,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle)
 			P_SetTarget(&flame->target, player->mo);
 			flame->angle = travelangle;
 			flame->fuse = TICRATE*6;
-			flame->destscale = player->mo->scale;
-			P_SetScale(flame, player->mo->scale);
+			P_SetScale(flame, player->mo->scale, true);
 			if (!(player->mo->flags2 & MF2_OBJECTFLIP) != !(player->powers[pw_gravityboots])) // take gravity boots into account
 				flame->flags2 |= MF2_OBJECTFLIP;
 			flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
@@ -7976,8 +7963,7 @@ void P_SpawnSkidDust(player_t *player, fixed_t radius, boolean sound)
 	}
 	particle->tics = 10;
 
-	particle->destscale = (2*mo->scale)/3;
-	P_SetScale(particle, particle->destscale);
+	P_SetScale(particle, (2*mo->scale)/3, true);
 	P_SetObjectMomZ(particle, FRACUNIT, false);
 
 	if (mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) // overrides fire version
@@ -8074,6 +8060,7 @@ void P_MovePlayer(player_t *player)
 {
 	ticcmd_t *cmd;
 	INT32 i;
+	boolean spinshieldhack = false; // Hack: Is Spin and Shield bound to the same button (pressed on the same tic)?
 
 	fixed_t runspd;
 
@@ -8566,8 +8553,7 @@ void P_MovePlayer(player_t *player)
 				water->flags2 |= MF2_OBJECTFLIP;
 				water->eflags |= MFE_VERTICALFLIP;
 			}
-			water->destscale = player->mo->scale;
-			P_SetScale(water, player->mo->scale);
+			P_SetScale(water, player->mo->scale, true);
 		}
 	}
 
@@ -8696,10 +8682,13 @@ void P_MovePlayer(player_t *player)
 	&& !(player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)))
 		P_ElementalFire(player, false);
 
+	if ((cmd->buttons & (BT_SPIN|BT_SHIELD)) == (BT_SPIN|BT_SHIELD) && !(player->pflags & (PF_SPINDOWN|PF_SHIELDDOWN)))
+		spinshieldhack = true; // Spin and Shield is bound to the same button (pressed on the same tic), so enable two-button play (Jump and Spin+Shield)
+
 	P_DoSpinAbility(player, cmd);
 
 	// jumping
-	P_DoJumpStuff(player, cmd);
+	P_DoJumpStuff(player, cmd, spinshieldhack);
 
 	// If you're not spinning, you'd better not be spindashing!
 	if (!(player->pflags & PF_SPINNING) && player->powers[pw_carry] != CR_NIGHTSMODE)
@@ -8777,30 +8766,32 @@ void P_MovePlayer(player_t *player)
 	if (!(player->mo->momz || player->mo->momx || player->mo->momy) && !(player->mo->eflags & MFE_GOOWATER)
 	&& player->panim == PA_IDLE && !(player->powers[pw_carry]))
 		P_DoTeeter(player);
+	
+	// Toss a flag
+	if (G_GametypeHasTeams() && (cmd->buttons & BT_TOSSFLAG) && !(player->powers[pw_super]) && !(player->tossdelay))
+	{
+		if (!(player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
+			P_PlayerEmeraldBurst(player, true); // Toss emeralds
+		else
+			P_PlayerFlagBurst(player, true);
+	}
 
 	// Check for fire and shield buttons
-	if (!player->exiting && !(player->pflags & PF_STASIS))
+	if (!player->exiting)
 	{
-		// Check for fire buttons
 		P_DoFiring(player, cmd);
-		
-		// Release the shield button
-		if (!(cmd->buttons & BT_SHIELD))
-			player->pflags &= ~PF_SHIELDDOWN;
-		
+
 		// Shield button behavior
 		// Check P_PlayerShieldThink for actual shields!
-		else if (!(player->pflags & PF_SHIELDDOWN))
+		if ((cmd->buttons & BT_SHIELD) && !(player->pflags & PF_SHIELDDOWN) && !spinshieldhack)
 		{
 			// Transform into super if we can!
 			if (P_SuperReady(player, true))
 				P_DoSuperTransformation(player, false);
-			
+
 			// Detransform from super if we can!
 			else if (P_SuperReady(player, false))
 				P_DoSuperDetransformation(player);
-			
-			player->pflags |= PF_SHIELDDOWN;
 		}
 	}
 
@@ -9817,9 +9808,10 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0,
 static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {25, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t multiplier_cons_t[] = {{0, "MIN"}, {3*FRACUNIT, "MAX"}, {0, NULL}};
+static CV_PossibleValue_t campos_cons_t[] = { {INT32_MIN, "MIN"}, {INT32_MAX, "MAX"}, {0, NULL} };
 
-consvar_t cv_cam_dist = CVAR_INIT ("cam_curdist", "160", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
-consvar_t cv_cam_height = CVAR_INIT ("cam_curheight", "25", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
+consvar_t cv_cam_dist = CVAR_INIT ("cam_curdist", "160", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
+consvar_t cv_cam_height = CVAR_INIT ("cam_curheight", "25", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
 consvar_t cv_cam_still = CVAR_INIT ("cam_still", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_cam_speed = CVAR_INIT ("cam_speed", "0.3", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
 consvar_t cv_cam_rotate = CVAR_INIT ("cam_rotate", "0", CV_CALL|CV_NOINIT|CV_ALLOWLUA, CV_CamRotate, CV_CamRotate_OnChange);
@@ -9827,8 +9819,8 @@ consvar_t cv_cam_rotspeed = CVAR_INIT ("cam_rotspeed", "10", CV_SAVE|CV_ALLOWLUA
 consvar_t cv_cam_turnmultiplier = CVAR_INIT ("cam_turnmultiplier", "0.75", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, multiplier_cons_t, NULL);
 consvar_t cv_cam_orbit = CVAR_INIT ("cam_orbit", "Off", CV_SAVE|CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_cam_adjust = CVAR_INIT ("cam_adjust", "On", CV_SAVE|CV_ALLOWLUA, CV_OnOff, NULL);
-consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
-consvar_t cv_cam2_height = CVAR_INIT ("cam2_curheight", "25", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
+consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
+consvar_t cv_cam2_height = CVAR_INIT ("cam2_curheight", "25", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
 consvar_t cv_cam2_still = CVAR_INIT ("cam2_still", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_cam2_speed = CVAR_INIT ("cam2_speed", "0.3", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
 consvar_t cv_cam2_rotate = CVAR_INIT ("cam2_rotate", "0", CV_CALL|CV_NOINIT|CV_ALLOWLUA, CV_CamRotate, CV_CamRotate2_OnChange);
@@ -9840,23 +9832,23 @@ consvar_t cv_cam2_adjust = CVAR_INIT ("cam2_adjust", "On", CV_SAVE|CV_ALLOWLUA,
 // [standard vs simple][p1 or p2]
 consvar_t cv_cam_savedist[2][2] = {
 	{ // standard
-		CVAR_INIT ("cam_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 	},
 	{ // simple
-		CVAR_INIT ("cam_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 
 	}
 };
 consvar_t cv_cam_saveheight[2][2] = {
 	{ // standard
-		CVAR_INIT ("cam_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 	},
 	{ // simple
-		CVAR_INIT ("cam_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 
 	}
 };
@@ -10999,8 +10991,7 @@ static void P_SpawnSparks(mobj_t *mo, angle_t maindir)
 	spark->momz = mo->momz + r3;
 
 	P_Thrust(spark, R_PointToAngle2(mo->x, mo->y, spark->x, spark->y), 8*FRACUNIT);
-	P_SetScale(spark, FRACUNIT/4);
-	spark->destscale = spark->scale;
+	P_SetScale(spark, FRACUNIT/4, true);
 	spark->fuse = TICRATE/3;
 }
 
@@ -11105,7 +11096,8 @@ static void P_MinecartThink(player_t *player)
 	fa = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK;
 	if (!P_TryMove(minecart, minecart->x + FINECOSINE(fa), minecart->y + FINESINE(fa), true))
 	{
-		P_KillMobj(minecart, NULL, NULL, 0);
+		if (!P_MobjWasRemoved(minecart))
+			P_KillMobj(minecart, NULL, NULL, 0);
 		return;
 	}
 
@@ -11306,7 +11298,7 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	fixed_t backwards = -1*FRACUNIT;
 	boolean doswim = (player->panim == PA_ABILITY && (player->mo->eflags & MFE_UNDERWATER));
 	boolean doroll = (player->panim == PA_ROLL || (player->panim == PA_JUMP && !(player->charflags & SF_NOJUMPSPIN)) || doswim);
-	angle_t rollangle;
+	angle_t rollangle = 0;
 	boolean panimchange;
 	INT32 ticnum = 0;
 	statenum_t chosenstate;
@@ -11433,10 +11425,10 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	}
 	else
 	{
-		if (tails->state != states+chosenstate)
+		if (tails->state != &states[chosenstate])
 		{
 			if (states[chosenstate].sprite == SPR_PLAY)
-				tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), (states[chosenstate].frame & FF_FRAMEMASK), player);
+				tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), P_GetStateSprite2(&states[chosenstate]), player);
 			P_SetMobjState(tails, chosenstate);
 		}
 	}
@@ -11471,8 +11463,9 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	tails->threshold = player->mo->z;
 	tails->movecount = player->panim;
 	tails->angle = horizangle;
-	P_SetScale(tails, player->mo->scale);
+	P_SetScale(tails, player->mo->scale, false);
 	tails->destscale = player->mo->destscale;
+	tails->old_scale = player->mo->old_scale;
 	tails->radius = player->mo->radius;
 	tails->height = player->mo->height;
 	zoffs = FixedMul(zoffs, tails->scale);
@@ -11563,7 +11556,9 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 				y = mo->y + radiusY + FixedMul(offsetH, factorY);
 				z = mo->z + heightoffset + offsetV;
 				bubble = P_SpawnMobj(x, y, z, MT_SMALLBUBBLE);
-				bubble->scale = mo->scale >> 1;
+				P_SetScale(bubble, mo->scale/2, true);
+				bubble->destscale = mo->scale;
+				bubble->scalespeed = FixedMul(bubble->scalespeed, mo->scale);
 				P_SetTarget(&bubble->dontdrawforviewmobj, mo); // Hide the bubble in first-person
 			}
 
@@ -11584,7 +11579,7 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 	if (stat == fume->info->spawnstate) // If currently inivisble, activate!
 	{
 		P_SetMobjState(fume, (stat = fume->info->seestate));
-		P_SetScale(fume, mo->scale);
+		P_SetScale(fume, mo->scale, false);
 		resetinterp = true;
 	}
 
@@ -11599,7 +11594,7 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 		if (dashmode == DASHMODE_THRESHOLD && dashmode > (tic_t)fume->movecount) // If just about to enter dashmode, play the startup animation again
 		{
 			P_SetMobjState(fume, (stat = fume->info->seestate));
-			P_SetScale(fume, mo->scale << 1);
+			P_SetScale(fume, 2*mo->scale, true);
 		}
 		fume->flags2 = (fume->flags2 & ~MF2_DONTDRAW) | (mo->flags2 & MF2_DONTDRAW);
 		fume->destscale = (mo->scale + FixedDiv(player->speed, player->normalspeed)) / (underwater ? 6 : 3);
@@ -12053,7 +12048,7 @@ void P_PlayerThink(player_t *player)
 				ticmiss++;
 
 			P_DoRopeHang(player);
-			P_DoJumpStuff(player, &player->cmd);
+			P_DoJumpStuff(player, &player->cmd, false); // P_DoRopeHang would set PF_SPINDOWN, so no spinshieldhack here
 		}
 		else //if (player->powers[pw_carry] == CR_ZOOMTUBE)
 		{
@@ -12088,7 +12083,7 @@ void P_PlayerThink(player_t *player)
 	// deez New User eXperiences.
 	{
 		angle_t oldang = player->drawangle, diff = 0;
-		UINT8 factor;
+		UINT8 factor = 0;
 		// Directionchar!
 		// Camera angle stuff.
 		if (player->exiting // no control, no modification
@@ -12324,6 +12319,12 @@ void P_PlayerThink(player_t *player)
 			player->pflags &= ~PF_SPINDOWN;
 	}
 
+	// Check for Shield button
+	if (cmd->buttons & BT_SHIELD)
+		player->pflags |= PF_SHIELDDOWN;
+	else
+		player->pflags &= ~PF_SHIELDDOWN;
+
 	// IF PLAYER NOT HERE THEN FLASH END IF
 	if (player->quittime && player->powers[pw_flashing] < flashingtics - 1
 	&& !(G_TagGametype() && !(player->pflags & PF_TAGIT)) && !player->gotflag)
@@ -12455,13 +12456,13 @@ void P_PlayerThink(player_t *player)
 	if (player->texttimer)
 	{
 		--player->texttimer;
-		if (!player->texttimer && !player->exiting && player->textvar >= 4)
+		if (!player->texttimer && !player->exiting && (player->textvar == NTV_NONE || player->textvar == NTV_BONUSTIMEEND))
 		{
 			player->texttimer = 4*TICRATE;
-			player->textvar = 2; // GET n RINGS!
+			player->textvar = NTV_GETSPHERES; // GET n SPHERES/CHIPS!
 
-			if (player->capsule && player->capsule->health != player->capsule->spawnpoint->angle)
-				player->textvar++; // GET n MORE RINGS!
+			if (!P_MobjWasRemoved(player->capsule) && player->capsule->health != player->capsule->spawnpoint->args[1])
+				player->textvar = NTV_GETMORESPHERES; // GET n MORE SPHERES/CHIPS!
 		}
 	}
 
@@ -13199,7 +13200,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle)
 boolean P_PlayerFullbright(player_t *player)
 {
 	return (player->powers[pw_super]
-		|| ((player->powers[pw_carry] == CR_NIGHTSMODE && (((skin_t *)player->mo->skin)->flags & (SF_SUPER|SF_NONIGHTSSUPER)) == SF_SUPER) // Super colours? Super bright!
+		|| ((player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & (SF_SUPER|SF_NONIGHTSSUPER)) == SF_SUPER) // Super colours? Super bright!
 		&& (player->exiting
 			|| !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
 			&& player->mo->state < &states[S_PLAY_NIGHTS_TRANS6])))); // Note the < instead of <=
diff --git a/src/r_bsp.c b/src/r_bsp.c
index 918dc40b0f721a73badb9549d8e656a98fedf54c..d606d7a274b322e932cdd9778ea9d780748c7394 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -1382,10 +1382,9 @@ void R_RenderPortalHorizonLine(sector_t *sector)
 		|| frontsector->ceilingpic == skyflatnum
 		|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum))
 	{
-		ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic,
-			ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingxscale, frontsector->ceilingyscale,
-			frontsector->ceilingyoffset, frontsector->ceilingangle,
-			ceilingcolormap, NULL, NULL, NULL, NULL);
+		ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel,
+			frontsector->ceilingxoffset, frontsector->ceilingyoffset, frontsector->ceilingxscale, frontsector->ceilingyscale,
+			frontsector->ceilingangle, ceilingcolormap, NULL, NULL, NULL, NULL);
 	}
 	else
 		ceilingplane = NULL;
diff --git a/src/r_data.c b/src/r_data.c
index 56fe9403983ab29e2d60428672e8b4551e715ae4..75ec0556d46f1edff4d2c473b595a40e835426ac 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -54,10 +54,6 @@ lighttable_t *fadecolormap;
 // for debugging/info purposes
 size_t flatmemory, spritememory, texturememory;
 
-// highcolor stuff
-INT16 color8to16[256]; // remap color index to highcolor rgb value
-INT16 *hicolormaps; // test a 32k colormap remaps high -> high
-
 // Blends two pixels together, using the equation
 // that matches the specified alpha style.
 UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha)
@@ -1177,40 +1173,6 @@ const char *R_NameForColormap(extracolormap_t *extra_colormap)
 }
 #endif
 
-//
-// build a table for quick conversion from 8bpp to 15bpp
-//
-
-//
-// added "static inline" keywords, linking with the debug version
-// of allegro, it have a makecol15 function of it's own, now
-// with "static inline" keywords,it sloves this problem ;)
-//
-FUNCMATH static inline int makecol15(int r, int g, int b)
-{
-	return (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
-}
-
-static void R_Init8to16(void)
-{
-	UINT8 *palette;
-	int i;
-
-	palette = W_CacheLumpName("PLAYPAL",PU_CACHE);
-
-	for (i = 0; i < 256; i++)
-	{
-		// PLAYPAL uses 8 bit values
-		color8to16[i] = (INT16)makecol15(palette[0], palette[1], palette[2]);
-		palette += 3;
-	}
-
-	// test a big colormap
-	hicolormaps = Z_Malloc(16384*sizeof(*hicolormaps), PU_STATIC, NULL);
-	for (i = 0; i < 16384; i++)
-		hicolormaps[i] = (INT16)(i<<1);
-}
-
 //
 // R_InitData
 //
@@ -1219,12 +1181,6 @@ static void R_Init8to16(void)
 //
 void R_InitData(void)
 {
-	if (highcolor)
-	{
-		CONS_Printf("InitHighColor...\n");
-		R_Init8to16();
-	}
-
 	CONS_Printf("R_LoadParsedTranslations()...\n");
 	R_LoadParsedTranslations();
 
diff --git a/src/r_data.h b/src/r_data.h
index 364f85b6d4b0cbdd09448144f0546db9bc661bfc..9340ed284b6524e54774cfa43ed6c24e3e92afe3 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -36,9 +36,6 @@ UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT
 
 extern INT32 ASTTextureBlendingThreshold[2];
 
-extern INT16 color8to16[256]; // remap color index to highcolor
-extern INT16 *hicolormaps; // remap high colors to high colors..
-
 extern CV_PossibleValue_t Color_cons_t[];
 
 // I/O, setting up the stuff.
diff --git a/src/r_defs.h b/src/r_defs.h
index 65fd883c91a9ccb7b02fbcfa7864d1783ca987ef..da4dd2d70e6049479eacd24c51af11b4a995507b 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -405,6 +405,8 @@ typedef enum
 	SSF_ROPEHANG = 1<<18,
 	SSF_JUMPFLIP = 1<<19,
 	SSF_GRAVITYOVERRIDE = 1<<20, // combine with MSF_GRAVITYFLIP
+	SSF_NOPHYSICSFLOOR = 1<<21,
+	SSF_NOPHYSICSCEILING = 1<<22,
 } sectorspecialflags_t;
 
 typedef enum
@@ -751,9 +753,6 @@ typedef struct seg_s
 	lightmap_t *lightmaps; // for static lightmap
 #endif
 
-	// Why slow things down by calculating lightlists for every thick side?
-	size_t numlights;
-	r_lightlist_t *rlights;
 	polyobj_t *polyseg;
 	boolean dontrenderme;
 	boolean glseg;
@@ -837,6 +836,7 @@ typedef struct drawseg_s
 	INT16 *sprtopclip;
 	INT16 *sprbottomclip;
 	fixed_t *maskedtexturecol;
+	fixed_t *maskedtextureheight; // For handling sloped midtextures
 	fixed_t *invscale;
 
 	struct visplane_s *ffloorplanes[MAXFFLOORS];
@@ -848,20 +848,9 @@ typedef struct drawseg_s
 
 	UINT8 portalpass; // if > 0 and <= portalrender, do not affect sprite clipping
 
-	fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures
-
 	vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes
 } drawseg_t;
 
-typedef enum
-{
-	PALETTE         = 0,  // 1 byte is the index in the doom palette (as usual)
-	INTENSITY       = 1,  // 1 byte intensity
-	INTENSITY_ALPHA = 2,  // 2 byte: alpha then intensity
-	RGB24           = 3,  // 24 bit rgb
-	RGBA32          = 4,  // 32 bit rgba
-} pic_mode_t;
-
 #ifdef ROTSPRITE
 typedef struct
 {
@@ -906,26 +895,6 @@ typedef struct
 	// the [0] is &columnofs[width]
 } ATTRPACK softwarepatch_t;
 
-#ifdef _MSC_VER
-#pragma warning(disable :  4200)
-#endif
-
-// a pic is an unmasked block of pixels, stored in horizontal way
-typedef struct
-{
-	INT16 width;
-	UINT8 zero;       // set to 0 allow autodetection of pic_t
-	                 // mode instead of patch or raw
-	UINT8 mode;       // see pic_mode_t above
-	INT16 height;
-	INT16 reserved1; // set to 0
-	UINT8 data[0];
-} ATTRPACK pic_t;
-
-#ifdef _MSC_VER
-#pragma warning(default : 4200)
-#endif
-
 #if defined(_MSC_VER)
 #pragma pack()
 #endif
@@ -1007,6 +976,8 @@ typedef struct
 #endif
 } spriteframe_t;
 
+#define MAXFRAMENUM 256
+
 //
 // A sprite definition:  a number of animation frames.
 //
diff --git a/src/r_draw.c b/src/r_draw.c
index 513a54f4aefff9ac0f57b916e6e0c12d7286e4c3..86f7e488c8502516cc4f36bb04b7a516385fc5ed 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -40,23 +40,6 @@
 */
 INT32 viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
 
-/**	\brief pointer to the start of each line of the screen,
-*/
-UINT8 *ylookup[MAXVIDHEIGHT*4];
-
-/**	\brief pointer to the start of each line of the screen, for view1 (splitscreen)
-*/
-UINT8 *ylookup1[MAXVIDHEIGHT*4];
-
-/**	\brief pointer to the start of each line of the screen, for view2 (splitscreen)
-*/
-UINT8 *ylookup2[MAXVIDHEIGHT*4];
-
-/**	\brief  x byte offset for columns inside the viewwindow,
-	so the first column starts at (SCRWIDTH - VIEWWIDTH)/2
-*/
-INT32 columnofs[MAXVIDWIDTH*4];
-
 UINT8 *topleft;
 
 // =========================================================================
@@ -67,8 +50,6 @@ lighttable_t *dc_colormap;
 INT32 dc_x = 0, dc_yl = 0, dc_yh = 0;
 
 fixed_t dc_iscale, dc_texturemid;
-UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bit,
-               // soo lets make it a byte on all system for the ASM code
 UINT8 *dc_source;
 
 // -----------------------
@@ -677,7 +658,7 @@ UINT16 R_GetSuperColorByName(const char *name)
 
 void R_InitViewBuffer(INT32 width, INT32 height)
 {
-	INT32 i, bytesperpixel = vid.bpp;
+	INT32 bytesperpixel = vid.bpp;
 
 	if (width > MAXVIDWIDTH)
 		width = MAXVIDWIDTH;
@@ -689,118 +670,13 @@ void R_InitViewBuffer(INT32 width, INT32 height)
 	// Handle resize, e.g. smaller view windows with border and/or status bar.
 	viewwindowx = (vid.width - width) >> 1;
 
-	// Column offset for those columns of the view window, but relative to the entire screen
-	for (i = 0; i < width; i++)
-		columnofs[i] = (viewwindowx + i) * bytesperpixel;
-
 	// Same with base row offset.
 	if (width == vid.width)
 		viewwindowy = 0;
 	else
 		viewwindowy = (vid.height - height) >> 1;
-
-	// Precalculate all row offsets.
-	for (i = 0; i < height; i++)
-	{
-		ylookup[i] = ylookup1[i] = screens[0] + (i+viewwindowy)*vid.width*bytesperpixel;
-		ylookup2[i] = screens[0] + (i+(vid.height>>1))*vid.width*bytesperpixel; // for splitscreen
-	}
 }
 
-/**	\brief viewborder patches lump numbers
-*/
-lumpnum_t viewborderlump[8];
-
-/**	\brief Store the lumpnumber of the viewborder patches
-*/
-
-void R_InitViewBorder(void)
-{
-	viewborderlump[BRDR_T] = W_GetNumForName("brdr_t");
-	viewborderlump[BRDR_B] = W_GetNumForName("brdr_b");
-	viewborderlump[BRDR_L] = W_GetNumForName("brdr_l");
-	viewborderlump[BRDR_R] = W_GetNumForName("brdr_r");
-	viewborderlump[BRDR_TL] = W_GetNumForName("brdr_tl");
-	viewborderlump[BRDR_BL] = W_GetNumForName("brdr_bl");
-	viewborderlump[BRDR_TR] = W_GetNumForName("brdr_tr");
-	viewborderlump[BRDR_BR] = W_GetNumForName("brdr_br");
-}
-
-#if 0
-/**	\brief R_FillBackScreen
-
-	Fills the back screen with a pattern for variable screen sizes
-	Also draws a beveled edge.
-*/
-void R_FillBackScreen(void)
-{
-	UINT8 *src, *dest;
-	patch_t *patch;
-	INT32 x, y, step, boff;
-
-	// quickfix, don't cache lumps in both modes
-	if (rendermode != render_soft)
-		return;
-
-	// draw pattern around the status bar too (when hires),
-	// so return only when in full-screen without status bar.
-	if (scaledviewwidth == vid.width && viewheight == vid.height)
-		return;
-
-	src = scr_borderpatch;
-	dest = screens[1];
-
-	for (y = 0; y < vid.height; y++)
-	{
-		for (x = 0; x < vid.width/128; x++)
-		{
-			M_Memcpy (dest, src+((y&127)<<7), 128);
-			dest += 128;
-		}
-
-		if (vid.width&127)
-		{
-			M_Memcpy(dest, src+((y&127)<<7), vid.width&127);
-			dest += (vid.width&127);
-		}
-	}
-
-	// don't draw the borders when viewwidth is full vid.width.
-	if (scaledviewwidth == vid.width)
-		return;
-
-	step = 8;
-	boff = 8;
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_T], PU_CACHE);
-	for (x = 0; x < scaledviewwidth; x += step)
-		V_DrawPatch(viewwindowx + x, viewwindowy - boff, 1, patch);
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_B], PU_CACHE);
-	for (x = 0; x < scaledviewwidth; x += step)
-		V_DrawPatch(viewwindowx + x, viewwindowy + viewheight, 1, patch);
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_L], PU_CACHE);
-	for (y = 0; y < viewheight; y += step)
-		V_DrawPatch(viewwindowx - boff, viewwindowy + y, 1, patch);
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_R],PU_CACHE);
-	for (y = 0; y < viewheight; y += step)
-		V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + y, 1,
-			patch);
-
-	// Draw beveled corners.
-	V_DrawPatch(viewwindowx - boff, viewwindowy - boff, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_TL], PU_CACHE));
-	V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy - boff, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_TR], PU_CACHE));
-	V_DrawPatch(viewwindowx - boff, viewwindowy + viewheight, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_BL], PU_CACHE));
-	V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + viewheight, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_BR], PU_CACHE));
-}
-#endif
-
 /**	\brief	The R_VideoErase function
 
 	Copy a screen buffer.
@@ -822,55 +698,6 @@ void R_VideoErase(size_t ofs, INT32 count)
 	M_Memcpy(screens[0] + ofs, screens[1] + ofs, count);
 }
 
-#if 0
-/**	\brief The R_DrawViewBorder
-
-  Draws the border around the view
-	for different size windows?
-*/
-void R_DrawViewBorder(void)
-{
-	INT32 top, side, ofs;
-
-	if (rendermode == render_none)
-		return;
-#ifdef HWRENDER
-	if (rendermode != render_soft)
-	{
-		HWR_DrawViewBorder(0);
-		return;
-	}
-	else
-#endif
-
-#ifdef DEBUG
-	fprintf(stderr,"RDVB: vidwidth %d vidheight %d scaledviewwidth %d viewheight %d\n",
-		vid.width, vid.height, scaledviewwidth, viewheight);
-#endif
-
-	if (scaledviewwidth == vid.width)
-		return;
-
-	top = (vid.height - viewheight)>>1;
-	side = (vid.width - scaledviewwidth)>>1;
-
-	// copy top and one line of left side
-	R_VideoErase(0, top*vid.width+side);
-
-	// copy one line of right side and bottom
-	ofs = (viewheight+top)*vid.width - side;
-	R_VideoErase(ofs, top*vid.width + side);
-
-	// copy sides using wraparound
-	ofs = top*vid.width + vid.width-side;
-	side <<= 1;
-
-    // simpler using our VID_Blit routine
-	VID_BlitLinearScreen(screens[1] + ofs, screens[0] + ofs, side, viewheight - 1,
-		vid.width, vid.width);
-}
-#endif
-
 // R_CalcTiltedLighting
 // Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly.
 static INT32 tiltlighting[MAXVIDWIDTH];
@@ -912,11 +739,3 @@ static void R_CalcSlopeLight(void)
 
 #include "r_draw8.c"
 #include "r_draw8_npo2.c"
-
-// ==========================================================================
-//                   INCLUDE 16bpp DRAWING CODE HERE
-// ==========================================================================
-
-#ifdef HIGHCOLOR
-#include "r_draw16.c"
-#endif
diff --git a/src/r_draw.h b/src/r_draw.h
index 7eb001ebd360df404e57a5716d96aa73aa013219..1a828312a7a922353a3ff5b969908dc61dcf0ee6 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -19,10 +19,6 @@
 // -------------------------------
 // COMMON STUFF FOR 8bpp AND 16bpp
 // -------------------------------
-extern UINT8 *ylookup[MAXVIDHEIGHT*4];
-extern UINT8 *ylookup1[MAXVIDHEIGHT*4];
-extern UINT8 *ylookup2[MAXVIDHEIGHT*4];
-extern INT32 columnofs[MAXVIDWIDTH*4];
 extern UINT8 *topleft;
 
 // -------------------------
@@ -32,7 +28,6 @@ extern UINT8 *topleft;
 extern lighttable_t *dc_colormap;
 extern INT32 dc_x, dc_yl, dc_yh;
 extern fixed_t dc_iscale, dc_texturemid;
-extern UINT8 dc_hires;
 
 extern UINT8 *dc_source; // first pixel in a column
 
@@ -77,25 +72,6 @@ extern UINT32 nflatyshift;
 extern UINT32 nflatshiftup;
 extern UINT32 nflatmask;
 
-/// \brief Top border
-#define BRDR_T 0
-/// \brief Bottom border
-#define BRDR_B 1
-/// \brief Left border
-#define BRDR_L 2
-/// \brief Right border
-#define BRDR_R 3
-/// \brief Topleft border
-#define BRDR_TL 4
-/// \brief Topright border
-#define BRDR_TR 5
-/// \brief Bottomleft border
-#define BRDR_BL 6
-/// \brief Bottomright border
-#define BRDR_BR 7
-
-extern lumpnum_t viewborderlump[8];
-
 // ------------------------------------------------
 // r_draw.c COMMON ROUTINES FOR BOTH 8bpp and 16bpp
 // ------------------------------------------------
@@ -169,17 +145,8 @@ boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel);
 extern boolean skincolor_modified[];
 
 void R_InitViewBuffer(INT32 width, INT32 height);
-void R_InitViewBorder(void);
 void R_VideoErase(size_t ofs, INT32 count);
 
-// Rendering function.
-#if 0
-void R_FillBackScreen(void);
-
-// If the view size is not full screen, draws a border around it.
-void R_DrawViewBorder(void);
-#endif
-
 #define TRANSPARENTPIXEL 255
 
 // -----------------
@@ -240,17 +207,5 @@ void R_DrawTiltedTransSolidColorSpan_8(void);
 void R_DrawWaterSolidColorSpan_8(void);
 void R_DrawTiltedWaterSolidColorSpan_8(void);
 
-// ------------------
-// 16bpp DRAWING CODE
-// ------------------
-
-#ifdef HIGHCOLOR
-void R_DrawColumn_16(void);
-void R_DrawWallColumn_16(void);
-void R_DrawTranslucentColumn_16(void);
-void R_DrawTranslatedColumn_16(void);
-void R_DrawSpan_16(void);
-#endif
-
 // =========================================================================
 #endif  // __R_DRAW__
diff --git a/src/r_draw16.c b/src/r_draw16.c
deleted file mode 100644
index 2ed5a2a8e3d267ab869c5a0c800423fe7eb68eba..0000000000000000000000000000000000000000
--- a/src/r_draw16.c
+++ /dev/null
@@ -1,214 +0,0 @@
-// SONIC ROBO BLAST 2
-//-----------------------------------------------------------------------------
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-// Copyright (C) 1999-2023 by Sonic Team Junior.
-//
-// This program is free software distributed under the
-// terms of the GNU General Public License, version 2.
-// See the 'LICENSE' file for more details.
-//-----------------------------------------------------------------------------
-/// \file  r_draw16.c
-/// \brief 16bpp (HIGHCOLOR) span/column drawer functions
-/// \note  no includes because this is included as part of r_draw.c
-
-// ==========================================================================
-// COLUMNS
-// ==========================================================================
-
-/// \brief kick out the upper bit of each component (we're in 5 : 5 : 5)
-#define HIMASK1 0x7bde
-
-/**	\brief The R_DrawColumn_16 function
-	standard upto 128high posts column drawer
-*/
-void R_DrawColumn_16(void)
-{
-	INT32 count;
-	INT16 *dest;
-	fixed_t frac, fracstep;
-
-	count = dc_yh - dc_yl + 1;
-
-	// Zero length, column does not exceed a pixel.
-	if (count <= 0)
-		return;
-
-#ifdef RANGECHECK
-	if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height)
-		I_Error("R_DrawColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x);
-#endif
-
-	// Framebuffer destination address.
-	// Use ylookup LUT to avoid multiply with ScreenWidth.
-	// Use columnofs LUT for subwindows?
-	dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]);
-
-	// Determine scaling, which is the only mapping to be done.
-	fracstep = dc_iscale;
-	frac = dc_texturemid + (dc_yl - centery)*fracstep;
-
-	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
-	// This is as fast as it gets.
-
-	do
-	{
-		// Re-map color indices from wall texture column using a lighting/special effects LUT.
-		*dest = hicolormaps[((INT16 *)(void *)dc_source)[(frac>>FRACBITS)&127]>>1];
-
-		dest += vid.width;
-		frac += fracstep;
-	} while (--count);
-}
-
-/**	\brief The R_DrawWallColumn_16 function
-	LAME cutnpaste: same as R_DrawColumn_16 but wraps around 256
-	instead of 128 for the tall sky textures (256x240)
-*/
-void R_DrawWallColumn_16(void)
-{
-	INT32 count;
-	INT16 *dest;
-	fixed_t frac, fracstep;
-
-	count = dc_yh - dc_yl + 1;
-
-	// Zero length, column does not exceed a pixel.
-	if (count <= 0)
-		return;
-
-#ifdef RANGECHECK
-	if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height)
-		I_Error("R_DrawWallColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x);
-#endif
-
-	dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]);
-
-	fracstep = dc_iscale;
-	frac = dc_texturemid + (dc_yl - centery)*fracstep;
-
-	do
-	{
-		*dest = hicolormaps[((INT16 *)(void *)dc_source)[(frac>>FRACBITS)&255]>>1];
-
-		dest += vid.width;
-		frac += fracstep;
-	} while (--count);
-}
-
-/**	\brief The R_DrawTranslucentColumn_16 function
-		LAME cutnpaste: same as R_DrawColumn_16 but does
-		translucent
-*/
-void R_DrawTranslucentColumn_16(void)
-{
-	INT32 count;
-	INT16 *dest;
-	fixed_t frac, fracstep;
-
-	// check out coords for src*
-	if ((dc_yl < 0) || (dc_x >= vid.width))
-		return;
-
-	count = dc_yh - dc_yl;
-	if (count < 0)
-		return;
-
-#ifdef RANGECHECK
-	if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height)
-		I_Error("R_DrawTranslucentColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x);
-#endif
-
-	// FIXME. As above.
-	dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]);
-
-	// Looks familiar.
-	fracstep = dc_iscale;
-	frac = dc_texturemid + (dc_yl - centery)*fracstep;
-
-	// Here we do an additional index re-mapping.
-	do
-	{
-		*dest = (INT16)((INT16)((color8to16[dc_source[frac>>FRACBITS]]>>1) & 0x39ce)
-			+ (INT16)(((*dest & HIMASK1)) & 0x7fff));
-
-		dest += vid.width;
-		frac += fracstep;
-	} while (count--);
-}
-
-/**	\brief The R_DrawTranslatedColumn_16 function
-	?
-*/
-void R_DrawTranslatedColumn_16(void)
-{
-	INT32 count;
-	INT16 *dest;
-	fixed_t frac, fracstep;
-
-	count = dc_yh - dc_yl;
-	if (count < 0)
-		return;
-
-#ifdef RANGECHECK
-	if (dc_x >= vid.width || dc_yl < 0 || dc_yh >= vid.height)
-		I_Error("R_DrawTranslatedColumn_16: %d to %d at %d", dc_yl, dc_yh, dc_x);
-#endif
-
-	dest = (INT16 *)(void *)(ylookup[dc_yl] + columnofs[dc_x]);
-
-	// Looks familiar.
-	fracstep = dc_iscale;
-	frac = dc_texturemid + (dc_yl - centery)*fracstep;
-
-	// Here we do an additional index re-mapping.
-	do
-	{
-		*dest = color8to16[dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]];
-		dest += vid.width;
-
-		frac += fracstep;
-	} while (count--);
-}
-
-// ==========================================================================
-// SPANS
-// ==========================================================================
-
-/**	\brief The R_*_16 function
-	Draws the actual span.
-*/
-void R_DrawSpan_16(void)
-{
-	fixed_t xfrac, yfrac;
-	INT16 *dest;
-	INT32 count, spot;
-
-#ifdef RANGECHECK
-	if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= vid.width || ds_y > vid.height)
-		I_Error("R_DrawSpan_16: %d to %d at %d", ds_x1, ds_x2, ds_y);
-#endif
-
-	xfrac = ds_xfrac;
-	yfrac = ds_yfrac;
-
-	dest = (INT16 *)(void *)(ylookup[ds_y] + columnofs[ds_x1]);
-
-	// We do not check for zero spans here?
-	count = ds_x2 - ds_x1;
-
-	if (count <= 0) // We do now!
-		return;
-
-	do
-	{
-		// Current texture index in u, v.
-		spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
-
-		// Lookup pixel from flat texture tile, re-index using light/colormap.
-		*dest++ = hicolormaps[((INT16 *)(void *)ds_source)[spot]>>1];
-
-		// Next step in u, v.
-		xfrac += ds_xstep;
-		yfrac += ds_ystep;
-	} while (count--);
-}
diff --git a/src/r_draw8.c b/src/r_draw8.c
index 87545f41836761421f2cdf8694c07c88f6815612..99fb71e289343034bc6327314da0e64b0d687dab 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -40,18 +40,13 @@ void R_DrawColumn_8(void)
 #endif
 
 	// Framebuffer destination address.
-	// Use ylookup LUT to avoid multiply with ScreenWidth.
-	// Use columnofs LUT for subwindows?
-
-	//dest = ylookup[dc_yl] + columnofs[dc_x];
 	dest = &topleft[dc_yl*vid.width + dc_x];
 
 	count++;
 
 	// Determine scaling, which is the only mapping to be done.
 	fracstep = dc_iscale;
-	//frac = dc_texturemid + (dc_yl - centery)*fracstep;
-	frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires);
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
 
 	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
 	// This is as fast as it gets.
@@ -127,14 +122,11 @@ void R_DrawShadeColumn_8(void)
 		I_Error("R_DrawShadeColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x);
 #endif
 
-	// FIXME. As above.
-	//dest = ylookup[dc_yl] + columnofs[dc_x];
 	dest = &topleft[dc_yl*vid.width + dc_x];
 
 	// Looks familiar.
 	fracstep = dc_iscale;
-	//frac = dc_texturemid + (dc_yl - centery)*fracstep;
-	frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires);
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
 
 	// Here we do an additional index re-mapping.
 	do
@@ -166,14 +158,11 @@ void R_DrawTranslucentColumn_8(void)
 		I_Error("R_DrawTranslucentColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x);
 #endif
 
-	// FIXME. As above.
-	//dest = ylookup[dc_yl] + columnofs[dc_x];
 	dest = &topleft[dc_yl*vid.width + dc_x];
 
 	// Looks familiar.
 	fracstep = dc_iscale;
-	//frac = dc_texturemid + (dc_yl - centery)*fracstep;
-	frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires);
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
 
 	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
 	// This is as fast as it gets.
@@ -271,14 +260,11 @@ void R_DrawTranslatedTranslucentColumn_8(void)
 	if (count <= 0) // Zero length, column does not exceed a pixel.
 		return;
 
-	// FIXME. As above.
-	//dest = ylookup[dc_yl] + columnofs[dc_x];
 	dest = &topleft[dc_yl*vid.width + dc_x];
 
 	// Looks familiar.
 	fracstep = dc_iscale;
-	//frac = dc_texturemid + (dc_yl - centery)*fracstep;
-	frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires);
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
 
 	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
 	// This is as fast as it gets.
@@ -347,14 +333,11 @@ void R_DrawTranslatedColumn_8(void)
 		I_Error("R_DrawTranslatedColumn_8: %d to %d at %d", dc_yl, dc_yh, dc_x);
 #endif
 
-	// FIXME. As above.
-	//dest = ylookup[dc_yl] + columnofs[dc_x];
 	dest = &topleft[dc_yl*vid.width + dc_x];
 
 	// Looks familiar.
 	fracstep = dc_iscale;
-	//frac = dc_texturemid + (dc_yl-centery)*fracstep;
-	frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires);
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
 
 	// Here we do an additional index re-mapping.
 	do
@@ -410,7 +393,7 @@ void R_DrawSpan_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	if (dest+8 > deststop)
 		return;
@@ -489,7 +472,7 @@ void R_DrawTiltedSpan_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = ds_source;
 	//colormap = ds_colormap;
 
@@ -611,7 +594,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = ds_source;
 	//colormap = ds_colormap;
 
@@ -733,7 +716,7 @@ void R_DrawTiltedWaterSpan_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
 	source = ds_source;
 	//colormap = ds_colormap;
@@ -854,7 +837,7 @@ void R_DrawTiltedSplat_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = ds_source;
 	//colormap = ds_colormap;
 
@@ -991,7 +974,7 @@ void R_DrawSplat_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	while (count >= 8)
 	{
@@ -1111,7 +1094,7 @@ void R_DrawTranslucentSplat_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	while (count >= 8)
 	{
@@ -1214,7 +1197,7 @@ void R_DrawFloorSprite_8 (void)
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	while (count >= 8)
 	{
@@ -1325,7 +1308,7 @@ void R_DrawTranslucentFloorSprite_8 (void)
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	while (count >= 8)
 	{
@@ -1420,7 +1403,7 @@ void R_DrawTiltedFloorSprite_8(void)
 	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
 	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
@@ -1529,7 +1512,7 @@ void R_DrawTiltedTranslucentFloorSprite_8(void)
 	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
 	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
@@ -1644,7 +1627,7 @@ void R_DrawTranslucentSpan_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	while (count >= 8)
 	{
@@ -1721,7 +1704,7 @@ void R_DrawWaterSpan_8(void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
 	count = ds_x2 - ds_x1 + 1;
 
@@ -1784,7 +1767,6 @@ void R_DrawFogSpan_8(void)
 	size_t count;
 
 	colormap = ds_colormap;
-	//dest = ylookup[ds_y] + columnofs[ds_x1];
 	dest = &topleft[ds_y *vid.width + ds_x1];
 
 	count = ds_x2 - ds_x1 + 1;
@@ -1814,7 +1796,7 @@ void R_DrawTiltedFogSpan_8(void)
 {
 	int width = ds_x2 - ds_x1;
 
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 
 	R_CalcSlopeLight();
 
@@ -1834,7 +1816,7 @@ void R_DrawSolidColorSpan_8(void)
 	size_t count = (ds_x2 - ds_x1 + 1);
 
 	UINT8 source = ds_colormap[ds_source[0]];
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 
 	memset(dest, source, count);
 }
@@ -1847,7 +1829,7 @@ void R_DrawTransSolidColorSpan_8(void)
 	size_t count = (ds_x2 - ds_x1 + 1);
 
 	UINT8 source = ds_colormap[ds_source[0]];
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 
 	const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
 
@@ -1866,7 +1848,7 @@ void R_DrawTiltedSolidColorSpan_8(void)
 	int width = ds_x2 - ds_x1;
 
 	UINT8 source = ds_source[0];
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 
 	R_CalcSlopeLight();
 
@@ -1885,7 +1867,7 @@ void R_DrawTiltedTransSolidColorSpan_8(void)
 	int width = ds_x2 - ds_x1;
 
 	UINT8 source = ds_source[0];
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 
 	R_CalcSlopeLight();
 
@@ -1904,7 +1886,7 @@ void R_DrawWaterSolidColorSpan_8(void)
 {
 	UINT8 source = ds_source[0];
 	UINT8 *colormap = ds_colormap;
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 	UINT8 *dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
 
 	size_t count = (ds_x2 - ds_x1 + 1);
@@ -1925,7 +1907,7 @@ void R_DrawTiltedWaterSolidColorSpan_8(void)
 	int width = ds_x2 - ds_x1;
 
 	UINT8 source = ds_source[0];
-	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+	UINT8 *dest = &topleft[ds_y*vid.width + ds_x1];
 	UINT8 *dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
 
 	R_CalcSlopeLight();
@@ -1957,9 +1939,6 @@ void R_DrawFogColumn_8(void)
 #endif
 
 	// Framebuffer destination address.
-	// Use ylookup LUT to avoid multiply with ScreenWidth.
-	// Use columnofs LUT for subwindows?
-	//dest = ylookup[dc_yl] + columnofs[dc_x];
 	dest = &topleft[dc_yl*vid.width + dc_x];
 
 	// Determine scaling, which is the only mapping to be done.
diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c
index 78cde8a2ce195678333916f38a1b51bf5ba8e898..1ed3a8fa406ac8cb7cef2c95729a3a4de611faf0 100644
--- a/src/r_draw8_npo2.c
+++ b/src/r_draw8_npo2.c
@@ -46,7 +46,7 @@ void R_DrawSpan_NPO2_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	if (dest+8 > deststop)
 		return;
@@ -120,7 +120,7 @@ void R_DrawTiltedSpan_NPO2_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = ds_source;
 	//colormap = ds_colormap;
 
@@ -309,7 +309,7 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = ds_source;
 	//colormap = ds_colormap;
 
@@ -496,7 +496,7 @@ void R_DrawTiltedSplat_NPO2_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = ds_source;
 	//colormap = ds_colormap;
 
@@ -690,7 +690,7 @@ void R_DrawSplat_NPO2_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	fixedwidth = ds_flatwidth << FRACBITS;
 	fixedheight = ds_flatheight << FRACBITS;
@@ -758,7 +758,7 @@ void R_DrawTranslucentSplat_NPO2_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	fixedwidth = ds_flatwidth << FRACBITS;
 	fixedheight = ds_flatheight << FRACBITS;
@@ -828,7 +828,7 @@ void R_DrawFloorSprite_NPO2_8 (void)
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	fixedwidth = ds_flatwidth << FRACBITS;
 	fixedheight = ds_flatheight << FRACBITS;
@@ -898,7 +898,7 @@ void R_DrawTranslucentFloorSprite_NPO2_8 (void)
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	fixedwidth = ds_flatwidth << FRACBITS;
 	fixedheight = ds_flatheight << FRACBITS;
@@ -971,7 +971,7 @@ void R_DrawTiltedFloorSprite_NPO2_8(void)
 	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
 	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
@@ -1127,7 +1127,7 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void)
 	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
 	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	source = (UINT16 *)ds_source;
 	colormap = ds_colormap;
 	translation = ds_translation;
@@ -1278,7 +1278,7 @@ void R_DrawTranslucentSpan_NPO2_8 (void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 
 	fixedwidth = ds_flatwidth << FRACBITS;
 	fixedheight = ds_flatheight << FRACBITS;
@@ -1342,7 +1342,7 @@ void R_DrawWaterSpan_NPO2_8(void)
 
 	source = ds_source;
 	colormap = ds_colormap;
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
 
 	fixedwidth = ds_flatwidth << FRACBITS;
@@ -1414,7 +1414,7 @@ void R_DrawTiltedWaterSpan_NPO2_8(void)
 
 	R_CalcSlopeLight();
 
-	dest = ylookup[ds_y] + columnofs[ds_x1];
+	dest = &topleft[ds_y*vid.width + ds_x1];
 	dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
 	source = ds_source;
 	//colormap = ds_colormap;
diff --git a/src/r_fps.c b/src/r_fps.c
index 83fd0eec15f4c9fd0f41fa60104be022b9b4c7eb..0773f228d6c8b6fdf266aff91f4f25e07080fee1 100644
--- a/src/r_fps.c
+++ b/src/r_fps.c
@@ -817,6 +817,10 @@ void R_ResetMobjInterpolationState(mobj_t *mobj)
 	mobj->old_roll2 = mobj->old_roll;
 	mobj->old_spriteroll2 = mobj->old_spriteroll;
 	mobj->old_scale2 = mobj->old_scale;
+	mobj->old_spritexscale2 = mobj->old_spritexscale;
+	mobj->old_spriteyscale2 = mobj->old_spriteyscale;
+	mobj->old_spritexoffset2 = mobj->old_spritexoffset;
+	mobj->old_spriteyoffset2 = mobj->old_spriteyoffset;
 	mobj->old_x = mobj->x;
 	mobj->old_y = mobj->y;
 	mobj->old_z = mobj->z;
@@ -853,6 +857,10 @@ void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj)
 	mobj->old_pitch2 = mobj->old_pitch;
 	mobj->old_roll2 = mobj->old_roll;
 	mobj->old_spriteroll2 = mobj->old_spriteroll;
+	mobj->old_spritexscale2 = mobj->old_spritexscale;
+	mobj->old_spriteyscale2 = mobj->old_spriteyscale;
+	mobj->old_spritexoffset2 = mobj->old_spritexoffset;
+	mobj->old_spriteyoffset2 = mobj->old_spriteyoffset;
 	mobj->old_x = mobj->x;
 	mobj->old_y = mobj->y;
 	mobj->old_z = mobj->z;
diff --git a/src/r_main.c b/src/r_main.c
index aaab234ad1f168f2df77d2ed55b430b5cc3ff6fa..4624392944a931b4178f84038de2982f9ff371cb 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -66,6 +66,10 @@ sector_t *viewsector;
 player_t *viewplayer;
 mobj_t *r_viewmobj;
 
+boolean r_renderwalls;
+boolean r_renderfloors;
+boolean r_renderthings;
+
 fixed_t rendertimefrac;
 fixed_t renderdeltatics;
 boolean renderisnewtic;
@@ -149,8 +153,6 @@ consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT,
 
 consvar_t cv_shadow = CVAR_INIT ("shadow", "On", CV_SAVE, CV_OnOff, NULL);
 consvar_t cv_skybox = CVAR_INIT ("skybox", "On", CV_SAVE, CV_OnOff, NULL);
-consvar_t cv_ffloorclip = CVAR_INIT ("r_ffloorclip", "On", CV_SAVE, CV_OnOff, NULL);
-consvar_t cv_spriteclip = CVAR_INIT ("r_spriteclip", "On", CV_SAVE, CV_OnOff, NULL);
 consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", CV_NETVAR|CV_ALLOWLUA, CV_YesNo, NULL);
 consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", CV_CALL|CV_ALLOWLUA,  CV_YesNo, R_SetViewSize);
 consvar_t cv_translucenthud = CVAR_INIT ("translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL);
@@ -161,11 +163,16 @@ consvar_t cv_drawdist_nights = CVAR_INIT ("drawdist_nights", "2048", CV_SAVE, dr
 consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL);
 consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_SAVE|CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange);
 consvar_t cv_fovchange = CVAR_INIT ("fovchange", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
 
-// Okay, whoever said homremoval causes a performance hit should be shot.
-consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL);
+consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL);
+consvar_t cv_renderwalls = CVAR_INIT ("r_renderwalls", "On", 0, CV_OnOff, NULL);
+consvar_t cv_renderfloors = CVAR_INIT ("r_renderfloors", "On", 0, CV_OnOff, NULL);
+consvar_t cv_renderthings = CVAR_INIT ("r_renderthings", "On", 0, CV_OnOff, NULL);
+consvar_t cv_ffloorclip = CVAR_INIT ("r_ffloorclip", "On", 0, CV_OnOff, NULL);
+consvar_t cv_spriteclip = CVAR_INIT ("r_spriteclip", "On", 0, CV_OnOff, NULL);
 
-consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
+consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL);
 
 consvar_t cv_renderstats = CVAR_INIT ("renderstats", "Off", 0, CV_OnOff, NULL);
 
@@ -318,7 +325,6 @@ angle_t R_PointToAngle(fixed_t x, fixed_t y)
 }
 
 // This version uses 64-bit variables to avoid overflows with large values.
-// Currently used only by OpenGL rendering.
 angle_t R_PointToAngle64(INT64 x, INT64 y)
 {
 	return (y -= viewy, (x -= viewx) || y) ?
@@ -384,56 +390,26 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
 	return R_PointToDist2(viewx, viewy, x, y);
 }
 
-angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1)
+line_t *R_GetFFloorLine(const seg_t *seg, const ffloor_t *pfloor)
 {
-	INT64 dx = x1-x2;
-	INT64 dy = y1-y2;
-	if (dx < INT32_MIN || dx > INT32_MAX || dy < INT32_MIN || dy > INT32_MAX)
+	if (pfloor->master->flags & ML_TFERLINE)
 	{
-		x1 = (int)(dx / 2 + x2);
-		y1 = (int)(dy / 2 + y2);
+		size_t linenum = seg->linedef - pfloor->target->lines[0];
+		return pfloor->master->frontsector->lines[0] + linenum;
 	}
-	return (y1 -= y2, (x1 -= x2) || y1) ?
-	x1 >= 0 ?
-	y1 >= 0 ?
-		(x1 > y1) ? tantoangle[SlopeDivEx(y1,x1)] :                            // octant 0
-		ANGLE_90-tantoangle[SlopeDivEx(x1,y1)] :                               // octant 1
-		x1 > (y1 = -y1) ? 0-tantoangle[SlopeDivEx(y1,x1)] :                    // octant 8
-		ANGLE_270+tantoangle[SlopeDivEx(x1,y1)] :                              // octant 7
-		y1 >= 0 ? (x1 = -x1) > y1 ? ANGLE_180-tantoangle[SlopeDivEx(y1,x1)] :  // octant 3
-		ANGLE_90 + tantoangle[SlopeDivEx(x1,y1)] :                             // octant 2
-		(x1 = -x1) > (y1 = -y1) ? ANGLE_180+tantoangle[SlopeDivEx(y1,x1)] :    // octant 4
-		ANGLE_270-tantoangle[SlopeDivEx(x1,y1)] :                              // octant 5
-		0;
+	else
+		return pfloor->master;
 }
 
-//
-// R_ScaleFromGlobalAngle
-// Returns the texture mapping scale for the current line (horizontal span)
-//  at the given angle.
-// rw_distance must be calculated first.
-//
-// killough 5/2/98: reformatted, cleaned up
-//
-// note: THIS IS USED ONLY FOR WALLS!
-fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
+side_t *R_GetFFloorSide(const seg_t *seg, const ffloor_t *pfloor)
 {
-	angle_t anglea = ANGLE_90 + (visangle-viewangle);
-	angle_t angleb = ANGLE_90 + (visangle-rw_normalangle);
-	fixed_t den = FixedMul(rw_distance, FINESINE(anglea>>ANGLETOFINESHIFT));
-	// proff 11/06/98: Changed for high-res
-	fixed_t num = FixedMul(projectiony, FINESINE(angleb>>ANGLETOFINESHIFT));
-
-	if (den > num>>16)
+	if (pfloor->master->flags & ML_TFERLINE)
 	{
-		num = FixedDiv(num, den);
-		if (num > 64*FRACUNIT)
-			return 64*FRACUNIT;
-		if (num < 256)
-			return 256;
-		return num;
+		line_t *newline = R_GetFFloorLine(seg, pfloor);
+		return &sides[newline->sidenum[0]];
 	}
-	return 64*FRACUNIT;
+	else
+		return &sides[pfloor->master->sidenum[0]];
 }
 
 //
@@ -1001,8 +977,6 @@ void R_Init(void)
 	//I_OutputMsg("\nR_InitData");
 	R_InitData();
 
-	//I_OutputMsg("\nR_InitViewBorder");
-	R_InitViewBorder();
 	R_SetViewSize(); // setsizeneeded is set true
 
 	// this is now done by SCR_Recalc() at the first mode set
@@ -1363,7 +1337,7 @@ void R_SkyboxFrame(player_t *player)
 			newview->z += campos.z * -mh->skybox_scalez;
 	}
 
-	if (r_viewmobj->subsector)
+	if (!P_MobjWasRemoved(r_viewmobj) && r_viewmobj->subsector)
 		newview->sector = r_viewmobj->subsector->sector;
 	else
 		newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
@@ -1646,17 +1620,11 @@ void R_RenderPlayerView(player_t *player)
 
 void R_RegisterEngineStuff(void)
 {
-	CV_RegisterVar(&cv_gravity);
-	CV_RegisterVar(&cv_tailspickup);
-	CV_RegisterVar(&cv_allowmlook);
-	CV_RegisterVar(&cv_homremoval);
-	CV_RegisterVar(&cv_flipcam);
-	CV_RegisterVar(&cv_flipcam2);
-
-	// Enough for dedicated server
+	// Do nothing for dedicated server
 	if (dedicated)
 		return;
 
+	CV_RegisterVar(&cv_homremoval);
 	CV_RegisterVar(&cv_translucency);
 	CV_RegisterVar(&cv_drawdist);
 	CV_RegisterVar(&cv_drawdist_nights);
@@ -1669,6 +1637,13 @@ void R_RegisterEngineStuff(void)
 
 	CV_RegisterVar(&cv_shadow);
 	CV_RegisterVar(&cv_skybox);
+	CV_RegisterVar(&cv_renderview);
+	CV_RegisterVar(&cv_renderhitboxinterpolation);
+	CV_RegisterVar(&cv_renderhitboxgldepth);
+	CV_RegisterVar(&cv_renderhitbox);
+	CV_RegisterVar(&cv_renderwalls);
+	CV_RegisterVar(&cv_renderfloors);
+	CV_RegisterVar(&cv_renderthings);
 	CV_RegisterVar(&cv_ffloorclip);
 	CV_RegisterVar(&cv_spriteclip);
 
@@ -1707,8 +1682,6 @@ void R_RegisterEngineStuff(void)
 
 	CV_RegisterVar(&cv_maxportals);
 
-	CV_RegisterVar(&cv_movebob);
-
 	// Frame interpolation/uncapped
 	CV_RegisterVar(&cv_fpscap);
 }
diff --git a/src/r_main.h b/src/r_main.h
index c7dc06c901d417885750238e6424f862ddd9e3d0..aedfeb6ad0f2ca2a0caaba771f38e44ad29e1142 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -77,17 +77,18 @@ INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line);
 angle_t R_PointToAngle(fixed_t x, fixed_t y);
 angle_t R_PointToAngle64(INT64 x, INT64 y);
 angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
-angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1);
 fixed_t R_PointToDist(fixed_t x, fixed_t y);
 fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
 
-fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
 boolean R_IsPointInSector(sector_t *sector, fixed_t x, fixed_t y);
 subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
 subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y);
 
 boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph);
 
+line_t *R_GetFFloorLine(const seg_t *seg, const ffloor_t *pfloor);
+side_t *R_GetFFloorSide(const seg_t *seg, const ffloor_t *pfloor);
+
 // Render stats
 
 extern precise_t ps_prevframetime;// time when previous frame was rendered
@@ -118,12 +119,18 @@ extern consvar_t cv_chasecam, cv_chasecam2;
 extern consvar_t cv_flipcam, cv_flipcam2;
 
 extern consvar_t cv_shadow;
-extern consvar_t cv_ffloorclip, cv_spriteclip;
 extern consvar_t cv_translucency;
 extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip;
 extern consvar_t cv_fov, cv_fovchange;
 extern consvar_t cv_skybox;
-extern consvar_t cv_tailspickup;
+extern consvar_t cv_renderview;
+extern consvar_t cv_renderhitbox, cv_renderhitboxinterpolation, cv_renderhitboxgldepth;
+extern consvar_t cv_renderwalls, cv_renderfloors, cv_renderthings;
+extern consvar_t cv_ffloorclip, cv_spriteclip;
+
+extern boolean r_renderwalls;
+extern boolean r_renderfloors;
+extern boolean r_renderthings;
 
 // Called by startup code.
 void R_Init(void);
diff --git a/src/r_picformats.c b/src/r_picformats.c
index e4a59f2115d3833b3f5a76e38ff4a1cdd7d4ce30..d71657021b6e2cc91efe504b49286f459461095d 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -1570,7 +1570,7 @@ static void R_ParseSpriteInfo(boolean spr2)
 	spriteinfo_t *info;
 	char *sprinfoToken;
 	size_t sprinfoTokenLength;
-	char newSpriteName[5]; // no longer dynamically allocated
+	char newSpriteName[MAXSPRITENAME + 1]; // no longer dynamically allocated
 	spritenum_t sprnum = NUMSPRITES;
 	playersprite_t spr2num = NUMPLAYERSPRITES;
 	INT32 i;
@@ -1584,31 +1584,17 @@ static void R_ParseSpriteInfo(boolean spr2)
 		I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be");
 	}
 	sprinfoTokenLength = strlen(sprinfoToken);
-	if (sprinfoTokenLength != 4)
-	{
-		I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken);
-	}
-	else
-	{
-		memset(&newSpriteName, 0, 5);
-		M_Memcpy(newSpriteName, sprinfoToken, sprinfoTokenLength);
-		// ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer
-		strupr(newSpriteName); // Just do this now so we don't have to worry about it
-	}
+	if (sprinfoTokenLength > MAXSPRITENAME)
+		I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" is longer than %d characters", sprinfoToken, MAXSPRITENAME);
+	strcpy(newSpriteName, sprinfoToken);
+	strupr(newSpriteName); // Just do this now so we don't have to worry about it
 	Z_Free(sprinfoToken);
 
 	if (!spr2)
 	{
-		for (i = 0; i <= NUMSPRITES; i++)
-		{
-			if (i == NUMSPRITES)
-				I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
-			if (!memcmp(newSpriteName,sprnames[i],4))
-			{
-				sprnum = i;
-				break;
-			}
-		}
+		sprnum = R_GetSpriteNumByName(newSpriteName);
+		if (sprnum == NUMSPRITES)
+			I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
 	}
 	else
 	{
diff --git a/src/r_picformats.h b/src/r_picformats.h
index 3ee9805d867f30cf8eec923285b24d0172038f18..098f927a5619d74ca9813d37658d5bfb75bc8f04 100644
--- a/src/r_picformats.h
+++ b/src/r_picformats.h
@@ -100,7 +100,7 @@ typedef struct
 
 typedef struct
 {
-	spriteframepivot_t pivot[64];
+	spriteframepivot_t pivot[MAXFRAMENUM];
 	boolean available;
 } spriteinfo_t;
 
diff --git a/src/r_plane.c b/src/r_plane.c
index 4f9ce9ec84bdf7443a16b811504a30df674d78f7..33e3aac1349faebb317d47c1f30ecec5d94a55ce 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -603,6 +603,9 @@ void R_DrawPlanes(void)
 	visplane_t *pl;
 	INT32 i;
 
+	if (!r_renderfloors)
+		return;
+
 	R_UpdatePlaneRipple();
 
 	for (i = 0; i < MAXVISPLANES; i++, pl++)
@@ -626,7 +629,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
 {
 	INT32 texture = texturetranslation[skytexture];
 
-	// Reset column drawer function (note: couldn't we just call walldrawerfunc directly?)
+	// Reset column drawer function (note: couldn't we just call colfuncs[BASEDRAWFUNC] directly?)
 	// (that is, unless we'll need to switch drawers in future for some reason)
 	colfunc = colfuncs[BASEDRAWFUNC];
 
diff --git a/src/r_segs.c b/src/r_segs.c
index 453debeb6ef69840329270624f70dddae4603f49..e07ced86a7c6002c7bd127c1e2867bdae5386419 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -16,15 +16,10 @@
 #include "r_sky.h"
 
 #include "r_portal.h"
-#include "r_splats.h"
 
 #include "w_wad.h"
 #include "z_zone.h"
-#include "netcode/d_netcmd.h"
-#include "m_misc.h"
-#include "p_local.h" // Camera...
 #include "p_slopes.h"
-#include "console.h" // con_clipviewtop
 #include "taglist.h"
 
 // OPTIMIZE: closed two sided lines as single sided
@@ -79,6 +74,8 @@ static fixed_t *maskedtextureheight = NULL;
 static fixed_t *thicksidecol = NULL;
 static fixed_t *invscale = NULL;
 
+static boolean texcoltables;
+
 //SoM: 3/23/2000: Use boom opening limit removal
 static size_t numopenings;
 static INT16 *openings, *lastopening;
@@ -92,10 +89,6 @@ void R_ClearSegTables(void)
 	curtexturecolumntable = texturecolumntable;
 }
 
-// ==========================================================================
-// R_RenderMaskedSegRange
-// ==========================================================================
-
 transnum_t R_GetLinedefTransTable(fixed_t alpha)
 {
 	return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1);
@@ -115,8 +108,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	INT32 times, repeats;
 	INT64 overflow_test;
 	INT32 range;
+	UINT8 vertflip;
 	unsigned lengthcol;
 
+	fixed_t wall_scaley;
+	fixed_t scalestep;
+	fixed_t scale1;
+
 	// Calculate light table.
 	// Use different light tables
 	//   for horizontal / vertical / diagonal. Diagonal?
@@ -164,9 +162,17 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 		colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 	}
 
-	fixed_t wall_scaley = sidedef->scaley_mid;
-	fixed_t scalestep = FixedDiv(ds->scalestep, wall_scaley);
-	fixed_t scale1 = FixedDiv(ds->scale1, wall_scaley);
+	vertflip = textures[texnum]->flip & 2;
+
+	wall_scaley = sidedef->scaley_mid;
+	if (wall_scaley < 0)
+	{
+		wall_scaley = -wall_scaley;
+		vertflip = !vertflip;
+	}
+
+	scalestep = FixedDiv(ds->scalestep, wall_scaley);
+	scale1 = FixedDiv(ds->scale1, wall_scaley);
 
 	range = max(ds->x2-ds->x1, 1);
 	rw_scalestep = scalestep;
@@ -175,7 +181,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	// Texture must be cached
 	R_CheckTextureCache(texnum);
 
-	if (textures[texnum]->flip & 2) // vertically flipped?
+	if (vertflip) // vertically flipped?
 		colfunc_2s = R_DrawFlippedMaskedColumn;
 	else
 		colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
@@ -187,7 +193,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	if (frontsector->numlights)
 	{
 		dc_numlights = frontsector->numlights;
-		if (dc_numlights >= dc_maxlights)
+		if (dc_numlights > dc_maxlights)
 		{
 			dc_maxlights = dc_numlights;
 			dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL);
@@ -343,7 +349,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 			{
 				lighttable_t **xwalllights;
 
-				sprbotscreen = INT32_MAX;
 				sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale));
 
 				realbot = FixedMul(textureheight[texnum], spryscale) + sprtopscreen;
@@ -450,10 +455,13 @@ static void R_DrawRepeatMaskedColumn(column_t *col, unsigned lengthcol)
 
 static void R_DrawRepeatFlippedMaskedColumn(column_t *col, unsigned lengthcol)
 {
-	do {
+	while (sprtopscreen < sprbotscreen) {
 		R_DrawFlippedMaskedColumn(col, lengthcol);
-		sprtopscreen += dc_texheight*spryscale;
-	} while (sprtopscreen < sprbotscreen);
+		if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
+			sprtopscreen = INT32_MAX;
+		else
+			sprtopscreen += dc_texheight*spryscale;
+	}
 }
 
 // Returns true if a fake floor is translucent.
@@ -469,6 +477,11 @@ static boolean R_IsFFloorTranslucent(visffloor_t *pfloor)
 	return false;
 }
 
+static fixed_t R_GetSlopeTextureSlide(pslope_t *slope, angle_t lineangle)
+{
+	return FixedMul(slope->zdelta, FINECOSINE((lineangle-slope->xydirection)>>ANGLETOFINESHIFT));
+}
+
 //
 // R_RenderThickSideRange
 // Renders all the thick sides in the given range.
@@ -484,8 +497,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	sector_t        tempsec;
 	INT32             templight;
 	INT32             i, p;
-	fixed_t         bottombounds = viewheight << FRACBITS;
-	fixed_t         topbounds = (con_clipviewtop - 1) << FRACBITS;
 	fixed_t         offsetvalue;
 	lightlist_t     *light;
 	r_lightlist_t   *rlight;
@@ -495,12 +506,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	INT64         top_frac, top_step, bottom_frac, bottom_step;
 	// skew FOF walls with slopes?
 	fixed_t       ffloortextureslide = 0;
-	INT32         oldx = -1;
+	fixed_t       oldtexturecolumn = -1;
 	fixed_t       left_top, left_bottom; // needed here for slope skewing
 	pslope_t      *skewslope = NULL;
 	boolean do_texture_skew;
 	boolean dont_peg_bottom;
+	fixed_t wall_offsetx;
 	fixed_t wall_scalex, wall_scaley;
+	UINT8 vertflip;
 	unsigned lengthcol;
 
 	void (*colfunc_2s) (column_t *, unsigned);
@@ -513,15 +526,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	curline = ds->curline;
 	backsector = pfloor->target;
 	frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
-	sidedef = &sides[pfloor->master->sidenum[0]];
+	sidedef = R_GetFFloorSide(curline, pfloor);
 
 	colfunc = colfuncs[BASEDRAWFUNC];
 
 	if (pfloor->master->flags & ML_TFERLINE)
 	{
-		size_t linenum = curline->linedef-backsector->lines[0];
-		line_t *newline = pfloor->master->frontsector->lines[0] + linenum;
-		sidedef = &sides[newline->sidenum[0]];
+		line_t *newline = R_GetFFloorLine(curline, pfloor);
 		do_texture_skew = newline->flags & ML_SKEWTD;
 		dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
 	}
@@ -532,6 +543,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	}
 
 	texnum = R_GetTextureNum(sidedef->midtexture);
+	vertflip = textures[texnum]->flip & 2;
 
 	if (pfloor->fofflags & FOF_TRANSLUCENT)
 	{
@@ -685,18 +697,25 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 	wall_scalex = FixedDiv(FRACUNIT, sidedef->scalex_mid);
 	wall_scaley = sidedef->scaley_mid;
+	if (wall_scaley < 0)
+	{
+		wall_scaley = -wall_scaley;
+		vertflip = !vertflip;
+	}
 
 	thicksidecol = ffloortexturecolumn;
 
+	wall_offsetx = ds->offsetx + sidedef->offsetx_mid;
+
 	if (wall_scalex == FRACUNIT)
 	{
 		for (INT32 x = x1; x <= x2; x++)
-			thicksidecol[x] = ds->thicksidecol[x] + ds->offsetx;
+			thicksidecol[x] = ds->thicksidecol[x];
 	}
 	else
 	{
 		for (INT32 x = x1; x <= x2; x++)
-			thicksidecol[x] = FixedDiv(ds->thicksidecol[x], wall_scalex) + ds->offsetx;
+			thicksidecol[x] = FixedDiv(ds->thicksidecol[x], wall_scalex);
 	}
 
 	mfloorclip = ds->sprbottomclip;
@@ -731,7 +750,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	if (skewslope)
 	{
 		angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y);
-		ffloortextureslide = FixedMul(skewslope->zdelta, FINECOSINE((lineangle-skewslope->xydirection)>>ANGLETOFINESHIFT));
+		ffloortextureslide = FixedMul(R_GetSlopeTextureSlide(skewslope, lineangle), wall_scaley);
 	}
 
 	dc_texturemid += offsetvalue;
@@ -739,10 +758,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	// Texture must be cached
 	R_CheckTextureCache(texnum);
 
-	if (textures[texnum]->flip & 2) // vertically flipped?
+	if (vertflip) // vertically flipped?
 		colfunc_2s = R_DrawRepeatFlippedMaskedColumn;
 	else
-		colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture
+		colfunc_2s = R_DrawRepeatMaskedColumn;
 
 	lengthcol = textures[texnum]->height;
 
@@ -773,9 +792,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		// skew FOF walls
 		if (ffloortextureslide)
 		{
-			if (oldx != -1)
-				dc_texturemid += FixedMul(ffloortextureslide, thicksidecol[oldx]-thicksidecol[dc_x]);
-			oldx = dc_x;
+			if (oldtexturecolumn != -1)
+				dc_texturemid += FixedMul(ffloortextureslide, oldtexturecolumn-ds->thicksidecol[dc_x]);
+			oldtexturecolumn = ds->thicksidecol[dc_x];
 		}
 
 		// Calculate bounds
@@ -787,11 +806,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac;
 		else                                    sprbotscreen = windowbottom = CLAMPMIN;
 
+		fixed_t bottomclip = sprbotscreen;
+
 		top_frac += top_step;
 		bottom_frac += bottom_step;
 
 		// SoM: If column is out of range, why bother with it??
-		if (windowbottom < topbounds || windowtop > bottombounds)
+		if (windowbottom < 0 || windowtop > (viewheight << FRACBITS))
 		{
 			if (dc_numlights)
 			{
@@ -810,7 +831,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		dc_iscale = FixedMul(0xffffffffu / (unsigned)spryscale, wall_scaley);
 
 		// Get data for the column
-		col = R_GetColumn(texnum, (thicksidecol[dc_x] >> FRACBITS));
+		col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS));
 
 		// SoM: New code does not rely on R_DrawColumnShadowed_8 which
 		// will (hopefully) put less strain on the stack.
@@ -819,14 +840,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			lighttable_t **xwalllights;
 			fixed_t height;
 			fixed_t bheight = 0;
-			INT32 solid = 0;
-			INT32 lighteffect = 0;
+			boolean lighteffect = false;
 
 			for (i = 0; i < dc_numlights; i++)
 			{
 				// Check if the current light effects the colormap/lightlevel
 				rlight = &dc_lightlist[i];
-				lighteffect = !(dc_lightlist[i].flags & FOF_NOSHADE);
+				lighteffect = !(rlight->flags & FOF_NOSHADE);
 				if (lighteffect)
 				{
 					lightnum = rlight->lightnum;
@@ -859,11 +879,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 					}
 				}
 
-				solid = 0; // don't carry over solid-cutting flag from the previous light
-
 				// Check if the current light can cut the current 3D floor.
+				boolean solid = false;
+
 				if (rlight->flags & FOF_CUTSOLIDS && !(pfloor->fofflags & FOF_EXTRA))
-					solid = 1;
+					solid = true;
 				else if (rlight->flags & FOF_CUTEXTRA && pfloor->fofflags & FOF_EXTRA)
 				{
 					if (rlight->flags & FOF_EXTRA)
@@ -871,13 +891,13 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 						// The light is from an extra 3D floor... Check the flags so
 						// there are no undesired cuts.
 						if ((rlight->flags & (FOF_FOG|FOF_SWIMMABLE)) == (pfloor->fofflags & (FOF_FOG|FOF_SWIMMABLE)))
-							solid = 1;
+							solid = true;
 					}
 					else
-						solid = 1;
+						solid = true;
 				}
 				else
-					solid = 0;
+					solid = false;
 
 				height = rlight->height;
 				rlight->height += rlight->heightstep;
@@ -893,14 +913,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 					if (lighteffect)
 						dc_colormap = rlight->rcolormap;
 					if (solid && windowtop < bheight)
-						windowtop = bheight;
+						sprtopscreen = windowtop = bheight;
 					continue;
 				}
 
-				windowbottom = height;
-				if (windowbottom >= sprbotscreen)
+				sprbotscreen = windowbottom = height;
+				if (windowbottom >= bottomclip)
 				{
-					windowbottom = sprbotscreen;
+					sprbotscreen = windowbottom = bottomclip;
 					// draw the texture
 					colfunc_2s (col, lengthcol);
 					for (i++; i < dc_numlights; i++)
@@ -918,10 +938,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 					windowtop = bheight;
 				else
 					windowtop = windowbottom + 1;
+				sprtopscreen = windowtop;
 				if (lighteffect)
 					dc_colormap = rlight->rcolormap;
 			}
-			windowbottom = sprbotscreen;
+			sprbotscreen = windowbottom = bottomclip;
 			// draw the texture, if there is any space left
 			if (windowtop < windowbottom)
 				colfunc_2s (col, lengthcol);
@@ -984,36 +1005,77 @@ static boolean R_FFloorCanClip(visffloor_t *pfloor)
 #define HEIGHTBITS              12
 #define HEIGHTUNIT              (1<<HEIGHTBITS)
 
+static void R_DrawRegularWall(UINT8 *source, INT32 height)
+{
+	dc_source = source;
+	dc_texheight = height;
+	colfunc();
+}
 
-//profile stuff ---------------------------------------------------------
-//#define TIMING
-#ifdef TIMING
-#include "p5prof.h"
-INT64 mycount;
-INT64 mytotal = 0;
-UINT32 nombre = 100000;
-//static   char runtest[10][80];
-#endif
-//profile stuff ---------------------------------------------------------
+static void R_DrawFlippedWall(UINT8 *source, INT32 height)
+{
+	dc_texheight = height;
+	R_DrawFlippedPost(source, (unsigned)height, colfunc);
+}
+
+static void R_DrawNoWall(UINT8 *source, INT32 height)
+{
+	(void)source;
+	(void)height;
+}
 
 static void R_RenderSegLoop (void)
 {
 	angle_t angle;
 	fixed_t textureoffset;
-	size_t  pindex;
-	INT32     yl;
-	INT32     yh;
+	size_t pindex;
+	INT32 yl;
+	INT32 yh;
 
-	INT32     mid;
+	INT32 mid;
 	fixed_t texturecolumn = 0;
 	fixed_t toptexturecolumn = 0;
 	fixed_t bottomtexturecolumn = 0;
 	fixed_t oldtexturecolumn = -1;
 	fixed_t oldtexturecolumn_top = -1;
 	fixed_t oldtexturecolumn_bottom = -1;
-	INT32     top;
-	INT32     bottom;
-	INT32     i;
+	INT32 top;
+	INT32 bottom;
+	INT32 i;
+
+	fixed_t topscaley = rw_toptexturescaley;
+	fixed_t midscaley = rw_midtexturescaley;
+	fixed_t bottomscaley = rw_bottomtexturescaley;
+
+	void (*drawtop)(UINT8 *, INT32) = R_DrawRegularWall;
+	void (*drawmiddle)(UINT8 *, INT32) = R_DrawRegularWall;
+	void (*drawbottom)(UINT8 *, INT32) = R_DrawRegularWall;
+
+	if (dc_numlights)
+		colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
+
+	if (toptexture && topscaley < 0)
+	{
+		topscaley = -topscaley;
+		drawtop = R_DrawFlippedWall;
+	}
+	if (midtexture && midscaley < 0)
+	{
+		midscaley = -midscaley;
+		drawmiddle = R_DrawFlippedWall;
+	}
+	if (bottomtexture && bottomscaley < 0)
+	{
+		bottomscaley = -bottomscaley;
+		drawbottom = R_DrawFlippedWall;
+	}
+
+	if (!r_renderwalls)
+	{
+		drawtop = R_DrawNoWall;
+		drawmiddle = R_DrawNoWall;
+		drawbottom = R_DrawNoWall;
+	}
 
 	if (midtexture)
 		R_CheckTextureCache(midtexture);
@@ -1022,6 +1084,9 @@ static void R_RenderSegLoop (void)
 	if (bottomtexture)
 		R_CheckTextureCache(bottomtexture);
 
+	if (dc_numlights)
+		colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
+
 	for (; rw_x < rw_stopx; rw_x++)
 	{
 		// mark floor / ceiling areas
@@ -1234,8 +1299,6 @@ static void R_RenderSegLoop (void)
 					dc_lightlist[i].rcolormap = dc_lightlist[i].extra_colormap->colormap + (xwalllights[pindex] - colormaps);
 				else
 					dc_lightlist[i].rcolormap = xwalllights[pindex];
-
-				colfunc = colfuncs[COLDRAWFUNC_SHADOWED];
 			}
 		}
 
@@ -1252,24 +1315,9 @@ static void R_RenderSegLoop (void)
 				dc_yl = yl;
 				dc_yh = yh;
 				dc_texturemid = rw_midtexturemid;
-				dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, rw_midtexturescaley);
-				dc_source = R_GetColumn(midtexture, offset >> FRACBITS)->pixels;
 				dc_texheight = textureheight[midtexture]>>FRACBITS;
-
-				//profile stuff ---------------------------------------------------------
-#ifdef TIMING
-				ProfZeroTimer();
-#endif
-				colfunc();
-#ifdef TIMING
-				RDMSR(0x10,&mycount);
-				mytotal += mycount;      //64bit add
-
-				if (nombre--==0)
-					I_Error("R_DrawColumn CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1),
-						(INT32)mytotal);
-#endif
-				//profile stuff ---------------------------------------------------------
+				dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, midscaley);
+				drawmiddle(R_GetColumn(midtexture, offset >> FRACBITS)->pixels, dc_texheight);
 
 				// dont draw anything more for this column, since
 				// a midtexture blocks the view
@@ -1321,10 +1369,9 @@ static void R_RenderSegLoop (void)
 						dc_yl = yl;
 						dc_yh = mid;
 						dc_texturemid = rw_toptexturemid;
-						dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, rw_toptexturescaley);
-						dc_source = R_GetColumn(toptexture, offset >> FRACBITS)->pixels;
 						dc_texheight = textureheight[toptexture]>>FRACBITS;
-						colfunc();
+						dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, topscaley);
+						drawtop(R_GetColumn(toptexture, offset >> FRACBITS)->pixels, dc_texheight);
 						ceilingclip[rw_x] = (INT16)mid;
 					}
 					else if (!rw_ceilingmarked) // entirely off top of screen
@@ -1334,8 +1381,8 @@ static void R_RenderSegLoop (void)
 					ceilingclip[rw_x] = topclip;
 
 				if (oldtexturecolumn_top != -1)
-					rw_toptexturemid += FixedMul(rw_toptextureslide, oldtexturecolumn_top-toptexturecolumn);
-				oldtexturecolumn_top = toptexturecolumn;
+					rw_toptexturemid += FixedMul(rw_toptextureslide, oldtexturecolumn_top-textureoffset);
+				oldtexturecolumn_top = textureoffset;
 			}
 			else if (markceiling && (!rw_ceilingmarked)) // no top wall
 				ceilingclip[rw_x] = topclip;
@@ -1369,10 +1416,9 @@ static void R_RenderSegLoop (void)
 						dc_yl = mid;
 						dc_yh = yh;
 						dc_texturemid = rw_bottomtexturemid;
-						dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, rw_bottomtexturescaley);
-						dc_source = R_GetColumn(bottomtexture, offset >> FRACBITS)->pixels;
 						dc_texheight = textureheight[bottomtexture]>>FRACBITS;
-						colfunc();
+						dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, bottomscaley);
+						drawbottom(R_GetColumn(bottomtexture, offset >> FRACBITS)->pixels, dc_texheight);
 						floorclip[rw_x] = (INT16)mid;
 					}
 					else if (!rw_floormarked)  // entirely off bottom of screen
@@ -1382,8 +1428,8 @@ static void R_RenderSegLoop (void)
 					floorclip[rw_x] = bottomclip;
 
 				if (oldtexturecolumn_bottom != -1)
-					rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn_bottom-bottomtexturecolumn);
-				oldtexturecolumn_bottom = bottomtexturecolumn;
+					rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn_bottom-textureoffset);
+				oldtexturecolumn_bottom = textureoffset;
 			}
 			else if (markfloor && (!rw_floormarked)) // no bottom wall
 				floorclip[rw_x] = bottomclip;
@@ -1407,11 +1453,14 @@ static void R_RenderSegLoop (void)
 		{
 			if (oldtexturecolumn != -1)
 			{
-				rw_midtexturemid += FixedMul(rw_midtextureslide, oldtexturecolumn-texturecolumn);
-				rw_midtextureback += FixedMul(rw_midtexturebackslide, oldtexturecolumn-texturecolumn);
+				INT32 diff = oldtexturecolumn-textureoffset;
+				if (rw_invmidtexturescalex < 0)
+					diff = -diff;
+				rw_midtexturemid += FixedMul(rw_midtextureslide, diff);
+				rw_midtextureback += FixedMul(rw_midtexturebackslide, diff);
 			}
 
-			oldtexturecolumn = texturecolumn;
+			oldtexturecolumn = textureoffset;
 		}
 
 		if (invscale)
@@ -1505,7 +1554,7 @@ static void R_AllocClippingTables(size_t range)
 static void R_AllocTextureColumnTables(size_t range)
 {
 	size_t pos = curtexturecolumntable - texturecolumntable;
-	size_t need = range * 3;
+	size_t need = range * 4;
 
 	if (pos + need < texturecolumntablesize)
 		return;
@@ -1526,13 +1575,46 @@ static void R_AllocTextureColumnTables(size_t range)
 	for (drawseg_t *ds = drawsegs; ds < ds_p; ds++)
 	{
 		// Check if it's in range of the tables
-		if (ds->maskedtexturecol + ds->x1 >= oldtable && ds->maskedtexturecol + ds->x1 <= oldlast)
-			ds->maskedtexturecol = (ds->maskedtexturecol - oldtable) + texturecolumntable;
-		if (ds->thicksidecol + ds->x1 >= oldtable && ds->thicksidecol + ds->x1 <= oldlast)
-			ds->thicksidecol = (ds->thicksidecol - oldtable) + texturecolumntable;
-		if (ds->invscale + ds->x1 >= oldtable && ds->invscale + ds->x1 <= oldlast)
-			ds->invscale = (ds->invscale - oldtable) + texturecolumntable;
+#define CHECK(which) \
+		if (which + ds->x1 >= oldtable && which + ds->x1 <= oldlast) \
+			which = (which - oldtable) + texturecolumntable
+
+		CHECK(ds->maskedtexturecol);
+		CHECK(ds->maskedtextureheight);
+		CHECK(ds->thicksidecol);
+		CHECK(ds->invscale);
+
+#undef CHECK
+	}
+}
+
+//
+// R_ScaleFromGlobalAngle
+// Returns the texture mapping scale for the current line (horizontal span)
+//  at the given angle.
+// rw_distance must be calculated first.
+//
+// killough 5/2/98: reformatted, cleaned up
+//
+// note: THIS IS USED ONLY FOR WALLS!
+static fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
+{
+	angle_t anglea = ANGLE_90 + (visangle-viewangle);
+	angle_t angleb = ANGLE_90 + (visangle-rw_normalangle);
+	fixed_t den = FixedMul(rw_distance, FINESINE(anglea>>ANGLETOFINESHIFT));
+	// proff 11/06/98: Changed for high-res
+	fixed_t num = FixedMul(projectiony, FINESINE(angleb>>ANGLETOFINESHIFT));
+
+	if (den > num>>16)
+	{
+		num = FixedDiv(num, den);
+		if (num > 64*FRACUNIT)
+			return 64*FRACUNIT;
+		if (num < 256)
+			return 256;
+		return num;
 	}
+	return 64*FRACUNIT;
 }
 
 //
@@ -1706,11 +1788,14 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 	midtexture = toptexture = bottomtexture = maskedtexture = 0;
 	ds_p->maskedtexturecol = NULL;
+	ds_p->maskedtextureheight = NULL;
 	ds_p->numthicksides = numthicksides = 0;
 	ds_p->thicksidecol = NULL;
 	ds_p->invscale = NULL;
 	ds_p->tsilheight = 0;
 
+	texcoltables = false;
+
 	numbackffloors = 0;
 
 	for (i = 0; i < MAXFFLOORS; i++)
@@ -1736,16 +1821,19 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y);
 
 		if (frontsector->f_slope)
-			floorfrontslide = FixedMul(frontsector->f_slope->zdelta, FINECOSINE((lineangle-frontsector->f_slope->xydirection)>>ANGLETOFINESHIFT));
+			floorfrontslide = R_GetSlopeTextureSlide(frontsector->f_slope, lineangle);
 
 		if (frontsector->c_slope)
-			ceilingfrontslide = FixedMul(frontsector->c_slope->zdelta, FINECOSINE((lineangle-frontsector->c_slope->xydirection)>>ANGLETOFINESHIFT));
+			ceilingfrontslide = R_GetSlopeTextureSlide(frontsector->c_slope, lineangle);
 
-		if (backsector && backsector->f_slope)
-			floorbackslide = FixedMul(backsector->f_slope->zdelta, FINECOSINE((lineangle-backsector->f_slope->xydirection)>>ANGLETOFINESHIFT));
+		if (backsector)
+		{
+			if (backsector->f_slope)
+				floorbackslide = R_GetSlopeTextureSlide(backsector->f_slope, lineangle);
 
-		if (backsector && backsector->c_slope)
-			ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT));
+			if (backsector->c_slope)
+				ceilingbackslide = R_GetSlopeTextureSlide(backsector->c_slope, lineangle);
+		}
 	}
 
 	rw_midtexturescalex = sidedef->scalex_mid;
@@ -1761,26 +1849,27 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 		fixed_t rowoffset = sidedef->rowoffset + sidedef->offsety_mid;
 		fixed_t texheight = textureheight[midtexture];
+		fixed_t scaley = abs(rw_midtexturescaley);
 
 		if (rw_midtexturescaley > 0)
 		{
 			if (linedef->flags & ML_NOSKEW)
 			{
 				if (linedef->flags & ML_DONTPEGBOTTOM)
-					rw_midtexturemid = FixedMul(frontsector->floorheight - viewz, rw_midtexturescaley) + texheight;
+					rw_midtexturemid = FixedMul(frontsector->floorheight - viewz, scaley) + texheight;
 				else
-					rw_midtexturemid = FixedMul(frontsector->ceilingheight - viewz, rw_midtexturescaley);
+					rw_midtexturemid = FixedMul(frontsector->ceilingheight - viewz, scaley);
 			}
 			else if (linedef->flags & ML_DONTPEGBOTTOM)
 			{
-				rw_midtexturemid = FixedMul(worldbottom, rw_midtexturescaley) + texheight;
-				rw_midtextureslide = floorfrontslide;
+				rw_midtexturemid = FixedMul(worldbottom, scaley) + texheight;
+				rw_midtextureslide = FixedMul(floorfrontslide, scaley);
 			}
 			else
 			{
 				// top of texture at top
-				rw_midtexturemid = FixedMul(worldtop, rw_midtexturescaley);
-				rw_midtextureslide = ceilingfrontslide;
+				rw_midtexturemid = FixedMul(worldtop, scaley);
+				rw_midtextureslide = FixedMul(ceilingfrontslide, scaley);
 			}
 		}
 		else
@@ -1791,20 +1880,20 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			if (linedef->flags & ML_NOSKEW)
 			{
 				if (linedef->flags & ML_DONTPEGBOTTOM)
-					rw_midtexturemid = FixedMul(frontsector->floorheight - viewz, rw_midtexturescaley);
+					rw_midtexturemid = FixedMul(frontsector->floorheight - viewz, scaley);
 				else
-					rw_midtexturemid = FixedMul(frontsector->ceilingheight - viewz, rw_midtexturescaley) + texheight;
+					rw_midtexturemid = FixedMul(frontsector->ceilingheight - viewz, scaley) + texheight;
 			}
 			else if (linedef->flags & ML_DONTPEGBOTTOM)
 			{
-				rw_midtexturemid = FixedMul(worldbottom, rw_midtexturescaley);
-				rw_midtextureslide = floorfrontslide;
+				rw_midtexturemid = FixedMul(worldbottom, scaley);
+				rw_midtextureslide = FixedMul(floorfrontslide, scaley);
 			}
 			else
 			{
 				// top of texture at top
-				rw_midtexturemid = FixedMul(worldtop, rw_midtexturescaley) + texheight;
-				rw_midtextureslide = ceilingfrontslide;
+				rw_midtexturemid = FixedMul(worldtop, scaley) + texheight;
+				rw_midtextureslide = FixedMul(ceilingfrontslide, scaley);
 			}
 		}
 
@@ -2013,15 +2102,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			{
 				// top of texture at top
 				rw_toptexturemid = worldtop;
-				rw_toptextureslide = ceilingfrontslide;
+				rw_toptextureslide = FixedMul(ceilingfrontslide, abs(rw_toptexturescaley));
 			}
 			else
 			{
 				rw_toptexturemid = worldhigh + texheight;
-				rw_toptextureslide = ceilingbackslide;
+				rw_toptextureslide = FixedMul(ceilingbackslide, abs(rw_toptexturescaley));
 			}
 
-			rw_toptexturemid = FixedMul(rw_toptexturemid, rw_toptexturescaley);
+			rw_toptexturemid = FixedMul(rw_toptexturemid, abs(rw_toptexturescaley));
+			rw_toptexturemid += toprowoffset;
 		}
 
 		// check BOTTOM TEXTURE
@@ -2052,24 +2142,24 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 				// bottom of texture at bottom
 				// top of texture at top
 				rw_bottomtexturemid = worldbottom;
-				rw_bottomtextureslide = floorfrontslide;
+				rw_bottomtextureslide = FixedMul(floorfrontslide, abs(rw_bottomtexturescaley));
 			}
 			else
 			{
 				// top of texture at top
 				rw_bottomtexturemid = worldlow;
-				rw_bottomtextureslide = floorbackslide;
+				rw_bottomtextureslide = FixedMul(floorbackslide, abs(rw_bottomtexturescaley));
 			}
 
-			rw_bottomtexturemid = FixedMul(rw_bottomtexturemid, rw_bottomtexturescaley);
+			rw_bottomtexturemid = FixedMul(rw_bottomtexturemid, abs(rw_bottomtexturescaley));
+			rw_bottomtexturemid += botrowoffset;
 		}
 
-		rw_toptexturemid += toprowoffset;
-		rw_bottomtexturemid += botrowoffset;
-
 		// allocate space for masked texture tables
 		R_AllocTextureColumnTables(rw_stopx - start);
 
+		texcoltables = true;
+
 		if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors))
 		{
 			ffloor_t *rover;
@@ -2268,7 +2358,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x;
 			curtexturecolumntable += rw_stopx - rw_x;
 
-			maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0])
+			ds_p->maskedtextureheight = maskedtextureheight = curtexturecolumntable - rw_x;
+			curtexturecolumntable += rw_stopx - rw_x;
 
 			maskedtexture = true;
 
@@ -2310,13 +2401,14 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 				}
 			}
 
-			rw_midtexturemid = FixedMul(rw_midtexturemid, rw_midtexturescaley);
-			rw_midtextureback = FixedMul(rw_midtextureback, rw_midtexturescaley);
+			rw_midtexturemid = FixedMul(rw_midtexturemid, abs(rw_midtexturescaley));
+			rw_midtextureback = FixedMul(rw_midtextureback, abs(rw_midtexturescaley));
+
+			rw_midtextureslide = FixedMul(rw_midtextureslide, abs(rw_midtexturescaley));
+			rw_midtexturebackslide = FixedMul(rw_midtexturebackslide, abs(rw_midtexturescaley));
 
 			rw_midtexturemid += sidedef->rowoffset + sidedef->offsety_mid;
 			rw_midtextureback += sidedef->rowoffset + sidedef->offsety_mid;
-
-			maskedtexture = true;
 		}
 	}
 
@@ -2440,7 +2532,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	if (frontsector->numlights)
 	{
 		dc_numlights = frontsector->numlights;
-		if (dc_numlights >= dc_maxlights)
+		if (dc_numlights > dc_maxlights)
 		{
 			dc_maxlights = dc_numlights;
 			dc_lightlist = Z_Realloc(dc_lightlist, sizeof (*dc_lightlist) * dc_maxlights, PU_STATIC, NULL);
diff --git a/src/r_skins.c b/src/r_skins.c
index 6b4aeefe1726e46ee3f169540d5e87ad15dc271e..cd7d60b53e4c572630e26980309729a121d43cb7 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -35,30 +35,86 @@
 INT32 numskins = 0;
 skin_t **skins = NULL;
 
-//
-// P_GetSkinSprite2
-// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
-// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
-//
-
-UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
+// Gets the animation ID of a state
+UINT16 P_GetStateSprite2(state_t *state)
 {
-	UINT8 super = 0, i = 0;
+	if (state->sprite2)
+		return state->sprite2;
+	else
+	{
+		// Transform the state frame into an animation ID
+		UINT16 spr2 = state->frame & FF_FRAMEMASK;
 
-	if (!skin)
+		if (state->frame & SPR2F_SUPER)
+			spr2 |= SPR2F_SUPER;
+
+		return spr2;
+	}
+}
+
+// Gets the starting frame of an animation
+UINT16 P_GetSprite2StateFrame(state_t *state)
+{
+	if (state->sprite2)
+		return state->frame & FF_FRAMEMASK;
+	else
 		return 0;
+}
+
+// Checks if a state should use the "super" variant of the animation
+boolean P_IsStateSprite2Super(state_t *state)
+{
+	if (state->sprite2)
+	{
+		if (state->sprite2 & SPR2F_SUPER)
+			return true;
+	}
+	else if (state->frame & SPR2F_SUPER)
+		return true;
+
+	return false;
+}
+
+// Applies SPR2F_SUPER to an animation based on the actor's state
+UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj)
+{
+	if (mobj->player)
+	{
+		if (mobj->player->charflags & SF_NOSUPERSPRITES || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_NONIGHTSSUPER)))
+			spr2 &= ~SPR2F_SUPER;
+		else if (mobj->player->powers[pw_super] || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_SUPER)))
+			spr2 |= SPR2F_SUPER;
+	}
+
+	if (spr2 & SPR2F_SUPER)
+	{
+		if (mobj->eflags & MFE_FORCENOSUPER)
+			spr2 &= ~SPR2F_SUPER;
+	}
+	else if (mobj->eflags & MFE_FORCESUPER)
+		spr2 |= SPR2F_SUPER;
 
-	if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
+	return spr2;
+}
+
+// For non-super players, this tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
+// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
+UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player)
+{
+	UINT16 super = 0;
+	UINT8 i = 0;
+
+	if (!skin)
 		return 0;
 
-	while (!skin->sprites[spr2].numframes
+	while (!P_IsValidSprite2(skin, spr2)
 		&& spr2 != SPR2_STND
 		&& ++i < 32) // recursion limiter
 	{
-		if (spr2 & FF_SPR2SUPER)
+		if (spr2 & SPR2F_SUPER)
 		{
-			super = FF_SPR2SUPER;
-			spr2 &= ~FF_SPR2SUPER;
+			super = SPR2F_SUPER;
+			spr2 &= ~SPR2F_SUPER;
 			continue;
 		}
 
@@ -92,6 +148,51 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
 	return spr2;
 }
 
+// Gets the spritedef of a skin animation
+spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2)
+{
+	if (!skin)
+		return NULL;
+
+	boolean is_super = spr2 & SPR2F_SUPER;
+
+	spr2 &= SPR2F_MASK;
+
+	if (spr2 >= free_spr2)
+		return NULL;
+
+	if (is_super)
+		return &skin->super.sprites[spr2];
+	else
+		return &skin->sprites[spr2];
+}
+
+// Gets the spriteinfo of a skin animation
+spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2)
+{
+	if (!skin)
+		return NULL;
+
+	boolean is_super = spr2 & SPR2F_SUPER;
+
+	spr2 &= SPR2F_MASK;
+
+	if (spr2 >= free_spr2)
+		return NULL;
+
+	if (is_super)
+		return &skin->super.sprinfo[spr2];
+	else
+		return &skin->sprinfo[spr2];
+}
+
+// Checks if a skin animation is valid
+boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2)
+{
+	spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
+	return sprdef && sprdef->numframes;
+}
+
 static void Sk_SetDefaultValue(skin_t *skin)
 {
 	INT32 i;
@@ -376,7 +477,7 @@ static void SetSkin(player_t *player, INT32 skinnum)
 		player->mo->skin = skin;
 		if (newcolor)
 			player->mo->color = newcolor;
-		P_SetScale(player->mo, player->mo->scale);
+		P_SetScale(player->mo, player->mo->scale, false);
 		player->mo->radius = radius;
 
 		P_SetMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames
@@ -500,10 +601,10 @@ static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
 	return INT16_MAX; // not found
 }
 
-static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT8 start_spr2)
+static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT16 start_spr2)
 {
 	UINT16 newlastlump;
-	UINT8 sprite2;
+	UINT16 sprite2;
 
 	*lump += 1; // start after S_SKIN
 	*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
@@ -523,7 +624,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
 		newlastlump++;
 		// load all sprite sets we are aware of... for super!
 		for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
-			R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump);
+			R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump, false);
 
 		newlastlump--;
 		*lastlump = newlastlump; // okay, make the normal sprite set loading end there
@@ -531,7 +632,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
 
 	// load all sprite sets we are aware of... for normal stuff.
 	for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
-		R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump);
+		R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump, false);
 
 	if (skin->sprites[0].numframes == 0)
 		CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]);
diff --git a/src/r_skins.h b/src/r_skins.h
index cc3b63cbed2c97de3fc312ad338d6f201edcd65b..1f2c57472d23ffd3026f0370e591dcd18ad77193 100644
--- a/src/r_skins.h
+++ b/src/r_skins.h
@@ -80,9 +80,14 @@ typedef struct
 	// specific sounds per skin
 	sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
 
+	spritedef_t sprites[NUMPLAYERSPRITES];
+	spriteinfo_t sprinfo[NUMPLAYERSPRITES];
+
 	// contains super versions too
-	spritedef_t sprites[NUMPLAYERSPRITES*2];
-	spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
+	struct {
+		spritedef_t sprites[NUMPLAYERSPRITES];
+		spriteinfo_t sprinfo[NUMPLAYERSPRITES];
+	} super;
 } skin_t;
 
 /// Externs
@@ -102,7 +107,14 @@ INT32 R_GetForcedSkin(INT32 playernum);
 void R_AddSkins(UINT16 wadnum, boolean mainfile);
 void R_PatchSkins(UINT16 wadnum, boolean mainfile);
 
-UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
+UINT16 P_GetStateSprite2(state_t *state);
+UINT16 P_GetSprite2StateFrame(state_t *state);
+UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player);
+UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj);
+spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2);
+spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2);
+boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2);
+boolean P_IsStateSprite2Super(state_t *state);
 
 void R_RefreshSprite2(void);
 
diff --git a/src/r_textures.c b/src/r_textures.c
index 59cc114139c5abb24df0f47fa0dddd0e70ec8d72..5d3fe24db2c942647d514a92ad42a759d0b3c9f4 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -821,8 +821,8 @@ Rloadflats (INT32 i, INT32 w)
 			UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
 			if (Picture_PNGDimensions((UINT8 *)flatlump, &texw, &texh, NULL, NULL, lumplength))
 			{
-				width = (INT16)width;
-				height = (INT16)height;
+				width = (INT16)texw;
+				height = (INT16)texh;
 			}
 			else
 			{
@@ -1068,6 +1068,98 @@ void R_LoadTexturesPwad(UINT16 wadnum)
 	R_FinishLoadingTextures(newtextures);
 }
 
+static lumpnum_t W_GetTexPatchLumpNum(const char *name)
+{
+	// Flats as a texture patch crashes horribly, and flats
+	// can share the same name as textures.
+
+	// But even if they worked, we want to prioritize:
+	// Patches -> Textures -> anything else
+
+	enum
+	{
+		USE_PATCHES,
+		USE_TEXTURES,
+		USE__MAX,
+	};
+
+	lumpnum_t lump = LUMPERROR;
+	INT32 lump_type_it;
+	
+
+	for (lump_type_it = 0; lump_type_it < USE__MAX; lump_type_it++)
+	{
+		INT32 i;
+
+		for (i = numwadfiles - 1; i >= 0; i--) // Scan wad files backwards so patched lumps take precedent
+		{
+			lumpnum_t start = LUMPERROR;
+			lumpnum_t end = LUMPERROR;
+
+			switch (wadfiles[i]->type)
+			{
+				case RET_WAD:
+					if (lump_type_it == USE_PATCHES)
+					{
+						if ((start = W_CheckNumForMarkerStartPwad("P_START", (UINT16)i, 0)) == INT16_MAX)
+							continue;
+						else if ((end = W_CheckNumForNamePwad("P_END", (UINT16)i, start)) == INT16_MAX)
+							continue;
+					}
+					else if (lump_type_it == USE_TEXTURES)
+					{
+						if ((start = W_CheckNumForMarkerStartPwad("TX_START", (UINT16)i, 0)) == INT16_MAX)
+							continue;
+						else if ((end = W_CheckNumForNamePwad("TX_END", (UINT16)i, start)) == INT16_MAX)
+							continue;
+					}
+					break;
+				case RET_PK3:
+				case RET_FOLDER:
+					if (lump_type_it == USE_PATCHES)
+					{
+						if ((start = W_CheckNumForFolderStartPK3("Patches/", i, 0)) == INT16_MAX)
+							continue;
+						if ((end = W_CheckNumForFolderEndPK3("Patches/", i, start)) == INT16_MAX)
+							continue;
+					}
+					else if (lump_type_it == USE_TEXTURES)
+					{
+						if ((start = W_CheckNumForFolderStartPK3("Textures/", i, 0)) == INT16_MAX)
+							continue;
+						if ((end = W_CheckNumForFolderEndPK3("Textures/", i, start)) == INT16_MAX)
+							continue;
+					}
+					break;
+				default:
+					continue;
+			}
+
+			// Now find lump with specified name in that range.
+			lump = W_CheckNumForNamePwad(name, (UINT16)i, start);
+			if (lump < end)
+			{
+				lump += (i<<16); // found it, in our constraints
+				break;
+			}
+			lump = LUMPERROR;
+		}
+
+		if (lump != LUMPERROR)
+		{
+			break;
+		}
+	}
+
+	if (lump == LUMPERROR)
+	{
+		// Use whatever else you can find.
+		return W_GetNumForName(name);
+	}
+
+	return lump;
+}
+
 static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
 {
 	char *texturesToken;
@@ -1240,13 +1332,13 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
 	if (actuallyLoadPatch == true)
 	{
 		// Check lump exists
-		patchLumpNum = W_GetNumForName(patchName);
+		patchLumpNum = W_GetTexPatchLumpNum(patchName);
 		// If so, allocate memory for texpatch_t and fill 'er up
 		resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL);
 		resultPatch->originx = patchXPos;
 		resultPatch->originy = patchYPos;
-		resultPatch->lump = patchLumpNum & 65535;
-		resultPatch->wad = patchLumpNum>>16;
+		resultPatch->lump = LUMPNUM(patchLumpNum);
+		resultPatch->wad = WADFILENUM(patchLumpNum);
 		resultPatch->flip = flip;
 		resultPatch->alpha = alpha;
 		resultPatch->style = style;
diff --git a/src/r_things.c b/src/r_things.c
index d6ef72b9d29980134757df4547ffd03837379957..c46d8162460e6ac4df025457910f1eae92634628 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -77,7 +77,7 @@ spriteinfo_t spriteinfo[NUMSPRITES];
 spritedef_t *sprites;
 size_t numsprites;
 
-static spriteframe_t sprtemp[64];
+static spriteframe_t sprtemp[MAXFRAMENUM];
 static size_t maxframe;
 static const char *spritename;
 
@@ -116,6 +116,14 @@ static INT32 drawsegs_xrange_count = 0;
 //
 // ==========================================================================
 
+spritenum_t R_GetSpriteNumByName(const char *name)
+{
+	for (spritenum_t i = 0; i < NUMSPRITES; i++)
+		if (!strcmp(name, sprnames[i]))
+			return i;
+	return NUMSPRITES;
+}
+
 //
 //
 //
@@ -128,10 +136,14 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 {
 	char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
 
+	char framedescription[256];
+	if (cn != '\xFF')
+		sprintf(framedescription, "%s frame %d (%c)", spritename, frame, cn);
+	else
+		sprintf(framedescription, "%s frame %d", spritename, frame);
+
 	INT32 r;
-	lumpnum_t lumppat = wad;
-	lumppat <<= 16;
-	lumppat += lump;
+	lumpnum_t lumppat = (wad << 16) + lump;
 
 	if (maxframe ==(size_t)-1 || frame > maxframe)
 		maxframe = frame;
@@ -147,9 +159,9 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 	{
 		// the lump should be used for all rotations
 		if (sprtemp[frame].rotate == SRF_SINGLE)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple rot = 0 lump\n", framedescription);
 		else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message.
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has rotations and a rot = 0 lump\n", framedescription);
 
 		sprtemp[frame].rotate = SRF_SINGLE;
 		for (r = 0; r < 16; r++)
@@ -169,15 +181,15 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 		if (sprtemp[frame].rotate == SRF_NONE)
 			sprtemp[frame].rotate = SRF_SINGLE;
 		else if (sprtemp[frame].rotate == SRF_SINGLE)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has L/R rotations and a rot = 0 lump\n", framedescription);
 		else if (sprtemp[frame].rotate == SRF_3D)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8 rotations\n", framedescription);
 		else if (sprtemp[frame].rotate == SRF_3DGE)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-G rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-G rotations\n", framedescription);
 		else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L))
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple L rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple L rotations\n", framedescription);
 		else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R))
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple R rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple R rotations\n", framedescription);
 
 		sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
 		if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
@@ -204,9 +216,9 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 	if (sprtemp[frame].rotate == SRF_NONE)
 		sprtemp[frame].rotate = SRF_SINGLE;
 	else if (sprtemp[frame].rotate == SRF_SINGLE)
-		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8/G rotations and a rot = 0 lump\n", spritename, cn);
+		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has 1-8/G rotations and a rot = 0 lump\n", framedescription);
 	else if (sprtemp[frame].rotate & SRF_2D)
-		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8/G rotations\n", spritename, cn);
+		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8/G rotations\n", framedescription);
 
 	// make 0 based
 	rotation--;
@@ -226,7 +238,12 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 	}
 
 	if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
-		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, cr);
+	{
+		if (cn != '\xFF')
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c (%c%c) has two lumps mapped to it\n", spritename, frame, cr, cn, cr);
+		else
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c has two lumps mapped to it\n", spritename, frame, cr);
+	}
 
 	// lumppat & lumpid are the same for original Doom, but different
 	// when using sprites in pwad : the lumppat points the new graphics
@@ -238,24 +255,201 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 		sprtemp[frame].flip &= ~(1<<rotation);
 }
 
+static boolean GetFramesAndRotationsFromShortLumpName(
+	const char *name,
+	INT32 *ret_frame,
+	UINT8 *ret_rotation,
+	INT32 *ret_frame2,
+	UINT8 *ret_rotation2
+)
+{
+	size_t namelen = strlen(name);
+
+	if (namelen != 6 && namelen != 8)
+		return false;
+
+	*ret_frame = R_Char2Frame(name[4]);
+	*ret_rotation = R_Char2Rotation(name[5]);
+	if (*ret_frame >= 64 || *ret_rotation == 255)
+		return false;
+
+	if (namelen == 8)
+	{
+		*ret_frame2 = R_Char2Frame(name[6]);
+		*ret_rotation2 = R_Char2Rotation(name[7]);
+		if (*ret_frame2 >= 64 || *ret_rotation2 == 255)
+			return false;
+	}
+	else
+	{
+		*ret_frame2 = -1;
+		*ret_rotation2 = 255;
+	}
+
+	return true;
+}
+
+static boolean GetSingleFrameAndRotation(
+	const char *name,
+	size_t len,
+	INT32 *ret_frame,
+	UINT8 *ret_rotation
+)
+{
+	const char *underscore = strchr(name, '_');
+
+	// Found but past the part of the name we are parsing
+	if ((size_t)(underscore - name) >= len)
+		underscore = NULL;
+
+	size_t framelen = underscore ? (size_t)(underscore - name) : len;
+	if (framelen < 1 || framelen > 4)
+		return false;
+
+	char framepart[4 + 1]; // Max 9999
+	strlcpy(framepart, name, framelen + 1);
+
+	for (size_t i = 0; i < framelen; i++)
+		if (!isdigit(framepart[i]))
+			return false;
+
+	*ret_frame = atoi(framepart);
+	*ret_rotation = underscore ? R_Char2Rotation(*(underscore + 1)) : 0;
+	if (*ret_frame >= MAXFRAMENUM || *ret_rotation == 255)
+		return false;
+
+	return true;
+}
+
+static boolean GetFramesAndRotationsFromLongLumpName(
+	const char *name,
+	INT32 *ret_frame,
+	UINT8 *ret_rotation,
+	INT32 *ret_frame2,
+	UINT8 *ret_rotation2
+)
+{
+	const char *plus = strchr(name, '+');
+
+	if (plus)
+	{
+		size_t len1 = plus - name;
+
+		if (!GetSingleFrameAndRotation(name, len1, ret_frame, ret_rotation))
+			return false;
+		if (!GetSingleFrameAndRotation(plus + 1, strlen(name) - len1 - 1, ret_frame2, ret_rotation2))
+			return false;
+	}
+	else
+	{
+		if (!GetSingleFrameAndRotation(name, strlen(name), ret_frame, ret_rotation))
+			return false;
+
+		*ret_frame2 = -1;
+		*ret_rotation2 = 255;
+	}
+
+	return true;
+}
+
+static UINT8 GetOppositeRotation(UINT8 rotation, UINT8 flags)
+{
+	if (flags & ~SRF_3DMASK)
+		I_Error("GetOppositeRotation: rotation type not supported");
+
+	UINT8 numrotations = (flags == SRF_3D) ? 8 : 16;
+	return (rotation == 1) ? 1 : numrotations + 2 - rotation;
+}
+
+static void MirrorMissingRotations(void)
+{
+	for (UINT32 framenum = 0; framenum < maxframe; framenum++)
+	{
+		spriteframe_t *frame = &sprtemp[framenum];
+
+		if (frame->rotate == SRF_NONE || !(frame->rotate & SRF_3DMASK))
+			continue;
+
+		UINT8 numrotations = frame->rotate == SRF_3D ? 8 : 16;
+
+		for (UINT8 rotation = 1; rotation <= numrotations; rotation++)
+		{
+			if (frame->lumppat[rotation - 1] != LUMPERROR)
+				continue;
+
+			UINT8 baserotation = GetOppositeRotation(rotation, frame->rotate);
+			UINT32 lumpnum = frame->lumppat[baserotation - 1];
+			R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), frame->lumpid[baserotation], framenum, rotation, 1);
+		}
+	}
+}
+
+// Some checks to help development
+static void CheckFrame(const char *sprname)
+{
+	for (UINT32 frame = 0; frame < maxframe; frame++)
+	{
+		spriteframe_t *spriteframe = &sprtemp[frame];
+
+		char framedescription[256];
+		if (frame < 64)
+			sprintf(framedescription, "%s frame %d (%c)", sprname, frame, R_Frame2Char(frame));
+		else
+			sprintf(framedescription, "%s frame %d", sprname, frame);
+
+		switch (spriteframe->rotate)
+		{
+		case SRF_NONE:
+			// no rotations were found for that frame at all
+			I_Error("R_AddSingleSpriteDef: No patches found for %s", framedescription);
+			break;
+
+		case SRF_SINGLE:
+			// only the first rotation is needed
+			break;
+
+		case SRF_2D: // both Left and Right rotations
+			// we test to see whether the left and right slots are present
+			if ((spriteframe->lumppat[2] == LUMPERROR) || (spriteframe->lumppat[6] == LUMPERROR))
+				I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (L-R mode)",
+				framedescription);
+			break;
+
+		default:
+			{
+				// must have all 8/16 frames
+				UINT8 rotation = ((spriteframe->rotate & SRF_3DGE) ? 16 : 8);
+				while (rotation--)
+				{
+					// we test the patch lump, or the id lump whatever
+					// if it was not loaded the two are LUMPERROR
+					if (spriteframe->lumppat[rotation] == LUMPERROR)
+						I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (1-%c mode)",
+								framedescription, ((spriteframe->rotate & SRF_3DGE) ? 'G' : '8'));
+				}
+			}
+			break;
+		}
+	}
+}
+
 // Install a single sprite, given its identifying name (4 chars)
 //
 // (originally part of R_AddSpriteDefs)
 //
-// Pass: name of sprite : 4 chars
+// Pass: name of sprite
 //       spritedef_t
 //       wadnum         : wad number, indexes wadfiles[], where patches
 //                        for frames are found
 //       startlump      : first lump to search for sprite frames
 //       endlump        : AFTER the last lump to search
+//       longname       : whether to use long sprite names or 4-char names
 //
 // Returns true if the sprite was succesfully added
 //
-boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump)
+boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname)
 {
 	UINT16 l;
-	UINT8 frame;
-	UINT8 rotation;
 	lumpinfo_t *lumpinfo;
 	UINT16 numadded = 0;
 
@@ -282,15 +476,23 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 
 	for (l = startlump; l < endlump; l++)
 	{
-		if (memcmp(lumpinfo[l].name,sprname,4)==0)
+		if (longname && W_IsLumpFolder(wadnum, l))
+			I_Error("R_AddSingleSpriteDef: all frame lumps for a sprite should be contained inside a single folder\n");
+
+		// For long sprites, the startlump-endlump range only includes
+		// relevant lumps, so no check needed in that case
+		if (longname || (strlen(sprname) == 4 && !memcmp(lumpinfo[l].name, sprname, 4)))
 		{
 			INT16 width, height;
 			INT16 topoffset, leftoffset;
+			INT32 frame, frame2;
+			UINT8 rotation, rotation2;
 
-			frame = R_Char2Frame(lumpinfo[l].name[4]);
-			rotation = R_Char2Rotation(lumpinfo[l].name[5]);
+			boolean good = longname ?
+				GetFramesAndRotationsFromLongLumpName(lumpinfo[l].longname, &frame, &rotation, &frame2, &rotation2) :
+				GetFramesAndRotationsFromShortLumpName(lumpinfo[l].name, &frame, &rotation, &frame2, &rotation2);
 
-			if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
+			if (!good) // Give an actual NAME error -_-...
 			{
 				CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
 				continue;
@@ -322,19 +524,8 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 			//----------------------------------------------------
 
 			R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0);
-
-			if (lumpinfo[l].name[6])
-			{
-				frame = R_Char2Frame(lumpinfo[l].name[6]);
-				rotation = R_Char2Rotation(lumpinfo[l].name[7]);
-
-				if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
-				{
-					CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
-					continue;
-				}
-				R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
-			}
+			if (frame2 != -1)
+				R_InstallSpriteLump(wadnum, l, numspritelumps, frame2, rotation2, 1);
 
 			if (++numspritelumps >= max_spritelumps)
 			{
@@ -374,41 +565,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 
 	maxframe++;
 
-	//
-	//  some checks to help development
-	//
-	for (frame = 0; frame < maxframe; frame++)
-	{
-		switch (sprtemp[frame].rotate)
-		{
-			case SRF_NONE:
-			// no rotations were found for that frame at all
-			I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
-			break;
-
-			case SRF_SINGLE:
-			// only the first rotation is needed
-			break;
-
-			case SRF_2D: // both Left and Right rotations
-			// we test to see whether the left and right slots are present
-			if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
-				I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (L-R mode)",
-				sprname, R_Frame2Char(frame));
-			break;
+	if (longname)
+		MirrorMissingRotations();
 
-			default:
-			// must have all 8/16 frames
-				rotation = ((sprtemp[frame].rotate & SRF_3DGE) ? 16 : 8);
-				while (rotation--)
-				// we test the patch lump, or the id lump whatever
-				// if it was not loaded the two are LUMPERROR
-				if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
-					I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (1-%c mode)",
-					        sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
-			break;
-		}
-	}
+	CheckFrame(sprname);
 
 	// allocate space for the frames present and copy sprtemp to it
 	if (spritedef->numframes &&             // has been allocated
@@ -429,14 +589,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 	return true;
 }
 
-//
-// Search for sprites replacements in a wad whose names are in namelist
-//
-void R_AddSpriteDefs(UINT16 wadnum)
+static void AddShortSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
 {
-	size_t i, addsprites = 0;
+	size_t i;
 	UINT16 start, end;
-	char wadname[MAX_WADPATH];
 
 	// Find the sprites section in this resource file.
 	switch (wadfiles[wadnum]->type)
@@ -474,27 +630,90 @@ void R_AddSpriteDefs(UINT16 wadnum)
 		return;
 	}
 
-
 	//
 	// scan through lumps, for each sprite, find all the sprite frames
 	//
 	for (i = 0; i < numsprites; i++)
 	{
-		if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4])
-			continue;
-
-		if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
+		if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end, false))
 		{
 			// if a new sprite was added (not just replaced)
-			addsprites++;
+			(*ptr_spritesadded)++;
 #ifndef ZDEBUG
 			CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum);
 #endif
 		}
 	}
 
-	nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
-	CONS_Printf(M_GetText("%s added %d frames in %s sprites\n"), wadname, end-start, sizeu1(addsprites));
+	*ptr_framesadded += end - start;
+}
+
+static void AddLongSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
+{
+	if (!W_FileHasFolders(wadfiles[wadnum]))
+		return;
+
+	UINT16 start = W_CheckNumForFolderStartPK3("LongSprites/", wadnum, 0);
+	UINT16 end = W_CheckNumForFolderEndPK3("LongSprites/", wadnum, start);
+
+	if (start == INT16_MAX || end == INT16_MAX || start >= end)
+		return;
+
+	size_t lumpnum = start;
+
+	while (lumpnum < end)
+	{
+		if (W_IsLumpFolder(wadnum, lumpnum))
+		{
+			lumpnum++;
+			continue;
+		}
+
+		UINT16 folderstart, folderend;
+		char *folderpath = W_GetLumpFolderPathPK3(wadnum, lumpnum);
+		folderstart = lumpnum;
+		folderend = W_CheckNumForFolderEndPK3(folderpath, wadnum, lumpnum);
+		Z_Free(folderpath);
+
+		spritenum_t sprnum;
+		char *sprname = W_GetLumpFolderNamePK3(wadnum, lumpnum);
+		strupr(sprname);
+		sprnum = R_GetSpriteNumByName(sprname);
+
+		if (sprnum != NUMSPRITES && R_AddSingleSpriteDef(sprname, &sprites[sprnum], wadnum, folderstart, folderend, true))
+		{
+			// A new sprite was added (not just replaced)
+			(*ptr_spritesadded)++;
+#ifndef ZDEBUG
+			CONS_Debug(DBG_SETUP, "long sprite %s set in pwad %d\n", sprname, wadnum);
+#endif
+		}
+
+		Z_Free(sprname);
+
+		lumpnum = folderend;
+	}
+
+	*ptr_framesadded += end - start;
+}
+
+//
+// Search for sprites replacements in a wad whose names are in namelist
+//
+void R_AddSpriteDefs(UINT16 wadnum)
+{
+	char wadname[MAX_WADPATH];
+	size_t spritesadded = 0;
+	size_t framesadded = 0;
+
+	AddShortSpriteDefs(wadnum, &spritesadded, &framesadded);
+	AddLongSpriteDefs(wadnum, &spritesadded, &framesadded);
+
+	if (spritesadded || framesadded)
+	{
+		nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
+		CONS_Printf(M_GetText("%s added %s frames in %s sprites\n"), wadname, sizeu1(framesadded), sizeu2(spritesadded));
+	}
 }
 
 //
@@ -658,12 +877,31 @@ void R_DrawMaskedColumn(column_t *column, unsigned lengthcol)
 static UINT8 *flippedcol = NULL;
 static size_t flippedcolsize = 0;
 
+void R_DrawFlippedPost(UINT8 *source, unsigned length, void (*drawcolfunc)(void))
+{
+	if (!length)
+		return;
+
+	if (!flippedcolsize || length > flippedcolsize)
+	{
+		flippedcolsize = length;
+		flippedcol = Z_Realloc(flippedcol, length, PU_STATIC, NULL);
+	}
+
+	dc_source = flippedcol;
+
+	for (UINT8 *s = (UINT8 *)source, *d = flippedcol+length-1; d >= flippedcol; s++)
+		*d-- = *s;
+
+	drawcolfunc();
+}
+
 void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol)
 {
 	INT32 topscreen;
 	INT32 bottomscreen;
 	fixed_t basetexturemid = dc_texturemid;
-	UINT8 *d,*s;
+	INT32 topdelta;
 
 	for (unsigned i = 0; i < column->num_posts; i++)
 	{
@@ -671,7 +909,7 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol)
 		if (!post->length)
 			continue;
 
-		INT32 topdelta = lengthcol-post->length-post->topdelta;
+		topdelta = lengthcol-post->length-post->topdelta;
 		topscreen = sprtopscreen + spryscale*topdelta;
 		bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*post->length
 		                                      : sprbotscreen + spryscale*post->length;
@@ -698,18 +936,9 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol)
 
 		if (dc_yl <= dc_yh && dc_yh > 0)
 		{
-			if (post->length > flippedcolsize)
-			{
-				flippedcolsize = post->length;
-				flippedcol = Z_Realloc(flippedcol, flippedcolsize, PU_STATIC, NULL);
-			}
-
-			for (s = column->pixels+post->data_offset+post->length, d = flippedcol; d < flippedcol+post->length; --s)
-				*d++ = *s;
-			dc_source = flippedcol;
 			dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
 
-			colfunc();
+			R_DrawFlippedPost(column->pixels + post->data_offset, post->length, colfunc);
 		}
 	}
 
@@ -941,7 +1170,6 @@ static void R_DrawVisSprite(vissprite_t *vis)
 	}
 
 	colfunc = colfuncs[BASEDRAWFUNC];
-	dc_hires = 0;
 
 	vis->x1 = x1;
 	vis->x2 = x2;
@@ -1528,6 +1756,9 @@ static void R_ProjectSprite(mobj_t *thing)
 	// uncapped/interpolation
 	interpmobjstate_t interp = {0};
 
+	if (!r_renderthings)
+		return;
+
 	// do interpolation
 	if (R_UsingFrameInterpolation() && !paused)
 	{
@@ -1567,20 +1798,22 @@ static void R_ProjectSprite(mobj_t *thing)
 	// decide which patch to use for sprite relative to player
 #ifdef RANGECHECK
 	if ((size_t)(thing->sprite) >= numsprites)
-		I_Error("R_ProjectSprite: invalid sprite number %d ", thing->sprite);
+		I_Error("R_ProjectSprite: invalid sprite number %d", thing->sprite);
 #endif
 
-	frame = thing->frame&FF_FRAMEMASK;
+	frame = thing->frame & FF_FRAMEMASK;
 
 	//Fab : 02-08-98: 'skin' override spritedef currently used for skin
 	if (thing->skin && thing->sprite == SPR_PLAY)
 	{
-		sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
+		sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
 #ifdef ROTSPRITE
-		sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
+		sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
 #endif
-		if (frame >= sprdef->numframes) {
-			CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(frame));
+
+		if (frame >= sprdef->numframes)
+		{
+			CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[SPR2_%s] %sframe %s\n"), ((skin_t *)thing->skin)->name, spr2names[thing->sprite2 & SPR2F_MASK], (thing->sprite2 & SPR2F_SUPER) ? "super ": "", sizeu5(frame));
 			thing->sprite = states[S_UNKNOWN].sprite;
 			thing->frame = states[S_UNKNOWN].frame;
 			sprdef = &sprites[thing->sprite];
@@ -2682,7 +2915,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
 	// Add the 3D floors, thicksides, and masked textures...
 	for (ds = drawsegs + mask->drawsegs[1]; ds-- > drawsegs + mask->drawsegs[0];)
 	{
-		if (ds->numthicksides)
+		if (ds->numthicksides && r_renderwalls)
 		{
 			for (i = 0; i < ds->numthicksides; i++)
 			{
@@ -2701,17 +2934,19 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
 			else {
 				// Put it in!
 				entry = R_CreateDrawNode(head);
-				entry->plane = plane;
-				entry->seg = ds;
+				if (r_renderwalls)
+					entry->seg = ds;
+				if (r_renderfloors)
+					entry->plane = plane;
 			}
 			ds->curline->polyseg->visplane = NULL;
 		}
-		if (ds->maskedtexturecol)
+		if (ds->maskedtexturecol && r_renderwalls)
 		{
 			entry = R_CreateDrawNode(head);
 			entry->seg = ds;
 		}
-		if (ds->numffloorplanes)
+		if (ds->numffloorplanes && r_renderfloors)
 		{
 			for (i = 0; i < ds->numffloorplanes; i++)
 			{
@@ -3011,9 +3246,6 @@ void R_InitDrawNodes(void)
 //
 // R_DrawSprite
 //
-//Fab : 26-04-98:
-// NOTE : uses con_clipviewtop, so that when console is on,
-//        don't draw the part of sprites hidden under the console
 static void R_DrawSprite(vissprite_t *spr)
 {
 	mfloorclip = spr->clipbot;
@@ -3181,9 +3413,6 @@ static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* port
 				(lowscale < spr->sortscale &&
 				 !R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
 			{
-				// masked mid texture?
-				/*if (ds->maskedtexturecol)
-					R_RenderMaskedSegRange (ds, r1, r2);*/
 				// seg is behind sprite
 				continue;
 			}
diff --git a/src/r_things.h b/src/r_things.h
index 043b454b049cefa907c16f12c13751236db4b456..3daf55c4235bc753aeb5f1c897856e6d9303338c 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -27,7 +27,9 @@
 
 #define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
 
-boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump);
+spritenum_t R_GetSpriteNumByName(const char *name);
+
+boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname);
 
 //faB: find sprites in wadfile, replace existing, add new ones
 //     (only sprites from namelist are added or replaced)
@@ -48,6 +50,7 @@ extern fixed_t windowbottom;
 
 void R_DrawMaskedColumn(column_t *column, unsigned lengthcol);
 void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol);
+void R_DrawFlippedPost(UINT8 *source, unsigned length, void (*drawcolfunc)(void));
 
 // ----------------
 // SPRITE RENDERING
diff --git a/src/r_translation.c b/src/r_translation.c
index 3905458026df20945e566861fc6c7a087bcab244..a53b30e9f6fc6196b72df18b3f6063534bda3219 100644
--- a/src/r_translation.c
+++ b/src/r_translation.c
@@ -556,7 +556,7 @@ static boolean ParseDecimal(tokenizer_t *sc, double *out)
 	return M_StringToDecimal(tkn, out);
 }
 
-static struct PaletteRemapParseResult *ThrowError(const char *format, ...)
+FUNCPRINTF static struct PaletteRemapParseResult *ThrowError(const char *format, ...)
 {
 	const size_t err_size = 512 * sizeof(char);
 
@@ -792,7 +792,7 @@ static struct PaletteRemapParseResult *PaletteRemap_ParseTranslation(const char
 	return result;
 }
 
-static void PrintError(const char *name, const char *format, ...)
+FUNCDEBUG static void PrintError(const char *name, const char *format, ...)
 {
 	char error[256];
 
diff --git a/src/s_sound.c b/src/s_sound.c
index a579292ff3aa791176b389d686901799c47c89a1..32353a59c2d590dd8ea1f74b47399de0886684d0 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -1910,7 +1910,7 @@ static void S_AddMusicStackEntry(const char *mname, UINT16 mflags, boolean loopi
 	if (!music_stacks)
 	{
 		music_stacks = Z_Calloc(sizeof (*mst), PU_MUSIC, NULL);
-		strncpy(music_stacks->musname, (status == JT_MASTER ? mname : (S_CheckQueue() ? queue_name : mapmusname)), 7);
+		strncpy(music_stacks->musname, (status == JT_MASTER ? mname : (S_CheckQueue() ? queue_name : mapmusname)), sizeof(music_stacks->musname)-1);
 		music_stacks->musflags = (status == JT_MASTER ? mflags : (S_CheckQueue() ? queue_flags : mapmusflags));
 		music_stacks->looping = (status == JT_MASTER ? looping : (S_CheckQueue() ? queue_looping : true));
 		music_stacks->position = (status == JT_MASTER ? position : (S_CheckQueue() ? queue_position : S_GetMusicPosition()));
@@ -2033,7 +2033,7 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst)
 	if (result)
 	{
 		*entry = *result;
-		strncpy(entry->musname, result->musname, 7);
+		memcpy(entry->musname, result->musname, sizeof(entry->musname));
 	}
 
 	// no result, just grab mapmusname
@@ -2255,10 +2255,10 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
 	if (S_MusicDisabled())
 		return;
 
-	strncpy(newmusic, mmusic, 7);
+	strncpy(newmusic, mmusic, sizeof(newmusic)-1);
+	newmusic[6] = 0;
 	if (LUA_HookMusicChange(music_name, &hook_param))
 		return;
-	newmusic[6] = 0;
 
 	// No Music (empty string)
 	if (newmusic[0] == 0)
@@ -2494,11 +2494,11 @@ static void Command_Tunes_f(void)
 		track = (UINT16)atoi(COM_Argv(2))-1;
 
 	strncpy(mapmusname, tunearg, 7);
+	mapmusname[6] = 0;
 
 	if (argc > 4)
 		position = (UINT32)atoi(COM_Argv(4));
 
-	mapmusname[6] = 0;
 	mapmusflags = (track & MUSIC_TRACKMASK);
 	mapmusposition = position;
 
diff --git a/src/s_sound.h b/src/s_sound.h
index 288859c8d233dc9696118ef1d93655f98be514b9..d64778fc37db6fffdf8027ad7aa3cb4f338a6a33 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -238,7 +238,7 @@ UINT32 S_GetMusicPosition(void);
 
 typedef struct musicstack_s
 {
-	char musname[7];
+	char musname[7+1];
 	UINT16 musflags;
 	boolean looping;
 	UINT32 position;
diff --git a/src/screen.c b/src/screen.c
index 76f546402ef38e0a4882221945ff602de73aadf9..9a82a15618a4045d651d10aae38a8e963b6711a5 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -8,7 +8,7 @@
 // See the 'LICENSE' file for more details.
 //-----------------------------------------------------------------------------
 /// \file  screen.c
-/// \brief Handles multiple resolutions, 8bpp/16bpp(highcolor) modes
+/// \brief Handles multiple resolutions
 
 #include "doomdef.h"
 #include "doomstat.h"
@@ -44,6 +44,8 @@
 // SRB2Kart
 #include "r_fps.h" // R_GetFramerateCap
 
+#include "lua_hud.h" // LUA_HudEnabled
+
 // --------------------------------------------
 // assembly or c drawer routines for 8bpp/16bpp
 // --------------------------------------------
@@ -70,8 +72,6 @@ consvar_t cv_scr_width_w = CVAR_INIT ("scr_width_w", "640", CV_SAVE, CV_Unsigned
 consvar_t cv_scr_height_w = CVAR_INIT ("scr_height_w", "400", CV_SAVE, CV_Unsigned, NULL);
 consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL);
 
-consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL);
-
 CV_PossibleValue_t cv_renderer_t[] = {
 	{1, "Software"},
 #ifdef HWRENDER
@@ -91,19 +91,15 @@ consvar_t cv_fullscreen = CVAR_INIT ("fullscreen", "Yes", CV_SAVE|CV_CALL, CV_Ye
 // =========================================================================
 
 INT32 scr_bpp; // current video mode bytes per pixel
-UINT8 *scr_borderpatch; // flat used to fill the reduced view borders set at ST_Init()
 
 // =========================================================================
 
-//  Short and Tall sky drawer, for the current color mode
-void (*walldrawerfunc)(void);
-
 void SCR_SetDrawFuncs(void)
 {
 	//
-	//  setup the right draw routines for either 8bpp or 16bpp
+	//  setup the right draw routines
 	//
-	if (true)//vid.bpp == 1) //Always run in 8bpp. todo: remove all 16bpp code?
+	if (vid.bpp == 1) //Always run in 8bpp.
 	{
 		colfuncs[BASEDRAWFUNC] = R_DrawColumn_8;
 		spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8;
@@ -139,7 +135,6 @@ void SCR_SetDrawFuncs(void)
 		spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
 		spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8;
 
-		// Lactozilla: Non-powers-of-two
 		spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8;
@@ -153,26 +148,9 @@ void SCR_SetDrawFuncs(void)
 		spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_NPO2_8;
-
 	}
-/*	else if (vid.bpp > 1)
-	{
-		I_OutputMsg("using highcolor mode\n");
-		spanfunc = basespanfunc = R_DrawSpan_16;
-		transcolfunc = R_DrawTranslatedColumn_16;
-		transtransfunc = R_DrawTranslucentColumn_16; // No 16bit operation for this function
-
-		colfunc = basecolfunc = R_DrawColumn_16;
-		shadecolfunc = NULL; // detect error if used somewhere..
-		fuzzcolfunc = R_DrawTranslucentColumn_16;
-		walldrawerfunc = R_DrawWallColumn_16;
-	}*/
 	else
 		I_Error("unknown bytes per pixel mode %d\n", vid.bpp);
-/*
-	if (SCR_IsAspectCorrect(vid.width, vid.height))
-		CONS_Alert(CONS_WARNING, M_GetText("Resolution is not aspect-correct!\nUse a multiple of %dx%d\n"), BASEVIDWIDTH, BASEVIDHEIGHT);
-*/
 }
 
 void SCR_SetMode(void)
@@ -513,6 +491,7 @@ void SCR_ClosedCaptions(void)
 			basey -= 8;
 		else if ((modeattacking == ATTACKING_NIGHTS)
 		|| (!(maptol & TOL_NIGHTS)
+		&& LUA_HudEnabled(hud_powerups)
 		&& ((cv_powerupdisplay.value == 2) // "Always"
 		 || (cv_powerupdisplay.value == 1 && !camera.chase)))) // "First-person only"
 			basey -= 16;
diff --git a/src/screen.h b/src/screen.h
index 64d92b9d3ef99cf3c4e066ddc5cc9e57edd94afd..8b952e553a18c30f9cbdaf323bdbc01aa11f0fe4 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -8,7 +8,7 @@
 // See the 'LICENSE' file for more details.
 //-----------------------------------------------------------------------------
 /// \file  screen.h
-/// \brief Handles multiple resolutions, 8bpp/16bpp(highcolor) modes
+/// \brief Handles multiple resolutions
 
 #ifndef __SCREEN_H__
 #define __SCREEN_H__
@@ -61,7 +61,7 @@ typedef struct viddef_s
 	UINT8 *direct; // linear frame buffer, or vga base mem.
 	INT32 dup; // scale 1, 2, 3 value for menus & overlays
 	INT32/*fixed_t*/ fdup; // same as dup, but exact value when aspect ratio isn't 320/200
-	INT32 bpp; // BYTES per pixel: 1 = 256color, 2 = highcolor
+	INT32 bpp; // BYTES per pixel: 1 = 256color
 
 	INT32 baseratio; // Used to get the correct value for lighting walls
 
@@ -83,35 +83,6 @@ enum
 	VID_GL_LIBRARY_ERROR      = -1,
 };
 
-// internal additional info for vesa modes only
-typedef struct
-{
-	INT32 vesamode; // vesa mode number plus LINEAR_MODE bit
-	void *plinearmem; // linear address of start of frame buffer
-} vesa_extra_t;
-// a video modes from the video modes list,
-// note: video mode 0 is always standard VGA320x200.
-typedef struct vmode_s
-{
-	struct vmode_s *pnext;
-	char *name;
-	UINT32 width, height;
-	UINT32 rowbytes; // bytes per scanline
-	UINT32 bytesperpixel; // 1 for 256c, 2 for highcolor
-	INT32 windowed; // if true this is a windowed mode
-	INT32 numpages;
-	vesa_extra_t *pextradata; // vesa mode extra data
-#ifdef _WIN32
-	INT32 (WINAPI *setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode);
-#else
-	INT32 (*setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode);
-#endif
-	INT32 misc; // misc for display driver (r_opengl.dll etc)
-} vmode_t;
-
-#define NUMSPECIALMODES  4
-extern vmode_t specialmodes[NUMSPECIALMODES];
-
 // ---------------------------------------------
 // color mode dependent drawer function pointers
 // ---------------------------------------------
@@ -184,11 +155,9 @@ void SCR_ChangeRenderer(void);
 extern CV_PossibleValue_t cv_renderer_t[];
 
 extern INT32 scr_bpp;
-extern UINT8 *scr_borderpatch; // patch used to fill the view borders
 
 extern consvar_t cv_scr_width, cv_scr_height, cv_scr_width_w, cv_scr_height_w, cv_scr_depth, cv_fullscreen;
-extern consvar_t cv_renderview, cv_renderer;
-extern consvar_t cv_renderhitbox, cv_renderhitboxinterpolation, cv_renderhitboxgldepth;
+extern consvar_t cv_renderer;
 // wait for page flipping to end or not
 extern consvar_t cv_vidwait;
 extern consvar_t cv_timescale;
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index 5aca04d120c39287eec5c2097aa6375e52eb27fb..ee48fa2b154568889c50d4e0a6c8d97c5c2a7bf0 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -1,7 +1,6 @@
 # Declare SDL2 interface sources
 
 target_sources(SRB2SDL2 PRIVATE
-	mixer_sound.c
 	ogl_sdl.c
 	i_threads.c
 	i_net.c
@@ -13,6 +12,161 @@ target_sources(SRB2SDL2 PRIVATE
 	hwsym_sdl.c
 )
 
+# Compatibility flag with later versions of GCC
+# We should really fix our code to not need this
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+endif()
+
+# Yes we know we use insecure CRT functions...
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+    target_compile_definitions(SRB2SDL2 PRIVATE -D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# Compiler warnings configuration
+target_compile_options(SRB2SDL2 PRIVATE
+    # Using generator expressions to handle per-language compile options
+
+    # C, GNU
+    # This is a direct translation from versions.mk
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>:
+        -Wall
+        -Wno-trigraphs
+        -W # Was controlled by RELAXWARNINGS
+        -pedantic
+        -Wpedantic
+        -Wfloat-equal
+        -Wundef
+        -Wpointer-arith
+        -Wbad-function-cast
+        -Wcast-qual
+        -Wcast-align # Was controlled by NOCASTALIGNWARN
+        -Wwrite-strings
+        -Wsign-compare
+        -Wmissing-prototypes
+        -Wmissing-declarations
+        -Wmissing-noreturn
+        -Winline
+        -Wformat-y2k
+        -Wformat-security
+
+        $<$<VERSION_LESS:$<C_COMPILER_VERSION>,2.9.5>:
+            -Wno-div-by-zero
+            -Wendif-labels
+            -Wdisabled-optimization
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.0.0>:
+            -Wold-style-definition
+            -Wmissing-field-initializers
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.1.0>:
+            -Wshadow
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.3.0>:
+            -funit-at-a-time
+            -Wlogical-op
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.5.0>:
+            -Wlogical-op
+            -Wno-error=array-bounds
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.6.0>:
+            -Wno-suggest-attribute=noreturn
+            -Wno-error=suggest-attribute=noreturn
+            -Werror=vla
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,5.4.0>:
+            -Wno-logical-op
+            -Wno-error=logical-op
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,6.1.0>:
+            -Wno-tautological-compare
+            -Wno-error=tautological-compare
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,7.1.0>:
+            -Wno-error=format-overflow=2
+            -Wimplicit-fallthrough=4
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,8.1.0>:
+            -Wno-error=format-overflow
+            -Wno-error=stringop-truncation
+            -Wno-error=stringop-overflow
+            -Wno-format-overflow
+            -Wno-stringop-truncation
+            -Wno-stringop-overflow
+            -Wno-error=multistatement-macros
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,9.1.0>:
+            -Wno-error=address-of-packed-member
+        >
+    >
+
+    # C, Clang and Apple Clang
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
+        -Wall
+        -Wno-absolute-value
+        -Wno-trigraphs
+        -Wno-error=non-literal-null-conversion
+        -Wno-error=constant-conversion
+        -Wno-unused-but-set-variable
+        -Wno-error=unused-but-set-variable
+        -Wno-shorten-64-to-32
+    >
+
+    # C, MSVC
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:MSVC>>:
+        # All warnings at and before Visual Studio 2019 RTM
+        # https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-by-compiler-version?view=msvc-170
+        /Wv:19.20.27004.0
+    >
+
+    # C++, GNU, Clang and Apple Clang
+    $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<C_COMPILER_ID:GNU>,$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
+        -Wall
+        -Wno-unused-function
+        -Wno-unused-but-set-variable
+        -Wno-unused-private-field
+    >
+
+    # C++, MSVC
+    $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<C_COMPILER_ID:MSVC>>:
+        /Wv:19.20.27004.0
+    >
+
+    # GNU
+    $<$<C_COMPILER_ID:GNU>:
+        -fmax-errors=5
+    >
+)
+if(SRB2_CONFIG_ERRORMODE)
+    target_compile_options(SRB2SDL2 PRIVATE
+        $<$<OR:$<C_COMPILER_ID:GNU>,$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>:
+            -Werror
+        >
+
+        $<$<C_COMPILER_ID:MSVC>:
+            /WX
+        >
+    )
+endif()
+
+# Link warnings configuration
+target_link_options(SRB2SDL2 PRIVATE
+    $<$<C_COMPILER_ID:GNU>:
+        # -Wl,--as-needed   - Was controlled by NOLDWARNING
+    >
+)
+
 if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
 	target_sources(SRB2SDL2 PRIVATE
 		../win32/win_dbg.c
@@ -62,12 +216,6 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
 	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2main)
 endif()
 
-if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}")
-	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2-static SDL2_mixer::SDL2_mixer-static)
-else()
-	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2 SDL2_mixer::SDL2_mixer)
-endif()
-
 if("${CMAKE_SYSTEM_NAME}" MATCHES Linux)
 	target_link_libraries(SRB2SDL2 PRIVATE m rt)
 endif()
@@ -81,8 +229,84 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
 	)
 endif()
 
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+find_package(SDL2 CONFIG REQUIRED)
+find_package(SDL2 REQUIRED)
+if(TARGET SDL2main)
+	target_link_libraries(SRB2SDL2 PRIVATE SDL2main)
+endif()
 target_compile_definitions(SRB2SDL2 PRIVATE -DDIRECTFULLSCREEN -DHAVE_SDL)
+target_include_directories(SRB2SDL2 PRIVATE ${SDL2_INCLUDE_DIR})
+
+find_package(SDL2_mixer_ext CONFIG QUIET)
+find_package(SDL2_mixer_ext QUIET)
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static OR TARGET SDL2_mixer_ext OR TARGET SDL2_mixer_ext_Static)
+	if(NOT TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static AND TARGET SDL2_mixer_ext_Static)
+	add_library(SDL2_mixer_ext::SDL2_mixer_ext_Static ALIAS SDL2_mixer_ext_Static)
+	endif()
+	if(NOT TARGET SDL2_mixer_ext::SDL2_mixer_ext AND TARGET SDL2_mixer_ext)
+	add_library(SDL2_mixer_ext::SDL2_mixer_ext ALIAS SDL2_mixer_ext)
+	endif()
+	if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+		if(TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+			target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer_ext::SDL2_mixer_ext_Static)
+		else()
+			target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer_ext::SDL2_mixer_ext)
+		endif()
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DHAVE_MIXERX -DSOUND=SOUND_MIXER)
+	endif()
+endif()
+
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+	message(STATUS "SDL2_mixer_ext found, skipping SDL2_mixer")
+else()
+	message(STATUS "SDL2_mixer_ext not found, going to try SDL2_mixer")
+	find_package(SDL2_mixer CONFIG QUIET)
+	find_package(SDL2_mixer QUIET)
+	if(TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static OR TARGET SDL2_mixer OR TARGET SDL2_mixer_Static)
+		if(NOT TARGET SDL2_mixer::SDL2_mixer-static AND TARGET SDL2_mixer_Static)
+		add_library(SDL2_mixer::SDL2_mixer-static ALIAS SDL2_mixer_Static)
+		endif()
+		if(NOT TARGET SDL2_mixer::SDL2_mixer AND TARGET SDL2_mixer)
+		add_library(SDL2_mixer::SDL2_mixer ALIAS SDL2_mixer)
+		endif()
+		if(TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static)
+			if(TARGET SDL2_mixer::SDL2_mixer-static)
+				target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer::SDL2_mixer-static)
+			else()
+				target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer::SDL2_mixer)
+			endif()
+		target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+		endif()
+	endif()
+endif()
+
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static OR TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static)
+	target_sources(SRB2SDL2 PRIVATE mixer_sound.c)
+	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2)
+else()
+	target_sources(SRB2SDL2 PRIVATE sdl_sound.c)
+	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2)
+endif()
+
+if(TARGET SDL2::SDL2)
+	message(STATUS "SDL2 Found")
+else()
+	message(STATUS "no SDL2 Found")
+endif()
+
+if(TARGET SDL2::SDL2main)
+	message(STATUS "SDL2main Found")
+else()
+	message(STATUS "No SDL2main Found")
+endif()
+
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+	message(STATUS "SDL2_mixer_ext Found")
+elseif(TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static)
+	message(STATUS "SDL2_mixer found")
+else()
+	message(STATUS "no SDL2_mixer_ext or SDL2_mixer Found")
+endif()
 
 #### Installation ####
 if("${CMAKE_SYSTEM_NAME}" MATCHES Darwin)
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 5e30970286724f98e6a220ff658207be0119dd84..86ffa7082ac3210321a06c3b477ba3b6239947b9 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -191,7 +191,8 @@
     <ClCompile>
       <DisableSpecificWarnings>4244;4267;4146;4003</DisableSpecificWarnings>
       <PreprocessorDefinitions>HAVE_CURL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>..\libs\curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\libs\curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <TreatWarningAsError>false</TreatWarningAsError>
     </ClCompile>
     <CustomBuild>
       <Command />
@@ -204,7 +205,7 @@
     </CustomBuild>
     <Link>
       <AdditionalDependencies>libcurl.dll.a;libz32.a;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>..\libs\zlib\win32;..\libs\curl\lib32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\..\libs\zlib\win32;..\..\libs\curl\lib32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -573,9 +574,6 @@
     <ClCompile Include="..\r_bsp.c" />
     <ClCompile Include="..\r_data.c" />
     <ClCompile Include="..\r_draw.c" />
-    <ClCompile Include="..\r_draw16.c">
-      <ExcludedFromBuild>true</ExcludedFromBuild>
-    </ClCompile>
     <ClCompile Include="..\r_draw8.c">
       <ExcludedFromBuild>true</ExcludedFromBuild>
     </ClCompile>
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 35d47fad1fb38f008138348d77d6c242b7e71ccf..d2f9d018f2b3ef44e59def85634aa46ef24acd95 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -982,9 +982,6 @@
     <ClCompile Include="..\r_draw.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
-    <ClCompile Include="..\r_draw16.c">
-      <Filter>R_Rend</Filter>
-    </ClCompile>
     <ClCompile Include="..\r_draw8.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c
index f5fe9fb041b9f02057955afe072815e709b19dc3..b2177e563120fc76cf726353e5cad841e45b1762 100644
--- a/src/sdl/i_main.c
+++ b/src/sdl/i_main.c
@@ -186,6 +186,9 @@ int main(int argc, char **argv)
 #endif
 #endif
 
+	// disable text input right off the bat, since we don't need it at the start.
+	I_SetTextInputMode(false);
+
 #ifdef LOGMESSAGES
 	if (!M_CheckParm("-nolog"))
 		InitLogging();
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index f03ea6226516836612195a39022723e5df11e148..115b900f5b575ce376a816dc9093c38202724e86 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -41,12 +41,6 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #include <ntsecapi.h>
 #undef SystemFunction036
 
-// A little more than the minimum sleep duration on Windows.
-// May be incorrect for other platforms, but we don't currently have a way to
-// query the scheduler granularity. SDL will do what's needed to make this as
-// low as possible though.
-#define MIN_SLEEP_DURATION_MS 2.1
-
 #endif
 #include <stdio.h>
 #include <stdlib.h>
@@ -108,6 +102,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #endif
 #endif
 
+#if defined(UNIXCOMMON)
+#include <poll.h>
+#endif
+
 #if defined (__unix__) || (defined (UNIXCOMMON) && !defined (__APPLE__))
 #include <errno.h>
 #include <sys/wait.h>
@@ -221,6 +219,12 @@ static char returnWadPath[256];
 #include "../byteptr.h"
 #endif
 
+// A little more than the minimum sleep duration on Windows.
+// May be incorrect for other platforms, but we don't currently have a way to
+// query the scheduler granularity. SDL will do what's needed to make this as
+// low as possible though.
+#define MIN_SLEEP_DURATION_MS 2.1
+
 /**	\brief	The JoyReset function
 
 	\param	JoySet	Joystick info to reset
@@ -616,50 +620,60 @@ void I_GetConsoleEvents(void)
 	// we use this when sending back commands
 	event_t ev = {0};
 	char key = 0;
-	ssize_t d;
+	struct pollfd pfd =
+	{
+		.fd = STDIN_FILENO,
+		.events = POLLIN,
+		.revents = 0,
+	};
 
 	if (!consolevent)
 		return;
 
-	ev.type = ev_console;
-	ev.key = 0;
-	if (read(STDIN_FILENO, &key, 1) == -1 || !key)
-		return;
-
-	// we have something
-	// backspace?
-	// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
-	if ((key == tty_erase) || (key == 127) || (key == 8))
+	for (;;)
 	{
-		if (tty_con.cursor > 0)
+		if (poll(&pfd, 1, 0) < 1 || !(pfd.revents & POLLIN))
+			return;
+
+		ev.type = ev_console;
+		ev.key = 0;
+		if (read(STDIN_FILENO, &key, 1) == -1 || !key)
+			return;
+
+		// we have something
+		// backspace?
+		// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
+		if ((key == tty_erase) || (key == 127) || (key == 8))
 		{
-			tty_con.cursor--;
-			tty_con.buffer[tty_con.cursor] = '\0';
-			tty_Back();
+			if (tty_con.cursor > 0)
+			{
+				tty_con.cursor--;
+				tty_con.buffer[tty_con.cursor] = '\0';
+				tty_Back();
+			}
+			ev.key = KEY_BACKSPACE;
 		}
-		ev.key = KEY_BACKSPACE;
-	}
-	else if (key < ' ') // check if this is a control char
-	{
-		if (key == '\n')
+		else if (key < ' ') // check if this is a control char
 		{
-			tty_Clear();
-			tty_con.cursor = 0;
-			ev.key = KEY_ENTER;
+			if (key == '\n')
+			{
+				tty_Clear();
+				tty_con.cursor = 0;
+				ev.key = KEY_ENTER;
+			}
+			else continue;
 		}
-		else return;
-	}
-	else if (tty_con.cursor < sizeof (tty_con.buffer))
-	{
-		// push regular character
-		ev.key = tty_con.buffer[tty_con.cursor] = key;
-		tty_con.cursor++;
-		// print the current line (this is differential)
-		d = write(STDOUT_FILENO, &key, 1);
+		else if (tty_con.cursor < sizeof (tty_con.buffer))
+		{
+			// push regular character
+			ev.key = tty_con.buffer[tty_con.cursor] = key;
+			tty_con.cursor++;
+			// print the current line (this is differential)
+			write(STDOUT_FILENO, &key, 1);
+		}
+		if (ev.key) D_PostEvent(&ev);
+		//tty_FlushIn();
 	}
-	if (ev.key) D_PostEvent(&ev);
-	//tty_FlushIn();
-	(void)d;
 }
 
 #elif defined (_WIN32)
@@ -1700,7 +1714,7 @@ const char *I_GetJoyName(INT32 joyindex)
 	{
 		tempname = SDL_JoystickNameForIndex(joyindex);
 		if (tempname)
-			strncpy(joyname, tempname, 255);
+			strncpy(joyname, tempname, sizeof(joyname)-1);
 	}
 	return joyname;
 }
@@ -2291,7 +2305,7 @@ void I_SleepDuration(precise_t duration)
 	int status;
 	do status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts);
 	while (status == EINTR);
-#else
+#elif defined (MIN_SLEEP_DURATION_MS)
 	UINT64 precision = I_GetPrecisePrecision();
 	INT32 sleepvalue = cv_sleep.value;
 	UINT64 delaygranularity;
@@ -2843,7 +2857,7 @@ size_t I_GetRandomBytes(char *destination, size_t count)
 {
 #if defined (__unix__) || defined (UNIXCOMMON) || defined(__APPLE__)
 	FILE *rndsource;
-	size_t actual_bytes;
+	size_t actual_bytes = 0;
 
 	if (!(rndsource = fopen("/dev/urandom", "r")))
 		if (!(rndsource = fopen("/dev/random", "r")))
@@ -3261,4 +3275,18 @@ const char *I_GetSysName(void)
 	return SDL_GetPlatform();
 }
 
+
+void I_SetTextInputMode(boolean active)
+{
+	if (active)
+		SDL_StartTextInput();
+	else
+		SDL_StopTextInput();
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return SDL_IsTextInputActive();
+}
+
 #endif
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 1005af9d91b41fef8789b1c44cdff72dc3c9349d..76fe172fce0e27f46ceb491be5a43f1b3e72f770 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -100,8 +100,6 @@ static char vidModeName[33][32]; // allow 33 different modes
 rendermode_t rendermode = render_soft;
 rendermode_t chosenrendermode = render_none; // set by command line arguments
 
-boolean highcolor = false;
-
 static void VidWaitChanged(void);
 
 // synchronize page flipping with screen refresh
@@ -1403,103 +1401,12 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h)
 		}
 	}
 	return -1;
-#if 0
-	INT32 matchMode = -1, i;
-	VID_PrepareModeList();
-	if (USE_FULLSCREEN && numVidModes != -1)
-	{
-		for (i=firstEntry; i<numVidModes; i++)
-		{
-			if (modeList[i]->w == w &&
-			    modeList[i]->h == h)
-			{
-				matchMode = i;
-				break;
-			}
-		}
-		if (-1 == matchMode) // use smaller mode
-		{
-			w -= w%BASEVIDWIDTH;
-			h -= h%BASEVIDHEIGHT;
-			for (i=firstEntry; i<numVidModes; i++)
-			{
-				if (modeList[i]->w == w &&
-				    modeList[i]->h == h)
-				{
-					matchMode = i;
-					break;
-				}
-			}
-			if (-1 == matchMode) // use smallest mode
-				matchMode = numVidModes-1;
-		}
-		matchMode -= firstEntry;
-	}
-	else
-	{
-		for (i=0; i<MAXWINMODES; i++)
-		{
-			if (windowedModes[i][0] == w &&
-			    windowedModes[i][1] == h)
-			{
-				matchMode = i;
-				break;
-			}
-		}
-		if (-1 == matchMode) // use smaller mode
-		{
-			w -= w%BASEVIDWIDTH;
-			h -= h%BASEVIDHEIGHT;
-			for (i=0; i<MAXWINMODES; i++)
-			{
-				if (windowedModes[i][0] == w &&
-				    windowedModes[i][1] == h)
-				{
-					matchMode = i;
-					break;
-				}
-			}
-			if (-1 == matchMode) // use smallest mode
-				matchMode = MAXWINMODES-1;
-		}
-	}
-	return matchMode;
-#endif
 }
 
 void VID_PrepareModeList(void)
 {
 	// Under SDL2, we just use the windowed modes list, and scale in windowed fullscreen.
 	allow_fullscreen = true;
-#if 0
-	INT32 i;
-
-	firstEntry = 0;
-
-#ifdef HWRENDER
-	if (rendermode == render_opengl)
-		modeList = SDL_ListModes(NULL, SDL_OPENGL|SDL_FULLSCREEN);
-	else
-#endif
-	modeList = SDL_ListModes(NULL, surfaceFlagsF|SDL_HWSURFACE); //Alam: At least hardware surface
-
-	if (disable_fullscreen?0:cv_fullscreen.value) // only fullscreen needs preparation
-	{
-		if (-1 != numVidModes)
-		{
-			for (i=0; i<numVidModes; i++)
-			{
-				if (modeList[i]->w <= MAXVIDWIDTH &&
-					modeList[i]->h <= MAXVIDHEIGHT)
-				{
-					firstEntry = i;
-					break;
-				}
-			}
-		}
-	}
-	allow_fullscreen = true;
-#endif
 }
 
 static SDL_bool Impl_CreateContext(void)
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index a5be3a754ce5a44b5c985f5881300d06a5ad07c7..8f2ca340879d5236822c534b2f9da57774a5356e 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -140,15 +140,18 @@ static void Midiplayer_Onchange(void)
 			restart = true;
 	}
 
-	if (stricmp(Mix_GetSoundFonts(), cv_midisoundfontpath.string))
+	if (!Mix_GetSoundFonts() || stricmp(Mix_GetSoundFonts(), cv_midisoundfontpath.string))
 	{
 		if (!Mix_SetSoundFonts(cv_midisoundfontpath.string)) // == 0 means error
 			CONS_Alert(CONS_ERROR, "Sound font error: %s", Mix_GetError());
 		else
 			restart = true;
 	}
-
+#if SDL_MIXER_VERSION_ATLEAST(2,5,0)
+	Mix_SetTimidityCfg(cv_miditimiditypath.string);
+#else
 	Mix_Timidity_addToPathList(cv_miditimiditypath.string);
+#endif
 
 	if (restart)
 		S_StartEx(true);
@@ -159,7 +162,7 @@ static void MidiSoundfontPath_Onchange(void)
 	if (Mix_GetMidiPlayer() != MIDI_Fluidsynth || (I_SongType() != MU_NONE && I_SongType() != MU_MID_EX))
 		return;
 
-	if (stricmp(Mix_GetSoundFonts(), cv_midisoundfontpath.string))
+	if (!Mix_GetSoundFonts() || stricmp(Mix_GetSoundFonts(), cv_midisoundfontpath.string))
 	{
 		char *miditoken;
 		char *source = strdup(cv_midisoundfontpath.string);
@@ -286,8 +289,12 @@ void I_StartupSound(void)
 #ifdef HAVE_MIXERX
 	Mix_SetMidiPlayer(cv_midiplayer.value);
 	Mix_SetSoundFonts(cv_midisoundfontpath.string);
+#if SDL_MIXER_VERSION_ATLEAST(2,5,0)
+	Mix_SetTimidityCfg(cv_miditimiditypath.string);
+#else
 	Mix_Timidity_addToPathList(cv_miditimiditypath.string);
 #endif
+#endif
 #if SDL_MIXER_VERSION_ATLEAST(1,2,11)
 	Mix_Init(MIX_INIT_FLAC|MIX_INIT_MP3|MIX_INIT_OGG|MIX_INIT_MOD);
 #endif
@@ -942,7 +949,12 @@ UINT32 I_GetSongLength(void)
 	else
 	{
 #ifdef HAVE_MIXERX
+#if SDL_MIXER_VERSION_ATLEAST(2,5,0)
+		double xlength = Mix_MusicDuration(music);
+#else
 		double xlength = Mix_GetMusicTotalTime(music);
+#endif
+
 		if (xlength >= 0)
 			return (UINT32)(xlength*1000);
 #endif
@@ -1198,10 +1210,14 @@ boolean I_LoadSong(char *data, size_t len)
 #ifdef HAVE_MIXERX
 	if (Mix_GetMidiPlayer() != cv_midiplayer.value)
 		Mix_SetMidiPlayer(cv_midiplayer.value);
-	if (stricmp(Mix_GetSoundFonts(), cv_midisoundfontpath.string))
+	if (!Mix_GetSoundFonts() || stricmp(Mix_GetSoundFonts(), cv_midisoundfontpath.string))
 		Mix_SetSoundFonts(cv_midisoundfontpath.string);
+#if SDL_MIXER_VERSION_ATLEAST(2,5,0)
+	Mix_SetTimidityCfg(cv_miditimiditypath.string);
+#else
 	Mix_Timidity_addToPathList(cv_miditimiditypath.string); // this overwrites previous custom path
 #endif
+#endif
 
 #ifdef HAVE_OPENMPT
 	/*
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 3d730fb4f099145cb8a62c1e7544b5cf6d705978..7df6f8848dd80c2cb0eb5839fd0389b7c86a3b8b 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -139,6 +139,7 @@ static patch_t *fireflower;
 hudinfo_t hudinfo[NUMHUDITEMS] =
 {
 	{  16, 176, V_SNAPTOLEFT|V_SNAPTOBOTTOM}, // HUD_LIVES
+	{  16, 152, V_SNAPTOLEFT|V_SNAPTOBOTTOM}, // HUD_INPUT
 
 	{  16,  42, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_RINGS
 	{  96,  42, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_RINGSNUM
@@ -253,10 +254,6 @@ void ST_LoadGraphics(void)
 {
 	int i;
 
-	// SRB2 border patch
-	// st_borderpatchnum = W_GetNumForName("GFZFLR01");
-	// scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX);
-
 	// the original Doom uses 'STF' as base name for all face graphics
 	// Graue 04-08-2004: face/name graphics are now indexed by skins
 	//                   but load them in R_AddSkins, that gets called
@@ -374,9 +371,11 @@ void ST_LoadFaceGraphics(INT32 skinnum)
 		spritedef_t *sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
 		spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC];
 		faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
-		if (skins[skinnum]->sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC)
+
+		spritedef_t *super_sprdef = P_GetSkinSpritedef(skins[skinnum], SPR2_XTRA|SPR2F_SUPER);
+		if (super_sprdef->numframes > XTRA_LIFEPIC)
 		{
-			sprdef = &skins[skinnum]->sprites[SPR2_XTRA|FF_SPR2SUPER];
+			sprdef = super_sprdef;
 			sprframe = &sprdef->spriteframes[0];
 			superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
 		}
@@ -510,7 +509,7 @@ static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fix
 static void ST_drawDebugInfo(void)
 {
 	INT32 height = 0, h = 8, w = 18, lowh;
-	void (*textfunc)(INT32, INT32, INT32, const char *);
+	fixed_t textscale = FRACUNIT/2;
 
 	if (!(stplyr->mo && cv_debug))
 		return;
@@ -519,12 +518,12 @@ static void ST_drawDebugInfo(void)
 
 	if ((moviemode == MM_GIF && cv_gif_downscale.value) || vid.dup == 1)
 	{
-		textfunc = V_DrawRightAlignedString;
+		textscale = FRACUNIT;
 		lowh = ((vid.height/vid.dup) - 16);
 	}
 	else
 	{
-		textfunc = V_DrawRightAlignedSmallString;
+		textscale = FRACUNIT/2;
 		h /= 2;
 		w /= 2;
 		lowh = 0;
@@ -535,10 +534,10 @@ static void ST_drawDebugInfo(void)
 								V_DrawRightAlignedThinString(320,  8+lowh, VFLAGS|V_REDMAP, "SOME INFO NOT VISIBLE");\
 								return;\
 							}\
-							textfunc(320, height, VFLAGS, str);\
+							V_DrawAlignedFontString(320, height, VFLAGS, textscale, textscale, str, hu_font, alignright);\
 							height += h;
 
-#define V_DrawDebugFlag(f, str) textfunc(width, height, VFLAGS|f, str);\
+#define V_DrawDebugFlag(f, str) V_DrawAlignedFontString(width, height, VFLAGS|f, textscale, textscale, str, hu_font, alignright);\
 								width -= w
 
 	if (cv_debug & DBG_MEMORY)
@@ -818,7 +817,7 @@ static inline void ST_drawRings(void)
 
 static void ST_drawLivesArea(void)
 {
-	INT32 v_colmap = V_YELLOWMAP, livescount;
+	INT32 v_colmap = V_YELLOWMAP, livescount = -1;
 	boolean notgreyedout = false;
 
 	if (!stplyr->skincolor)
@@ -1041,32 +1040,36 @@ static void ST_drawInput(void)
 	INT32 col;
 	UINT8 offs;
 
-	INT32 x = hudinfo[HUD_LIVES].x, y = hudinfo[HUD_LIVES].y;
+	INT32 x = hudinfo[HUD_INPUT].x, y = hudinfo[HUD_INPUT].y;
 
 	if (stplyr->powers[pw_carry] == CR_NIGHTSMODE)
-		y -= 16;
+		y += 8;
+	else if (modeattacking || !LUA_HudEnabled(hud_lives))
+		y += 24;
+	else if (G_RingSlingerGametype() && LUA_HudEnabled(hud_powerstones))
+		y -= 5;
 
 	if (F_GetPromptHideHud(y))
 		return;
 
 	// O backing
-	V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20);
-	V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_LIVES].f|29);
+	V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_INPUT].f|20);
+	V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_INPUT].f|29);
 
 	if (cv_showinputjoy.value) // joystick render!
 	{
-		/*V_DrawFill(x   , y   , 16,  1, hudinfo[HUD_LIVES].f|16);
-		V_DrawFill(x   , y+15, 16,  1, hudinfo[HUD_LIVES].f|16);
-		V_DrawFill(x   , y+ 1,  1, 14, hudinfo[HUD_LIVES].f|16);
-		V_DrawFill(x+15, y+ 1,  1, 14, hudinfo[HUD_LIVES].f|16); -- red's outline*/
+		/*V_DrawFill(x   , y   , 16,  1, hudinfo[HUD_INPUT.f|16);
+		V_DrawFill(x   , y+15, 16,  1, hudinfo[HUD_INPUT].f|16);
+		V_DrawFill(x   , y+ 1,  1, 14, hudinfo[HUD_INPUT].f|16);
+		V_DrawFill(x+15, y+ 1,  1, 14, hudinfo[HUD_INPUT].f|16); -- red's outline*/
 		if (stplyr->cmd.sidemove || stplyr->cmd.forwardmove)
 		{
 			// joystick hole
-			V_DrawFill(x+5, y+4, 6, 6, hudinfo[HUD_LIVES].f|29);
+			V_DrawFill(x+5, y+4, 6, 6, hudinfo[HUD_INPUT].f|29);
 			// joystick top
 			V_DrawFill(x+3+stplyr->cmd.sidemove/12,
 				y+2-stplyr->cmd.forwardmove/12,
-				10, 10, hudinfo[HUD_LIVES].f|29);
+				10, 10, hudinfo[HUD_INPUT].f|29);
 			V_DrawFill(x+3+stplyr->cmd.sidemove/9,
 				y+1-stplyr->cmd.forwardmove/9,
 				10, 10, accent);
@@ -1074,10 +1077,10 @@ static void ST_drawInput(void)
 		else
 		{
 			// just a limited, greyed out joystick top
-			V_DrawFill(x+3, y+11, 10, 1, hudinfo[HUD_LIVES].f|29);
+			V_DrawFill(x+3, y+11, 10, 1, hudinfo[HUD_INPUT].f|29);
 			V_DrawFill(x+3,
 				y+1,
-				10, 10, hudinfo[HUD_LIVES].f|16);
+				10, 10, hudinfo[HUD_INPUT].f|16);
 		}
 	}
 	else // arrows!
@@ -1091,10 +1094,10 @@ static void ST_drawInput(void)
 		else
 		{
 			offs = 1;
-			col = hudinfo[HUD_LIVES].f|16;
-			V_DrawFill(x- 2, y+10,  6,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+ 4, y+ 9,  1,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+ 5, y+ 8,  1,  1, hudinfo[HUD_LIVES].f|29);
+			col = hudinfo[HUD_INPUT].f|16;
+			V_DrawFill(x- 2, y+10,  6,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+ 4, y+ 9,  1,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+ 5, y+ 8,  1,  1, hudinfo[HUD_INPUT].f|29);
 		}
 		V_DrawFill(x- 2, y+ 5-offs,  6,  6, col);
 		V_DrawFill(x+ 4, y+ 6-offs,  1,  4, col);
@@ -1109,12 +1112,12 @@ static void ST_drawInput(void)
 		else
 		{
 			offs = 1;
-			col = hudinfo[HUD_LIVES].f|16;
-			V_DrawFill(x+ 5, y+ 3,  1,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+ 6, y+ 4,  1,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+ 7, y+ 5,  2,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+ 9, y+ 4,  1,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+10, y+ 3,  1,  1, hudinfo[HUD_LIVES].f|29);
+			col = hudinfo[HUD_INPUT].f|16;
+			V_DrawFill(x+ 5, y+ 3,  1,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+ 6, y+ 4,  1,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+ 7, y+ 5,  2,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+ 9, y+ 4,  1,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+10, y+ 3,  1,  1, hudinfo[HUD_INPUT].f|29);
 		}
 		V_DrawFill(x+ 5, y- 2-offs,  6,  6, col);
 		V_DrawFill(x+ 6, y+ 4-offs,  4,  1, col);
@@ -1129,10 +1132,10 @@ static void ST_drawInput(void)
 		else
 		{
 			offs = 1;
-			col = hudinfo[HUD_LIVES].f|16;
-			V_DrawFill(x+12, y+10,  6,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+11, y+ 9,  1,  1, hudinfo[HUD_LIVES].f|29);
-			V_DrawFill(x+10, y+ 8,  1,  1, hudinfo[HUD_LIVES].f|29);
+			col = hudinfo[HUD_INPUT].f|16;
+			V_DrawFill(x+12, y+10,  6,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+11, y+ 9,  1,  1, hudinfo[HUD_INPUT].f|29);
+			V_DrawFill(x+10, y+ 8,  1,  1, hudinfo[HUD_INPUT].f|29);
 		}
 		V_DrawFill(x+12, y+ 5-offs,  6,  6, col);
 		V_DrawFill(x+11, y+ 6-offs,  1,  4, col);
@@ -1147,8 +1150,8 @@ static void ST_drawInput(void)
 		else
 		{
 			offs = 1;
-			col = hudinfo[HUD_LIVES].f|16;
-			V_DrawFill(x+ 5, y+17,  6,  1, hudinfo[HUD_LIVES].f|29);
+			col = hudinfo[HUD_INPUT].f|16;
+			V_DrawFill(x+ 5, y+17,  6,  1, hudinfo[HUD_INPUT].f|29);
 		}
 		V_DrawFill(x+ 5, y+12-offs,  6,  6, col);
 		V_DrawFill(x+ 6, y+11-offs,  4,  1, col);
@@ -1164,16 +1167,18 @@ static void ST_drawInput(void)
 	else\
 	{\
 		offs = 1;\
-		col = hudinfo[HUD_LIVES].f|16;\
-		V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, hudinfo[HUD_LIVES].f|29);\
+		col = hudinfo[HUD_INPUT].f|16;\
+		V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, hudinfo[HUD_INPUT].f|29);\
 	}\
 	V_DrawFill(x+16+(xoffs), y+(yoffs)-offs, 10, 10, col);\
-	V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, hudinfo[HUD_LIVES].f|symb, false)
+	V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, hudinfo[HUD_INPUT].f|symb, false)
 
-	drawbutt( 4,-3, BT_JUMP, 'J');
-	drawbutt(15,-3, BT_SPIN, 'S');
+	drawbutt( 4,-3, BT_JUMP,   'J' );
+	drawbutt(15,-3, BT_SPIN,   'S' );
+	drawbutt(26,-3, BT_SHIELD, '\0'); // Instead of a wide 'J' or 'S', we'll draw a thin "SH" for Shield
+	V_DrawThinString(x+16+26, y+2+(-3)-offs, hudinfo[HUD_LIVES].f, "SH");
 
-	V_DrawFill(x+16+4, y+8, 21, 10, hudinfo[HUD_LIVES].f|20); // sundial backing
+	V_DrawFill(x+16+4, y+8, 21, 10, hudinfo[HUD_INPUT].f|20); // sundial backing
 	if (stplyr->mo)
 	{
 		UINT8 i, precision;
@@ -1193,7 +1198,7 @@ static void ST_drawInput(void)
 		{
 			V_DrawFill(x+16+14-(i*xcomp)/precision,
 				y+12-(i*ycomp)/precision,
-				1, 1, hudinfo[HUD_LIVES].f|16);
+				1, 1, hudinfo[HUD_INPUT].f|16);
 		}
 
 		if (ycomp <= 0)
@@ -1210,7 +1215,7 @@ static void ST_drawInput(void)
 		if (stplyr->pflags & PF_AUTOBRAKE)
 		{
 			V_DrawThinString(x, y,
-				hudinfo[HUD_LIVES].f|
+				hudinfo[HUD_INPUT].f|
 				((!stplyr->powers[pw_carry]
 				&& (stplyr->pflags & PF_APPLYAUTOBRAKE)
 				&& !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove)
@@ -1223,22 +1228,22 @@ static void ST_drawInput(void)
 		switch (P_ControlStyle(stplyr))
 		{
 		case CS_LMAOGALOG:
-			V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "ANALOG");
+			V_DrawThinString(x, y, hudinfo[HUD_INPUT].f, "ANALOG");
 			y -= 8;
 			break;
 
 		case CS_SIMPLE:
-			V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "AUTOMATIC");
+			V_DrawThinString(x, y, hudinfo[HUD_INPUT].f, "AUTOMATIC");
 			y -= 8;
 			break;
 
 		case CS_STANDARD:
-			V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "MANUAL");
+			V_DrawThinString(x, y, hudinfo[HUD_INPUT].f, "MANUAL");
 			y -= 8;
 			break;
 
 		case CS_LEGACY:
-			V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "STRAFE");
+			V_DrawThinString(x, y, hudinfo[HUD_INPUT].f, "STRAFE");
 			y -= 8;
 			break;
 
@@ -1247,7 +1252,7 @@ static void ST_drawInput(void)
 		}
 	}
 	if (!demosynced) // should always be last, so it doesn't push anything else around
-		V_DrawThinString(x, y, hudinfo[HUD_LIVES].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!");
+		V_DrawThinString(x, y, hudinfo[HUD_INPUT].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!");
 }
 
 static patch_t *lt_patches[3];
@@ -1548,13 +1553,16 @@ static void ST_drawPowerupHUD(void)
 	{
 		shieldoffs[q] = ICONSEP;
 
-		if ((stplyr->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE)
+		if ((stplyr->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE
+		&& (stplyr->powers[pw_shield] & SH_FORCEHP) > 0) // Special handling for >1HP Force Shields
 		{
-			UINT8 i, max = (stplyr->powers[pw_shield] & SH_FORCEHP);
-			for (i = 0; i <= max; i++)
-			{
-				V_DrawSmallScaledPatch(offs-(i<<1), hudinfo[HUD_POWERUPS].y-(i<<1), (V_PERPLAYER|hudinfo[HUD_POWERUPS].f)|((i == max) ? V_HUDTRANS : V_HUDTRANSHALF), forceshield);
-			}
+			UINT8 max = (stplyr->powers[pw_shield] & SH_FORCEHP);
+
+			V_DrawSmallScaledPatch(offs,   hudinfo[HUD_POWERUPS].y,   V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANSHALF, forceshield);
+			V_DrawSmallScaledPatch(offs-2, hudinfo[HUD_POWERUPS].y-2, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS,     forceshield);
+
+			if (max > 1) // if the shield has more than 2 hits, show the extra n hits as "+n"
+				V_DrawRightAlignedThinString(offs+16, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, va("+%d", max - 1));
 		}
 		else
 		{
@@ -1564,6 +1572,7 @@ static void ST_drawPowerupHUD(void)
 				case SH_ELEMENTAL:   p = watershield;   break;
 				case SH_ARMAGEDDON:  p = bombshield;    break;
 				case SH_ATTRACT:     p = ringshield;    break;
+				case SH_FORCE:       p = forceshield;   break;
 				case SH_PITY:        p = pityshield;    break;
 				case SH_PINK:        p = pinkshield;    break;
 				case SH_FLAMEAURA:   p = flameshield;   break;
@@ -1746,22 +1755,23 @@ static void ST_drawNightsRecords(void)
 
 	switch (stplyr->textvar)
 	{
-		case 1: // A "Bonus Time Start" by any other name...
+		case NTV_BONUSTIMESTART: // A "Bonus Time Start" by any other name...
 		{
 			V_DrawCenteredString(BASEVIDWIDTH/2, 52, V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!"));
 			V_DrawCenteredString(BASEVIDWIDTH/2, 60,            aflag, M_GetText("SCORE MULTIPLIER START!"));
 
 			if (stplyr->finishedtime)
 			{
-				V_DrawString(BASEVIDWIDTH/2 - 48, 140, aflag, "TIME:");
-				V_DrawString(BASEVIDWIDTH/2 - 48, 148, aflag, "BONUS:");
-				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE));
-				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
+				tic_t maretime = stplyr->startedtime - stplyr->finishedtime;
+				V_DrawString(BASEVIDWIDTH/2 - 48, 140, V_YELLOWMAP|aflag, "TIME:");
+				V_DrawString(BASEVIDWIDTH/2 - 48, 148, V_YELLOWMAP|aflag, "BONUS:");
+				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, aflag, va("%i:%02i.%02i", G_TicsToMinutes(maretime,true), G_TicsToSeconds(maretime), G_TicsToCentiseconds(maretime)));
+				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
 			}
 			break;
 		}
-		case 2: // Get n Spheres
-		case 3: // Get n more Spheres
+		case NTV_GETSPHERES: // Get n Spheres
+		case NTV_GETMORESPHERES: // Get n more Spheres
 		{
 			if (!stplyr->capsule)
 				return;
@@ -1769,31 +1779,37 @@ static void ST_drawNightsRecords(void)
 			// Yes, this string is an abomination.
 			V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag,
 								 va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health,
-									(stplyr->textvar == 3) ? M_GetText("MORE ") : "",
+									(stplyr->textvar == NTV_GETMORESPHERES) ? M_GetText("MORE ") : "",
 									(G_IsSpecialStage(gamemap)) ? "SPHERE" : "CHIP",
 									(stplyr->capsule->health > 1) ? "S" : ""));
 			break;
 		}
-		case 4: // End Bonus
+		case NTV_BONUSTIMEEND: // End Bonus
 		{
-			V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
-			V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:");
-			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres));
-			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 148, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres * 50));
-			ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
+			V_DrawString(BASEVIDWIDTH/2 - 48, 132, V_YELLOWMAP|aflag, "TIME:");
+			V_DrawString(BASEVIDWIDTH/2 - 48, 140, V_YELLOWMAP|aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
+			V_DrawString(BASEVIDWIDTH/2 - 48, 148, V_YELLOWMAP|aflag, "BONUS:");
+			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 132, aflag, va("%i:%02i.%02i", G_TicsToMinutes(stplyr->lastmaretime,true), G_TicsToSeconds(stplyr->lastmaretime), G_TicsToCentiseconds(stplyr->lastmaretime)));
+			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, aflag, va("%d", stplyr->finishedspheres));
+			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, aflag, va("%d", stplyr->finishedspheres * 50));
+			ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 48)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
+
+			// If this is a multi-mare map, display the mare number.
+			if (stplyr->lastmare || P_FindLowestMare() < UINT8_MAX)
+				V_DrawLevelActNum(BASEVIDWIDTH/2 - 80, 128 + 3, aflag, stplyr->lastmare + 1);
 
 			// If new record, say so!
 			if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1, clientGamedata) <= stplyr->lastmarescore)
 			{
 				if (stplyr->texttimer & 16)
-					V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *");
+					V_DrawCenteredString(BASEVIDWIDTH/2, 184, aflag, "\x85* \x82NEW RECORD \x85*\x80");
 			}
 
 			if (P_HasGrades(gamemap, stplyr->lastmare + 1))
 			{
 				UINT8 grade = P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare);
-				if (modeattacking || grade >= GRADE_A)
-					V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag, ngradeletters[grade]);
+				if (modeattacking || !G_IsSpecialStage(gamemap) || grade >= GRADE_A)
+					V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 128, aflag, ngradeletters[grade]);
 			}
 			break;
 		}
@@ -1903,7 +1919,7 @@ static void ST_drawNiGHTSHUD(void)
 	// Link drawing
 	if (!oldspecialstage
 	// Don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
-	&& !(stplyr->texttimer && stplyr->textvar == 4)
+	&& !(stplyr->texttimer && stplyr->textvar == NTV_BONUSTIMEEND)
 	&& LUA_HudEnabled(hud_nightslink)
 	&& ((cv_debug & DBG_NIGHTSBASIC) || stplyr->linkcount > 1)) // When debugging, show "0 Link".
 	{
@@ -1945,12 +1961,12 @@ static void ST_drawNiGHTSHUD(void)
 		total_ringcount = stplyr->spheres;
 	}
 
-	if (stplyr->capsule)
+	if (!P_MobjWasRemoved(stplyr->capsule))
 	{
 		INT32 amount;
 		const INT32 length = 88;
 
-		origamount = stplyr->capsule->spawnpoint->angle;
+		origamount = stplyr->capsule->spawnpoint->args[1];
 		I_Assert(origamount > 0); // should not happen now
 
 		ST_DrawTopLeftOverlayPatch(72, 8, nbracket);
@@ -2820,14 +2836,14 @@ static void ST_overlayDrawer(void)
 		|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))
 		{
 			ST_drawFirstPersonHUD();
-			if (cv_powerupdisplay.value)
+			if (cv_powerupdisplay.value && LUA_HudEnabled(hud_powerups))
 				ST_drawPowerupHUD();  // same as it ever was...
 		}
-		else if (cv_powerupdisplay.value == 2)
+		else if (cv_powerupdisplay.value == 2 && LUA_HudEnabled(hud_powerups))
 			ST_drawPowerupHUD();  // same as it ever was...
 		
 	}
-	else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2)
+	else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2 && LUA_HudEnabled(hud_powerups))
 		ST_drawPowerupHUD(); // same as it ever was...
 
 	if (!(netgame || multiplayer) || !hu_showscores)
@@ -2848,7 +2864,7 @@ static void ST_overlayDrawer(void)
 	if (!hu_showscores && (netgame || multiplayer) && LUA_HudEnabled(hud_textspectator))
 		ST_drawTextHUD();
 
-	if (modeattacking && !(demoplayback && hu_showscores))
+	if ((cv_showinput.value && !players[displayplayer].spectator) || (modeattacking && !(demoplayback && hu_showscores)))
 		ST_drawInput();
 
 	ST_drawDebugInfo();
diff --git a/src/st_stuff.h b/src/st_stuff.h
index 07dfac3eccf6095218bf0f4b16726c41a6f94fd5..6f6bac1fa47fd5b4b71a850383138ad9821456ee 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -92,6 +92,7 @@ typedef struct
 typedef enum
 {
 	HUD_LIVES,
+	HUD_INPUT,
 
 	HUD_RINGS,
 	HUD_RINGSNUM,
diff --git a/src/string.c b/src/string.c
index 2f16fa4c68a35fa287156f546fc2973e9d4ad426..b24e12e6e36fec3078aaae76bee7a765f9c30c8f 100644
--- a/src/string.c
+++ b/src/string.c
@@ -68,3 +68,27 @@ int endswith(const char *base, const char *tag)
 
 	return !memcmp(&base[base_length - tag_length], tag, tag_length);
 }
+
+// strtok version that only skips over one delimiter at a time
+char *xstrtok(char *line, const char *delims)
+{
+	static char *saveline = NULL;
+	char *p;
+
+	if(line != NULL)
+		saveline = line;
+
+	// see if we have reached the end of the line
+	if(saveline == NULL || *saveline == '\0')
+		return NULL;
+
+	p = saveline; // save start of this token
+	
+	saveline += strcspn(saveline, delims); // get the number of non-delims characters, go past delimiter
+
+	if(*saveline != '\0') // trash the delim if necessary
+		*saveline++ = '\0';
+
+	return p;
+}
+
diff --git a/src/tables.h b/src/tables.h
index 2736f03e8d57e9d06e90493354302c5403a05f45..65d7f72433177f77d711c5e4b5809ed2f9d6e2b8 100644
--- a/src/tables.h
+++ b/src/tables.h
@@ -81,7 +81,7 @@ extern angle_t tantoangle[SLOPERANGE+1];
 
 // Utility function, called by R_PointToAngle.
 FUNCMATH unsigned SlopeDiv(unsigned num, unsigned den);
-// Only called by R_PointToAngleEx
+// Only called by R_PointToAngle64
 UINT64 SlopeDivEx(unsigned int num, unsigned int den);
 
 // 360 - angle_t(ANGLE_45) = ANGLE_315
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
deleted file mode 100644
index 28c4ce492f2d8b4e7590e3ac10f9ce6a95d98a0f..0000000000000000000000000000000000000000
--- a/src/tests/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-target_sources(srb2tests PRIVATE
-	boolcompat.cpp
-)
diff --git a/src/tests/boolcompat.cpp b/src/tests/boolcompat.cpp
deleted file mode 100644
index fee40cd36f2bce34217a875024d6b41fe71adbd1..0000000000000000000000000000000000000000
--- a/src/tests/boolcompat.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <catch2/catch_test_macros.hpp>
-
-#include "../doomtype.h"
-
-TEST_CASE("C++ bool is convertible to doomtype.h boolean") {
-	REQUIRE(static_cast<boolean>(true) == 1);
-	REQUIRE(static_cast<boolean>(false) == 0);
-}
diff --git a/src/v_video.c b/src/v_video.c
index cb7db487e921b88e50fd0b6d97a6d3f631841c90..3beb435b58428491e5b62f3ce48ec35535c25f60 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -384,13 +384,14 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue)
 
 const char *R_GetPalname(UINT16 num)
 {
-	static char palname[9];
-	char newpal[9] = "PLAYPAL";
+	static char palname[8+1];
+	char newpal[9] = "PLAYPAL\0";
 
 	if (num > 0 && num <= 10000)
 		snprintf(newpal, 8, "PAL%04u", num-1);
 
-	strncpy(palname, newpal, 8);
+	strncpy(palname, newpal, sizeof(palname)-1);
+	palname[8] = 0;
 	return palname;
 }
 
@@ -1922,70 +1923,37 @@ UINT8 *V_GetStringColormap(INT32 colorflags)
 	}
 }
 
-// Writes a single character (draw WHITE if bit 7 set)
+// Generalized character drawing function, combining console & chat functionality with a specified font.
 //
-void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed)
+void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fixed_t scale, UINT8 *colormap, fontdef_t font)
 {
 	INT32 w, flags;
-	const UINT8 *colormap = V_GetStringColormap(c);
+	const UINT8 *color = colormap ? colormap : V_GetStringColormap(c);
 
 	flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
 	c &= 0x7f;
-	if (lowercaseallowed)
-		c -= HU_FONTSTART;
-	else
-		c = toupper(c) - HU_FONTSTART;
-	if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
+	c = (lowercaseallowed ? c : toupper(c)) - FONTSTART;
+	if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		return;
 
-	w = hu_font[c]->width;
+	w = FixedMul(font.chars[c]->width / 2, scale);	// use normal sized characters if we're using a terribly low resolution.
 	if (x + w > vid.width)
 		return;
 
-	if (colormap != NULL)
-		V_DrawMappedPatch(x, y, flags, hu_font[c], colormap);
-	else
-		V_DrawScaledPatch(x, y, flags, hu_font[c]);
+	V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, scale, flags, font.chars[c], color);
 }
 
-// Writes a single character for the chat. (draw WHITE if bit 7 set)
-// Essentially the same as the above but it's small or big depending on what resolution you've chosen to huge..
+// Precompile a wordwrapped string to any given width, using a specified font.
 //
-void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap)
-{
-	INT32 w, flags;
-	//const UINT8 *colormap = V_GetStringColormap(c);
-
-	flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
-	c &= 0x7f;
-	if (lowercaseallowed)
-		c -= HU_FONTSTART;
-	else
-		c = toupper(c) - HU_FONTSTART;
-	if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		return;
-
-	w = (vid.width < 640 ) ? ((hu_font[c]->width / 2)) : (hu_font[c]->width);	// use normal sized characters if we're using a terribly low resolution.
-	if (x + w > vid.width)
-		return;
-
-	V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, (vid.width < 640) ? (FRACUNIT) : (FRACUNIT/2), flags, hu_font[c], colormap);
-
-
-}
-
-// Precompile a wordwrapped string to any given width.
-// This is a muuuch better method than V_WORDWRAP.
-char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
+char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font)
 {
 	int c;
-	size_t chw, i, lastusablespace = 0;
-	size_t slen;
+	size_t slen, chw, i, lastusablespace = 0;
 	char *newstring = Z_StrDup(string);
-	INT32 spacewidth = 4, charwidth = 0;
+	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	slen = strlen(string);
-
+	
 	if (w == 0)
 		w = BASEVIDWIDTH;
 	w -= x;
@@ -1994,814 +1962,104 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
 	switch (option & V_SPACINGMASK)
 	{
 		case V_MONOSPACE:
-			spacewidth = 8;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 8;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (i = 0; i < slen; ++i)
-	{
-		c = newstring[i];
-		if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
-			continue;
-
-		if (c == '\n')
-		{
-			x = 0;
-			lastusablespace = 0;
-			continue;
-		}
-
-		if (!(option & V_ALLOWLOWERCASE))
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			chw = spacewidth;
-			lastusablespace = i;
-		}
-		else
-			chw = (charwidth ? charwidth : hu_font[c]->width);
-
-		x += chw;
-
-		if (lastusablespace != 0 && x > w)
-		{
-			newstring[lastusablespace] = '\n';
-			i = lastusablespace;
-			lastusablespace = 0;
-			x = 0;
-		}
-	}
-	return newstring;
-}
-
-//
-// Write a string using the hu_font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = (option & V_CHARCOLORMASK);
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 4, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 8;
+			spacewidth = font.charwidth;
 			/* FALLTHRU */
 		case V_OLDSPACING:
-			charwidth = 8;
+			charwidth = font.charwidth;
 			break;
 		case V_6WIDTHSPACE:
 			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 8*dup;
-			else
-				cy += 12*dup;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += spacewidth * dup;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*dup/2;
-		}
-		else
-			w = hu_font[c]->width * dup;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, hu_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_StringWidth(string, option)/2;
-	V_DrawString(x, y, option, string);
-}
-
-void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_StringWidth(string, option);
-	V_DrawString(x, y, option, string);
-}
-
-//
-// Write a string using the hu_font, 0.5x scale
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 4;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 4;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 4*dup;
-			else
-				cy += 6*dup;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += spacewidth * dup;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*dup/4;
-		}
-		else
-			w = hu_font[c]->width * dup / 2;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT/2, option, hu_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_SmallStringWidth(string, option)/2;
-	V_DrawSmallString(x, y, option, string);
-}
-
-
-void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_SmallStringWidth(string, option);
-	V_DrawSmallString(x, y, option, string);
-}
-
-//
-// Write a string using the tny_font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 5;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 5;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 8*dup;
-			else
-				cy += 12*dup;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase || !tny_font[c-HU_FONTSTART])
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
-		{
-			cx += spacewidth * dup;
-			continue;
-		}
-
-		if (charwidth)
-			w = charwidth * dup;
-		else
-			w = tny_font[c]->width * dup;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, tny_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_ThinStringWidth(string, option)/2;
-	V_DrawThinString(x, y, option, string);
-}
-
-void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_ThinStringWidth(string, option);
-	V_DrawThinString(x, y, option, string);
-}
-
-//
-// Write a string using the tny_font, 0.5x scale
-// NOTE: the text is centered for screens larger than the base width
-//
-// Literally a wrapper. ~Golden
-void V_DrawSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x <<= FRACBITS;
-	y <<= FRACBITS;
-	V_DrawSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
-}
-
-void V_DrawCenteredSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x <<= FRACBITS;
-	y <<= FRACBITS;
-	V_DrawCenteredSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
-}
-
-void V_DrawRightAlignedSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x <<= FRACBITS;
-	y <<= FRACBITS;
-	V_DrawRightAlignedSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
-}
-
-// Draws a string at a fixed_t location.
-void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 4, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 8;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 8;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color ignoring
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += (8*dup)<<FRACBITS;
-			else
-				cy += (12*dup)<<FRACBITS;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += (spacewidth * dup)<<FRACBITS;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*(dup/2);
-		}
-		else
-			w = hu_font[c]->width * dup;
-
-		if ((cx>>FRACBITS) > scrwidth)
-			continue;
-		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
-		{
-			cx += w<<FRACBITS;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT, option, hu_font[c], colormap);
-
-		cx += w<<FRACBITS;
-	}
-}
-
-void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= (V_StringWidth(string, option) / 2)<<FRACBITS;
-	V_DrawStringAtFixed(x, y, option, string);
-}
-
-void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= V_StringWidth(string, option)<<FRACBITS;
-	V_DrawStringAtFixed(x, y, option, string);
-}
-
-// Draws a small string at a fixed_t location.
-void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 4;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 4;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += (4*dup)<<FRACBITS;
-			else
-				cy += (6*dup)<<FRACBITS;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += (spacewidth * dup)<<FRACBITS;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*(dup/4);
-		}
-		else
-			w = hu_font[c]->width * dup / 2;
-
-		if ((cx>>FRACBITS) > scrwidth)
-			break;
-		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
-		{
-			cx += w<<FRACBITS;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-
-		V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT/2, option, hu_font[c], colormap);
-
-		cx += w<<FRACBITS;
-	}
-}
-
-void V_DrawCenteredSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= (V_SmallStringWidth(string, option) / 2)<<FRACBITS;
-	V_DrawSmallStringAtFixed(x, y, option, string);
-}
-
-void V_DrawRightAlignedSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= V_SmallStringWidth(string, option)<<FRACBITS;
-	V_DrawSmallStringAtFixed(x, y, option, string);
-}
-
-// Draws a thin string at a fixed_t location.
-void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 8;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 8;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += (8*dup)<<FRACBITS;
-			else
-				cy += (12*dup)<<FRACBITS;
+		default:
+			break;
+	}
 
+	for (i = 0; i < slen; ++i)
+	{
+		c = newstring[i];
+		if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
 			continue;
-		}
 
-		c = *ch;
-		if (!lowercase || !tny_font[c-HU_FONTSTART])
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
+		if (c == '\n')
 		{
-			cx += (spacewidth * dup)<<FRACBITS;
+			x = 0;
+			lastusablespace = 0;
 			continue;
 		}
 
-		if (charwidth)
+		c = (option & V_ALLOWLOWERCASE ? c : toupper(c)) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		{
-			w = charwidth * dup;
-			center = w/2 - tny_font[c]->width*(dup/2);
+			chw = spacewidth;
+			lastusablespace = i;
 		}
 		else
-			w = tny_font[c]->width * dup;
+			chw = (charwidth ? charwidth : font.chars[c]->width);
 
-		if ((cx>>FRACBITS) > scrwidth)
-			break;
-		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
+		x +=  FixedMul(chw, scale);
+
+		if (lastusablespace != 0 && x > w)
 		{
-			cx += w<<FRACBITS;
-			continue;
+			newstring[lastusablespace] = '\n';
+			i = lastusablespace;
+			lastusablespace = x = 0;
 		}
-
-		colormap = V_GetStringColormap(charflags);
-
-		V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT, option, tny_font[c], colormap);
-
-		cx += w<<FRACBITS;
 	}
+	return newstring;
 }
 
-void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+// Draw a string, using a supplied font and scale.
+// NOTE: The text is centered for screens larger than the base width.
+void V_DrawFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
 {
-	x -= (V_ThinStringWidth(string, option) / 2)<<FRACBITS;
-	V_DrawThinStringAtFixed(x, y, option, string);
+	V_DrawFontStringAtFixed((fixed_t)x<<FRACBITS, (fixed_t)y<<FRACBITS, option, pscale, vscale, string, font);
 }
 
-void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+void V_DrawAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align)
 {
-	x -= V_ThinStringWidth(string, option)<<FRACBITS;
-	V_DrawThinStringAtFixed(x, y, option, string);
+	V_DrawAlignedFontStringAtFixed((fixed_t)x<<FRACBITS, (fixed_t)y<<FRACBITS, option, pscale, vscale, string, font, align);
 }
 
-// Draws a small string at a fixed_t location.
-void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+// Write a string, using a supplied font and scale, at fixed_t coordinates.
+// NOTE: The text is centered for screens larger than the base width.
+void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
 {
 	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
+	INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
 	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2<<FRACBITS, charwidth = 0;
+	INT32 charflags = (option & V_CHARCOLORMASK);
+	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	INT32 lowercase = (option & V_ALLOWLOWERCASE);
 	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
 
 	if (option & V_NOSCALESTART)
 	{
-		dup = vid.dup<<FRACBITS;
+		dupx = vid.dup<<FRACBITS;
+		dupy = vid.dup<<FRACBITS;
 		scrwidth = vid.width;
 	}
 	else
 	{
-		dup = FRACUNIT;
+		dupx = pscale;
+		dupy = vscale;
 		scrwidth = FixedDiv(vid.width<<FRACBITS, vid.dup);
-		left = ((scrwidth - (BASEVIDWIDTH<<FRACBITS))/2);
+		left = (scrwidth - (BASEVIDWIDTH << FRACBITS))/2;
 		scrwidth -= left;
 	}
 
 	if (option & V_NOSCALEPATCH)
 		scrwidth *= vid.dup;
 
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
+	switch (option & V_SPACINGMASK) // TODO: 2.3: drop support for these crusty flags
 	{
 		case V_MONOSPACE:
-			spacewidth = 4<<FRACBITS;
+			spacewidth = font.charwidth;
 			/* FALLTHRU */
 		case V_OLDSPACING:
-			charwidth = 4<<FRACBITS;
+			charwidth = font.charwidth;
 			break;
 		case V_6WIDTHSPACE:
-			spacewidth = 3<<FRACBITS;
+			spacewidth = 6;
 		default:
 			break;
 	}
@@ -2820,61 +2078,66 @@ void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char
 		if (*ch == '\n')
 		{
 			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 4*dup;
-			else
-				cy += 6*dup;
-
+			cy += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, dupy);
 			continue;
 		}
 
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
+		c = (lowercase ? *ch : toupper(*ch)) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		{
-			cx += FixedMul(spacewidth, dup);
+			cx += FixedMul((spacewidth<<FRACBITS), dupx);
 			continue;
 		}
 
 		if (charwidth)
 		{
-			w = FixedMul(charwidth, dup);
-			center = w/2 - tny_font[c]->width*(dup/4);
+			w = FixedMul((charwidth<<FRACBITS), dupx);
+			center = w/2 - FixedMul(font.chars[c]->width<<FRACBITS, (dupx/2));
 		}
 		else
-			w = tny_font[c]->width * dup / 2;
+			w = FixedMul(font.chars[c]->width<<FRACBITS, dupx);
 
-		if (cx > scrwidth)
-			break;
+		if ((cx>>FRACBITS) > scrwidth)
+			continue;
 		if (cx+left + w < 0) //left boundary check
 		{
 			cx += w;
 			continue;
 		}
 
-		colormap = V_GetStringColormap(charflags);
-
-		V_DrawFixedPatch(cx + center, cy, FRACUNIT/2, option, tny_font[c], colormap);
+		V_DrawStretchyFixedPatch(cx + center, cy, pscale, vscale, option, font.chars[c], V_GetStringColormap(charflags));
 
-		cx += w;
+		cx += w + (font.kerning<<FRACBITS);
 	}
 }
 
-void V_DrawCenteredSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align)
 {
-	x -= V_SmallThinStringWidth(string, option)/4;
-	V_DrawSmallThinStringAtFixed(x, y, option, string);
-}
+	char *text = strdup(string);
+	char* line = xstrtok(text, "\n");
+	fixed_t lx = x, ly = y;
 
-void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= V_SmallThinStringWidth(string, option)/2;
-	V_DrawSmallThinStringAtFixed(x, y, option, string);
+	while (line)
+	{
+		switch(align)
+		{
+			case alignleft:
+				lx = x;
+				break;
+			case aligncenter:
+				lx = x - (V_FontStringWidth(line, option, font)*pscale) / 2;
+				break;
+			case alignright:
+				lx = x - (V_FontStringWidth(line, option, font)*pscale);
+				break;
+		}
+		
+		V_DrawFontStringAtFixed(lx, ly, option, pscale, vscale, line, font);
+
+		ly += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, vscale);
+
+		line = xstrtok(NULL, "\n");
+	}
 }
 
 // Draws a tallnum.  Replaces two functions in y_inter and st_stuff
@@ -2939,56 +2202,21 @@ void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num)
 	}
 }
 
-// Write a string using the credit font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string)
+// Returns the width of the act num patch(es)
+INT16 V_LevelActNumWidth(UINT8 num)
 {
-	INT32 w, c, dup, scrwidth = BASEVIDWIDTH;
-	fixed_t cx = x, cy = y;
-	const char *ch = string;
+	INT16 result = 0;
 
-	// It's possible for string to be a null pointer
-	if (!string)
-		return;
+	if (num == 0)
+		result = ttlnum[num]->width;
 
-	if (option & V_NOSCALESTART)
+	while (num > 0 && num <= 99)
 	{
-		dup = vid.dup;
-		scrwidth = vid.width;
+		result = result + ttlnum[num%10]->width;
+		num = num/10;
 	}
-	else
-		dup = 1;
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	for (;;)
-	{
-		c = *ch++;
-		if (!c)
-			break;
-		if (c == '\n')
-		{
-			cx = x;
-			cy += (12*dup)<<FRACBITS;
-			continue;
-		}
-
-		c = toupper(c) - CRED_FONTSTART;
-		if (c < 0 || c >= CRED_FONTSIZE)
-		{
-			cx += (16*dup)<<FRACBITS;
-			continue;
-		}
-
-		w = cred_font[c]->width * dup;
-		if ((cx>>FRACBITS) > scrwidth)
-			continue;
 
-		V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT);
-		cx += w<<FRACBITS;
-	}
+	return result;
 }
 
 // Draw a string using the nt_font
@@ -3029,21 +2257,18 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
 		if (*ch == '\n')
 		{
 			cx = x<<FRACBITS;
-			cy += FixedMul((21*dup)*FRACUNIT, scale);
+			cy += FixedMul((ntb_font.linespacing * dup)*FRACUNIT, scale);
 			continue;
 		}
 
-		c = toupper(*ch);
-		c -= NT_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c])
+		c = toupper(*ch) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !ntb_font.chars[c] || !nto_font.chars[c])
 		{
-			cx += FixedMul((4 * dup)*FRACUNIT, scale);
+			cx += FixedMul((ntb_font.spacewidth * dup)*FRACUNIT, scale);
 			continue;
 		}
 
-		w = FixedMul(((ntb_font[c]->width)+2 * dup) * FRACUNIT, scale);
+		w = FixedMul(((ntb_font.chars[c]->width)+ntb_font.kerning * dup) * FRACUNIT, scale);
 
 		if (FixedInt(cx) > scrwidth)
 			continue;
@@ -3053,8 +2278,8 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
 			continue;
 		}
 
-		V_DrawFixedPatch(cx, cy, scale, option, nto_font[c], outlinecolormap);
-		V_DrawFixedPatch(cx, cy, scale, option, ntb_font[c], basecolormap);
+		V_DrawFixedPatch(cx, cy, scale, option, nto_font.chars[c], outlinecolormap);
+		V_DrawFixedPatch(cx, cy, scale, option, ntb_font.chars[c], basecolormap);
 
 		cx += w;
 	}
@@ -3169,193 +2394,20 @@ INT32 V_CountNameTagLines(const char *string)
 	return ntlines;
 }
 
-INT32 V_NameTagWidth(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	// It's possible for string to be a null pointer
-	if (!string)
-		return 0;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		c = toupper(string[i]) - NT_FONTSTART;
-		if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c])
-			w += 4;
-		else
-			w += (ntb_font[c]->width)+2;
-	}
-
-	return w;
-}
-
-// Find string width from cred_font chars
-//
-INT32 V_CreditStringWidth(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	// It's possible for string to be a null pointer
-	if (!string)
-		return 0;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		c = toupper(string[i]) - CRED_FONTSTART;
-		if (c < 0 || c >= CRED_FONTSIZE)
-			w += 16;
-		else
-			w += cred_font[c]->width;
-	}
-
-	return w;
-}
-
-// Write a string using the level title font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, left = 0;
-	const char *ch = string;
-	INT32 charflags = (option & V_CHARCOLORMASK);
-	const UINT8 *colormap = NULL;
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-			cy += 12*dup;
-			continue;
-		}
-
-		c = *ch - LT_FONTSTART;
-		if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
-		{
-			cx += 16*dup;
-			continue;
-		}
-
-		w = lt_font[c]->width * dup;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, lt_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-// Find string width from lt_font chars
-//
-INT32 V_LevelNameWidth(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		if (string[i] & 0x80)
-			continue;
-		c = string[i] - LT_FONTSTART;
-		if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
-			w += 16;
-		else
-			w += lt_font[c]->width;
-	}
-
-	return w;
-}
-
-// Find max height of the string
-//
-INT32 V_LevelNameHeight(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		c = string[i] - LT_FONTSTART;
-		if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
-			continue;
-
-		if (lt_font[c]->height > w)
-			w = lt_font[c]->height;
-	}
-
-	return w;
-}
-
-// For ST_drawTitleCard
-// Returns the width of the act num patch(es)
-INT16 V_LevelActNumWidth(UINT8 num)
-{
-	INT16 result = 0;
-
-	if (num == 0)
-		result = ttlnum[num]->width;
-
-	while (num > 0 && num <= 99)
-	{
-		result = result + ttlnum[num%10]->width;
-		num = num/10;
-	}
-
-	return result;
-}
-
+// Find string width from supplied font characters & character width.
 //
-// Find string width from hu_font chars
-//
-INT32 V_StringWidth(const char *string, INT32 option)
+INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 {
-	INT32 c, w = 0;
-	INT32 spacewidth = 4, charwidth = 0;
-	size_t i;
+	INT32 c, w = 0, wline = 0;
+	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	switch (option & V_SPACINGMASK)
 	{
 		case V_MONOSPACE:
-			spacewidth = 8;
+			spacewidth = font.charwidth;
 			/* FALLTHRU */
 		case V_OLDSPACING:
-			charwidth = 8;
+			charwidth = font.charwidth;
 			break;
 		case V_6WIDTHSPACE:
 			spacewidth = 6;
@@ -3363,16 +2415,24 @@ INT32 V_StringWidth(const char *string, INT32 option)
 			break;
 	}
 
-	for (i = 0; i < strlen(string); i++)
+	for (size_t i = 0; i < strlen(string); i++)
 	{
+		if (string[i] == '\n')
+		{
+			if (wline < w) wline = w;
+			w = 0;
+			continue;
+		}	
 		if (string[i] & 0x80)
 			continue;
-		c = toupper(string[i]) - HU_FONTSTART;
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
+
+		c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 			w += spacewidth;
 		else
-			w += (charwidth ? charwidth : hu_font[c]->width);
+			w += (charwidth ? charwidth : (font.chars[c]->width)) + font.kerning;
 	}
+	w = max(wline, w);
 
 	if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
 		w *= vid.dup;
@@ -3380,87 +2440,30 @@ INT32 V_StringWidth(const char *string, INT32 option)
 	return w;
 }
 
+// Find max string height from supplied font characters
 //
-// Find string width from hu_font chars, 0.5x scale
-//
-INT32 V_SmallStringWidth(const char *string, INT32 option)
+INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font)
 {
-	INT32 c, w = 0;
-	INT32 spacewidth = 2, charwidth = 0;
-	size_t i;
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 4;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 4;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
+	INT32 c, h = 0, result = 0;
 
-	for (i = 0; i < strlen(string); i++)
+	for (size_t i = 0; i < strlen(string); i++)
 	{
-		if (string[i] & 0x80)
+		c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
+		{
+			if (string[i] == '\n')
+			{
+				result += (option & V_RETURN8) ? 8 : font.linespacing;
+				h = 0;
+			}	
 			continue;
-		c = toupper(string[i]) - HU_FONTSTART;
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-			w += spacewidth;
-		else
-			w += (charwidth ? charwidth : (hu_font[c]->width / 2));
-	}
-
-	return w;
-}
-
-//
-// Find string width from tny_font chars
-//
-INT32 V_ThinStringWidth(const char *string, INT32 option)
-{
-	INT32 c, w = 0;
-	INT32 spacewidth = 2, charwidth = 0;
-	size_t i;
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 5;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 5;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
+		}
 
-	for (i = 0; i < strlen(string); i++)
-	{
-		if (string[i] & 0x80)
-			continue;
-		c = toupper(string[i]) - HU_FONTSTART;
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
-			w += spacewidth;
-		else
-			w += (charwidth ? charwidth : tny_font[c]->width);
+		if (font.chars[c]->height > h)
+			h = font.chars[c]->height;
 	}
 
-	return w;
-}
-
-//
-// Find string width from tny_font chars, 0.5x scale
-//
-INT32 V_SmallThinStringWidth(const char *string, INT32 option)
-{
-	INT32 w = V_ThinStringWidth(string, option)<<FRACBITS;
-	return w/2 + FRACUNIT; // +FRACUNIT because otherwise it's offset wrong.
+	return result + h;
 }
 
 boolean *heatshifter = NULL;
diff --git a/src/v_video.h b/src/v_video.h
index 5a3df5a4499588df56e4a6d152f1445f82a60926..d37762466147ae843c8f0fba5218f4e8af3f6462 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -17,6 +17,7 @@
 #include "doomdef.h"
 #include "doomtype.h"
 #include "r_defs.h"
+#include "hu_stuff.h" //font arrays
 
 //
 // VIDEO
@@ -191,86 +192,93 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U
 
 void V_DrawFadeConsBack(INT32 plines);
 void V_DrawPromptBack(INT32 boxheight, INT32 color);
-
-// draw a single character
-void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
-// draw a single character, but for the chat
-void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap);
-
-UINT8 *V_GetStringColormap(INT32 colorflags);
-
-void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string);
-
-// wordwrap a string using the hu_font
-char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string);
 UINT8 *V_GetStringColormap(INT32 colorflags);
 
+// Generalized character drawing function, combining console & chat functionality with a specified font.
+void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fixed_t scale, UINT8 *colormap, fontdef_t font);
+#define V_DrawCharacter(x,y,c,l) V_DrawFontCharacter(x,y,c,l,FRACUNIT,NULL,hu_font)
+#define V_DrawChatCharacter(x,y,c,l,cm) V_DrawFontCharacter(x,y,c,l,FRACUNIT/2,cm,hu_font)
+
+// Precompile a wordwrapped string to any given width, using a specified font.
+char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font);
+#define V_WordWrap(x,w,o,str) V_FontWordWrap(x, w, o, FRACUNIT, str, hu_font)
+#define V_ChatWordWrap(x,w,o,str) V_FontWordWrap(x, w, o, FRACUNIT/2, str, hu_font)
+
+enum string_align {
+	alignleft = 0,
+	aligncenter,
+	alignright
+};
+
+// Draw a string, using a supplied font and scale.
+void V_DrawFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
+void V_DrawAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align);
+// Draw a string, using a supplied font and scale, at fixed_t coordinates.
+void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
+void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align);
+
+// Defines for old string drawers.
 // draw a string using the hu_font
-void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string);
-
+#define V_DrawString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT,FRACUNIT,str,hu_font)
+#define V_DrawCenteredString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,aligncenter)
+#define V_DrawRightAlignedString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,alignright)
 // draw a string using the hu_font, 0.5x scale
-void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string);
-
-// draw a string using the tny_font
-void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string);
-
+#define V_DrawSmallString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font)
+#define V_DrawCenteredSmallString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,aligncenter)
+#define V_DrawRightAlignedSmallString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,alignright)
+// Write a string using the tny_font
+#define V_DrawThinString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT,FRACUNIT,str,tny_font)
+#define V_DrawCenteredThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,aligncenter)
+#define V_DrawRightAlignedThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,alignright)
 // draw a string using the tny_font, 0.5x scale
-void V_DrawSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
-
+#define V_DrawSmallThinString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font)
+#define V_DrawCenteredSmallThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,aligncenter)
+#define V_DrawRightAlignedSmallThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,alignright)
 // draw a string using the hu_font at fixed_t coordinates
-void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-
+#define V_DrawStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,hu_font)
+#define V_DrawCenteredStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,aligncenter)
+#define V_DrawRightAlignedStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,alignright)
 // draw a string using the hu_font at fixed_t coordinates, 0.5x scale
-void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-
+#define V_DrawSmallStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font)
+#define V_DrawCenteredSmallStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,aligncenter)
+#define V_DrawRightAlignedSmallStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,alignright)
 // draw a string using the tny_font at fixed_t coordinates
-void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-
+#define V_DrawThinStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,tny_font)
+#define V_DrawCenteredThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,aligncenter)
+#define V_DrawRightAlignedThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,alignright)
 // draw a string using the tny_font at fixed_t coordinates, 0.5x scale
-void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
+#define V_DrawSmallThinStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font)
+#define V_DrawCenteredSmallThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,aligncenter)
+#define V_DrawRightAlignedSmallThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,alignright)
+// draw a string using the credit font
+#define V_DrawCreditString(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,cred_font)
+// draw a string using the level title font
+#define V_DrawLevelTitle(x,y,o,str) V_DrawFontString(x,y,o|V_ALLOWLOWERCASE,FRACUNIT,FRACUNIT,str,lt_font)
 
 // Draw tall nums, used for menu, HUD, intermission
 void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num);
 void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits);
 void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num);
-
-// Find string width from lt_font chars
-INT32 V_LevelNameWidth(const char *string);
-INT32 V_LevelNameHeight(const char *string);
 INT16 V_LevelActNumWidth(UINT8 num); // act number width
 
-void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string);
-INT32 V_CreditStringWidth(const char *string);
-
 // Draw a string using the nt_font
 void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string);
 INT32 V_CountNameTagLines(const char *string);
-INT32 V_NameTagWidth(const char *string);
-
-// Find string width from hu_font chars
-INT32 V_StringWidth(const char *string, INT32 option);
-// Find string width from hu_font chars, 0.5x scale
-INT32 V_SmallStringWidth(const char *string, INT32 option);
-// Find string width from tny_font chars
-INT32 V_ThinStringWidth(const char *string, INT32 option);
-// Find string width from tny_font chars, 0.5x scale
-INT32 V_SmallThinStringWidth(const char *string, INT32 option);
+
+// Find string width or height from supplied font chars
+INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font);
+INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font);
+
+// Defines for old string width functions.
+#define V_StringWidth(str,o) V_FontStringWidth(str,o,hu_font)
+#define V_SmallStringWidth(str,o) V_FontStringWidth(str,o,hu_font)/2
+#define V_ThinStringWidth(str,o) V_FontStringWidth(str,o,tny_font)
+#define V_SmallThinStringWidth(str,o) V_FontStringWidth(str,o,tny_font)/2
+#define V_CreditStringWidth(str) V_FontStringWidth(str,0,cred_font)
+#define V_NameTagWidth(str) V_FontStringWidth(str,0,ntb_font)
+#define V_LevelNameWidth(str) V_FontStringWidth(str,V_ALLOWLOWERCASE,lt_font)
+#define V_LevelNameHeight(str) V_FontStringHeight(str,0,lt_font)
+#define V_StringHeight(str,o) V_FontStringHeight(str,o,hu_font)
 
 void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param);
 
diff --git a/src/w_wad.c b/src/w_wad.c
index 0b391f0c488cbe0da6daa5251f362128807c2d27..78d26f9056c16e818d0384d1f91f2237d8b8024b 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -1168,6 +1168,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 	numwadfiles++;
 
 	W_ReadFileShaders(wadfile);
+	W_LoadTrnslateLumps(numwadfiles - 1);
 	W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile);
 	W_InvalidateLumpnumCache();
 
@@ -1348,6 +1349,47 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
 	return i;
 }
 
+char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump)
+{
+	const char *fullname = wadfiles[wad]->lumpinfo[lump].fullname;
+
+	const char *slash = strrchr(fullname, '/');
+	INT32 pathlen = slash ? slash - fullname : 0;
+
+	char *path = Z_Calloc(pathlen + 1, PU_STATIC, NULL);
+	strncpy(path, fullname, pathlen);
+
+	return path;
+}
+
+char *W_GetLumpFolderNamePK3(UINT16 wad, UINT16 lump)
+{
+	const char *fullname = wadfiles[wad]->lumpinfo[lump].fullname;
+	size_t start, end;
+
+	INT32 i = strlen(fullname);
+
+	i--;
+	while (i >= 0 && fullname[i] != '/')
+		i--;
+	if (i < 0)
+		return NULL;
+	end = i;
+
+	i--;
+	while (i >= 0 && fullname[i] != '/')
+		i--;
+	if (i < 0)
+		return NULL;
+	start = i + 1;
+
+	size_t namelen = end - start;
+	char *foldername = Z_Calloc(namelen + 1, PU_STATIC, NULL);
+	strncpy(foldername, fullname + start, namelen);
+
+	return foldername;
+}
+
 void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps)
 {
 	size_t name_length = strlen(name);
diff --git a/src/w_wad.h b/src/w_wad.h
index e043e4d62c82f061ce505c4ce6b6a2298d48a4ec..80e0e32fd585faaddcaf24dd8167e3f694d388f2 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -180,6 +180,8 @@ UINT16 W_CheckNumForMarkerStartPwad(const char *name, UINT16 wad, UINT16 startlu
 UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
 UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
 UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump);
+char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump);
+char *W_GetLumpFolderNamePK3(UINT16 wad, UINT16 lump);
 
 void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps);
 void W_GetFolderLumps(const char *name, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps);
diff --git a/src/y_inter.c b/src/y_inter.c
index bb4fa06907785c9b193881cfde8b0c4d8bfd18f8..2add8645b0888ea460419b0165abeca702d6e29b 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -579,9 +579,9 @@ void Y_IntermissionDrawer(void)
 		{
 			if (LUA_HudEnabled(hud_intermissiontitletext))
 			{
-				const char *ringtext = "\x82" "get 50 rings then";
+				const char *ringtext = "\x82" "get 50 rings, then";
 				const char *tut1text = "\x82" "press " "\x80" "shield";
-				const char *tut2text = "\x82" "to " "\x80" "transform";
+				const char *tut2text = "\x82" "to transform";
 				ttheight = 8;
 				V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
 				ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
diff --git a/thirdparty/00-SDL-Mixer-X-2.6.0-DISABLE_INSTALL.patch b/thirdparty/00-SDL-Mixer-X-2.6.0-DISABLE_INSTALL.patch
new file mode 100644
index 0000000000000000000000000000000000000000..0e7f55f1b282300bbdb6d21a8abd67373fd45828
--- /dev/null
+++ b/thirdparty/00-SDL-Mixer-X-2.6.0-DISABLE_INSTALL.patch
@@ -0,0 +1,26 @@
+--- a/CMakeLists.txt	2023-11-22 22:42:53.000000000 -0500
++++ b/CMakeLists.txt	2024-02-15 18:46:57.852076200 -0500
+@@ -45,6 +45,7 @@
+ 
+     option(SDL_MIXER_X_STATIC   "Build static library of SDL Mixer X" ${SDL_MIXER_X_STATIC_ENABLED_BY_DEFAULT})
+     option(SDL_MIXER_X_SHARED   "Build shared library of SDL Mixer X" ${SDL_MIXER_X_SHARED_ENABLED_BY_DEFAULT})
++     option(SDL_MIXER_X_DISABLE_INSTALL   "Disable install of SDL Mixer X" OFF)
+ else()
+     set(SDL_MIXER_X_STATIC ON)
+     set(SDL_MIXER_X_SHARED OFF)
+@@ -475,6 +476,7 @@
+     add_subdirectory(examples)
+ endif()
+ 
++if(NOT SDL_MIXER_X_DISABLE_INSTALL)
+ if(SDL_MIXER_X_STATIC AND NOT BUILD_AS_VB6_BINDING)
+     install(TARGETS SDL2_mixer_ext_Static
+             EXPORT SDL2MixerExtStaticTargets
+@@ -500,6 +502,7 @@
+             NAMESPACE SDL2_mixer_ext::
+             DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/SDL2_mixer_ext")
+ endif()
++endif()
+ 
+ 
+ if(BUILD_AS_VB6_BINDING)
diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt
index f33b3bf3f836b86b98fda8e78f73ec5be19758d8..5114cbe2c81432173409cce5a113ea9305b5b23b 100644
--- a/thirdparty/CMakeLists.txt
+++ b/thirdparty/CMakeLists.txt
@@ -1,21 +1,2 @@
-macro(export)
-endmacro()
 
-if(SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
-	set(SRB2_INTERNAL_LIBRARY_TYPE SHARED)
-	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES OFF)
-else()
-	set(SRB2_INTERNAL_LIBRARY_TYPE STATIC)
-	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES ON)
-endif()
-
-if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
-	include("cpm-sdl2.cmake")
-	include("cpm-sdl2-mixer.cmake")
-	include("cpm-zlib.cmake")
-	include("cpm-png.cmake")
-	include("cpm-curl.cmake")
-	include("cpm-openmpt.cmake")
-endif()
-
-include("cpm-libgme.cmake")
+include("Ccache.cmake")
diff --git a/thirdparty/Ccache.cmake b/thirdparty/Ccache.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6ca0d9fa0615d8cf091992ed84bec7b4fef09144
--- /dev/null
+++ b/thirdparty/Ccache.cmake
@@ -0,0 +1,15 @@
+# Enable CCache
+# (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options)
+if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows)
+	option(USE_CCACHE "Enable ccache support" OFF)
+
+	if(USE_CCACHE)
+		find_program(CCACHE_TOOL_PATH ccache)
+		if(CCACHE_TOOL_PATH)
+			set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
+			set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
+		else()
+			message(WARNING "USE_CCACHE was set but ccache is not found (set CCACHE_TOOL_PATH)")
+		endif()
+	endif()
+endif()
\ No newline at end of file
diff --git a/thirdparty/cpm-libgme.cmake b/thirdparty/cpm-libgme.cmake
deleted file mode 100644
index f15bc3b31cb23ed7663ed950c14c1d6a0dc36567..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-libgme.cmake
+++ /dev/null
@@ -1,16 +0,0 @@
-CPMAddPackage(
-	NAME libgme
-	VERSION 0.6.3
-	URL "https://bitbucket.org/mpyne/game-music-emu/get/e76bdc0cb916e79aa540290e6edd0c445879d3ba.zip"
-	EXCLUDE_FROM_ALL ON
-	OPTIONS
-		"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"ENABLE_UBSAN OFF"
-		"GME_YM2612_EMU MAME"
-)
-
-if(libgme_ADDED)
-	target_compile_features(gme PRIVATE cxx_std_11)
-	# libgme's CMakeLists.txt already links this
-	#target_link_libraries(gme PRIVATE ZLIB::ZLIB)
-endif()
diff --git a/thirdparty/cpm-png.cmake b/thirdparty/cpm-png.cmake
deleted file mode 100644
index f16ac037b0cc9c077f3ef315b67b430e68cf9b40..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-png.cmake
+++ /dev/null
@@ -1,69 +0,0 @@
-CPMAddPackage(
-	NAME png
-	VERSION 1.6.38
-	URL "https://github.com/glennrp/libpng/archive/refs/tags/v1.6.38.zip"
-	# png cmake build is broken on msys/mingw32
-	DOWNLOAD_ONLY YES
-)
-
-if(png_ADDED)
-	# Since png's cmake build is broken, we're going to create a target manually
-	set(
-		PNG_SOURCES
-		png.h
-		pngconf.h
-		pngpriv.h
-		pngdebug.h
-		pnginfo.h
-		pngstruct.h
-		png.c
-		pngerror.c
-		pngget.c
-		pngmem.c
-		pngpread.c
-		pngread.c
-		pngrio.c
-		pngrtran.c
-		pngrutil.c
-		pngset.c
-		pngtrans.c
-		pngwio.c
-		pngwrite.c
-		pngwtran.c
-		pngwutil.c
-	)
-	list(TRANSFORM PNG_SOURCES PREPEND "${png_SOURCE_DIR}/")
-
-	add_custom_command(
-		OUTPUT "${png_BINARY_DIR}/include/png.h" "${png_BINARY_DIR}/include/pngconf.h"
-		COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h" "${png_BINARY_DIR}/include"
-		DEPENDS "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h"
-		VERBATIM
-	)
-	add_custom_command(
-		OUTPUT "${png_BINARY_DIR}/include/pnglibconf.h"
-		COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt" "${png_BINARY_DIR}/include/pnglibconf.h"
-		DEPENDS "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt"
-		VERBATIM
-	)
-	list(
-		APPEND PNG_SOURCES
-		"${png_BINARY_DIR}/include/png.h"
-		"${png_BINARY_DIR}/include/pngconf.h"
-		"${png_BINARY_DIR}/include/pnglibconf.h"
-	)
-	add_library(png "${SRB2_INTERNAL_LIBRARY_TYPE}" ${PNG_SOURCES})
-
-	# Disable ARM NEON since having it automatic breaks libpng external build on clang for some reason
-	target_compile_definitions(png PRIVATE -DPNG_ARM_NEON_OPT=0)
-
-	# The png includes need to be available to consumers
-	target_include_directories(png PUBLIC "${png_BINARY_DIR}/include")
-
-	# ... and these also need to be present only for png build
-	target_include_directories(png PRIVATE "${ZLIB_SOURCE_DIR}")
-	target_include_directories(png PRIVATE "${ZLIB_BINARY_DIR}")
-	target_include_directories(png PRIVATE "${png_BINARY_DIR}")
-	target_link_libraries(png PRIVATE ZLIB::ZLIB)
-	add_library(PNG::PNG ALIAS png)
-endif()
diff --git a/thirdparty/cpm-sdl2-mixer.cmake b/thirdparty/cpm-sdl2-mixer.cmake
deleted file mode 100644
index b7dfeae0d3eab254651f0c5e6e69e7af0626012e..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-sdl2-mixer.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-CPMAddPackage(
-	NAME SDL2_mixer
-	VERSION 2.6.2
-	URL "https://github.com/libsdl-org/SDL_mixer/archive/refs/tags/release-2.6.2.zip"
-	EXCLUDE_FROM_ALL ON
-	OPTIONS
-		"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL2MIXER_INSTALL OFF"
-		"SDL2MIXER_DEPS_SHARED OFF"
-		"SDL2MIXER_SAMPLES OFF"
-		"SDL2MIXER_VENDORED ON"
-		"SDL2MIXER_FLAC ON"
-		"SDL2MIXER_FLAC_LIBFLAC OFF"
-		"SDL2MIXER_FLAC_DRFLAC ON"
-		"SDL2MIXER_MOD OFF"
-		"SDL2MIXER_MP3 ON"
-		"SDL2MIXER_MP3_DRMP3 ON"
-		"SDL2MIXER_MIDI ON"
-		"SDL2MIXER_OPUS OFF"
-		"SDL2MIXER_VORBIS STB"
-		"SDL2MIXER_WAVE ON"
-)
diff --git a/thirdparty/cpm-sdl2.cmake b/thirdparty/cpm-sdl2.cmake
deleted file mode 100644
index 90e5bd0fe3e081cfd320fcf06ff23e9477492793..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-sdl2.cmake
+++ /dev/null
@@ -1,28 +0,0 @@
-set(
-	internal_sdl2_options
-
-		"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL_TEST OFF"
-		"SDL2_DISABLE_INSTALL ON"
-)
-
-if(${CMAKE_SYSTEM} MATCHES Windows)
-	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
-endif()
-if(${CMAKE_SYSTEM} MATCHES Darwin)
-	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
-endif()
-if(${CMAKE_SYSTEM} MATCHES Linux)
-	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN ON")
-endif()
-
-CPMAddPackage(
-	NAME SDL2
-	VERSION 2.30.0
-	GITHUB_REPOSITORY "libsdl-org/SDL"
-	GIT_TAG release-2.30.0
-	EXCLUDE_FROM_ALL ON
-	OPTIONS ${internal_sdl2_options}
-)
diff --git a/thirdparty/cpm-zlib.cmake b/thirdparty/cpm-zlib.cmake
deleted file mode 100644
index f0a2c33aee8c483d82b4ab26e1d0be2143fd9e16..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-zlib.cmake
+++ /dev/null
@@ -1,18 +0,0 @@
-CPMAddPackage(
-	NAME zlib
-	VERSION 1.3.1
-	GITHUB_REPOSITORY "madler/zlib"
-	GIT_TAG v1.3.1
-	EXCLUDE_FROM_ALL
-	OPTIONS
-		"ZLIB_BUILD_EXAMPLES OFF"
-)
-
-if(zlib_ADDED)
-	if(SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
-		add_library(ZLIB::ZLIB ALIAS zlib)
-	endif()
-	if(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
-		add_library(ZLIB::ZLIB ALIAS zlibstatic)
-	endif()
-endif()
diff --git a/thirdparty/cpm-curl.cmake b/thirdparty/curl.cmake
similarity index 55%
rename from thirdparty/cpm-curl.cmake
rename to thirdparty/curl.cmake
index 3d8c6e61d46dee6f06f4e6d69beb09d1605f6584..5c3aa26e35882d64ca8a6cf99517d28e9fc56dcc 100644
--- a/thirdparty/cpm-curl.cmake
+++ b/thirdparty/curl.cmake
@@ -1,8 +1,16 @@
+if(TARGET CURL::libcurl)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'CURL::libcurl'")
+
+set(CURL_ENABLE_EXPORT_TARGET OFF CACHE BOOL "" FORCE)
+
 set(
 	internal_curl_options
 
 	"BUILD_CURL_EXE OFF"
-	"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
+	"BUILD_SHARED_LIBS OFF"
 	"CURL_DISABLE_TESTS ON"
 	"HTTP_ONLY ON"
 	"CURL_DISABLE_CRYPTO_AUTH ON"
@@ -26,10 +34,25 @@ if(${CMAKE_SYSTEM} MATCHES Linux)
 	list(APPEND internal_curl_options "CURL_USE_OPENSSL ON")
 endif()
 
-CPMAddPackage(
-	NAME curl
-	VERSION 7.86.0
-	URL "https://github.com/curl/curl/archive/refs/tags/curl-7_86_0.zip"
-	EXCLUDE_FROM_ALL ON
-	OPTIONS ${internal_curl_options}
-)
+include(FetchContent)
+
+if (CURL_USE_THIRDPARTY)
+	FetchContent_Declare(
+		curl
+		VERSION 7.88.1
+		GITHUB_REPOSITORY "curl/curl"
+		GIT_TAG curl-7_88_1
+		EXCLUDE_FROM_ALL ON
+		OPTIONS ${internal_curl_options}
+	)
+else()
+	FetchContent_Declare(
+		curl
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/curl/"
+		EXCLUDE_FROM_ALL ON
+		OPTIONS ${internal_curl_options}
+	)
+endif()
+
+FetchContent_MakeAvailable(curl)
+
diff --git a/thirdparty/libapng.cmake b/thirdparty/libapng.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f4bc50ff1d301b58bf91c44bfe40986c5c987654
--- /dev/null
+++ b/thirdparty/libapng.cmake
@@ -0,0 +1,38 @@
+if(TARGET libapng_static)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'libapng_static'")
+
+set(PNG_SHARED OFF CACHE BOOL "" FORCE)
+set(PNG_BUILD_ZLIB ON CACHE BOOL "" FORCE)
+
+include(FetchContent)
+
+	FetchContent_Declare(
+		libapng-local
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/libapng/"
+		EXCLUDE_FROM_ALL ON
+		DOWNLOAD_ONLY YES
+		OPTION
+			"PNG_SHARED OFF"
+			"PNG_EXECUTABLES OFF"
+			"PNG_TESTS OFF"
+			"PNG_BUILD_ZLIB ON"
+	)
+
+FetchContent_MakeAvailable(libapng-local)
+
+#add_custom_command(
+#OUTPUT ${libapng-local_BINARY_DIR}/CMakeLists.txt
+#COMMAND ${CMAKE_COMMAND}
+#  -Din_file:FILEPATH=${libapng-locall_SOURCE_DIR}/CMakeLists.txt
+#  -Dpatch_file:FILEPATH=${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/00-libapng-ZLIB.patch
+#  -Dout_file:FILEPATH=${libapng-local_BINARY_DIR}/CMakeLists.txt
+#  -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/PatchFile.cmake
+#DEPENDS ${libapng-local_SOURCE_DIR}/CMakeLists.txt
+#)
+
+set(libapng_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libapng" "${libapng_BINARY_DIR}" CACHE PATH "" FORCE)
+
+set(libapng_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/libapng/png.h" "${CMAKE_CURRENT_SOURCE_DIR}/libapng/pngconf.h" CACHE PATH "" FORCE)
diff --git a/thirdparty/cpm-openmpt.cmake b/thirdparty/libopenmpt.cmake
similarity index 82%
rename from thirdparty/cpm-openmpt.cmake
rename to thirdparty/libopenmpt.cmake
index 01f7ff75f64d915799e432f2923a2c7e8c344466..256b4c406b99b73bf96e9488316b1093515f65c9 100644
--- a/thirdparty/cpm-openmpt.cmake
+++ b/thirdparty/libopenmpt.cmake
@@ -1,13 +1,33 @@
-CPMAddPackage(
-	NAME openmpt
-	VERSION 0.4.30
-	URL "https://github.com/OpenMPT/openmpt/archive/refs/tags/libopenmpt-0.4.30.zip"
-	DOWNLOAD_ONLY ON
-)
+if(TARGET libopenmpt)
+    #return()
+endif()
+
+message(STATUS "Third-party: creating target 'libopenmpt'")
+
+
+include(FetchContent)
+
+if (libopenmpt_USE_THIRDPARTY)
+	FetchContent_Declare(
+		libopenmpt-local
+		GITHUB_REPOSITORY openmpt
+		GIT_TAG libopenmpt-0.4.38
+		version 0.4.38
+		EXCLUDE_FROM_ALL ON
+	)
+else()
+	FetchContent_Declare(
+		libopenmpt-local
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/libopenmpt/"
+		EXCLUDE_FROM_ALL ON
+	)
+endif()
+
+FetchContent_MakeAvailable(libopenmpt)
 
-if(openmpt_ADDED)
+if(aaaa-libopenmpt-local_ADDED)
 	set(
-		openmpt_SOURCES
+		libopenmpt-local_SOURCES
 
 		# minimp3
 		# -DMPT_WITH_MINIMP3
@@ -264,26 +284,26 @@ if(openmpt_ADDED)
 		libopenmpt/libopenmpt_impl.cpp
 		libopenmpt/libopenmpt_ext_impl.cpp
 	)
-	list(TRANSFORM openmpt_SOURCES PREPEND "${openmpt_SOURCE_DIR}/")
+	list(TRANSFORM libopenmpt-local_SOURCES PREPEND "${libopenmpt-local_SOURCE_DIR}/")
 
 	# -DLIBOPENMPT_BUILD
 	configure_file("openmpt_svn_version.h" "svn_version.h")
-	add_library(openmpt "${SRB2_INTERNAL_LIBRARY_TYPE}" ${openmpt_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/svn_version.h)
+	add_library(libopenmpt STATIC ${libopenmpt-local_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/svn_version.h)
 	if("${CMAKE_C_COMPILER_ID}" STREQUAL GNU OR "${CMAKE_C_COMPILER_ID}" STREQUAL Clang OR "${CMAKE_C_COMPILER_ID}" STREQUAL AppleClang)
-		target_compile_options(openmpt PRIVATE "-g0")
+		target_compile_options(libopenmpt PRIVATE "-g0")
 	endif()
 	if("${CMAKE_SYSTEM_NAME}" STREQUAL Windows AND "${CMAKE_C_COMPILER_ID}" STREQUAL MSVC)
-		target_link_libraries(openmpt PRIVATE Rpcrt4)
+		target_link_libraries(libopenmpt PRIVATE Rpcrt4)
 	endif()
-	target_compile_features(openmpt PRIVATE cxx_std_11)
-	target_compile_definitions(openmpt PRIVATE -DLIBOPENMPT_BUILD)
+	target_compile_features(libopenmpt PRIVATE cxx_std_11)
+	target_compile_definitions(libopenmpt PRIVATE -DLIBOPENMPT_BUILD)
 
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/common")
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/src")
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/include")
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}")
-	target_include_directories(openmpt PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}/common")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}/src")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}/include")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}")
+	target_include_directories(libopenmpt PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
 
 	# I wish this wasn't necessary, but it is
-	target_include_directories(openmpt PUBLIC "${openmpt_SOURCE_DIR}")
+	target_include_directories(libopenmpt PUBLIC "${libopenmpt-local_SOURCE_DIR}")
 endif()
diff --git a/thirdparty/libpng-1.6.40-apng.patch b/thirdparty/libpng-1.6.40-apng.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c5b870004ad2f7a82df6bbbc061c24cc8f5a5393
--- /dev/null
+++ b/thirdparty/libpng-1.6.40-apng.patch
@@ -0,0 +1,1728 @@
+diff -Naru libpng-1.6.40.org/png.h libpng-1.6.40/png.h
+--- libpng-1.6.40.org/png.h	2023-09-10 11:12:23.044481879 +0900
++++ libpng-1.6.40/png.h	2023-09-10 11:08:58.964075833 +0900
+@@ -330,6 +330,10 @@
+ #   include "pnglibconf.h"
+ #endif
+ 
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ #  include "pngconf.h"
+@@ -425,6 +429,17 @@
+  * See pngconf.h for base types that vary by machine/system
+  */
+ 
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE        0x00U
++#define PNG_DISPOSE_OP_BACKGROUND  0x01U
++#define PNG_DISPOSE_OP_PREVIOUS    0x02U
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE        0x00U
++#define PNG_BLEND_OP_OVER          0x01U
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+  * do not agree upon the version number.
+  */
+@@ -746,6 +761,10 @@
+ #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
+ #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
+ #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x20000U
++#define PNG_INFO_fcTL 0x40000U
++#endif
+ 
+ /* This is used for the transformation routines, as some of them
+  * change these values for the row.  It also should enable using
+@@ -783,6 +802,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++    png_uint_32));
++#endif
+ 
+ /* The following callback receives png_uint_32 row_number, int pass for the
+  * png_bytep data of the row.  When transforming an interlaced image the
+@@ -3226,6 +3249,74 @@
+ /*******************************************************************************
+  *  END OF HARDWARE AND SOFTWARE OPTIONS
+  ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
++   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
++   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++   png_infop info_ptr));
++
++PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++   png_infop info_ptr));
++
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
++   png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
++   png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
++   png_byte *blend_op));
++
++PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
++   png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++   png_byte blend_op));
++
++PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
++   (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
++   png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++   png_progressive_frame_ptr frame_info_fn,
++   png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
++   png_infop info_ptr, png_bytepp row_pointers,
++   png_uint_32 width, png_uint_32 height,
++   png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++   png_byte blend_op));
++
++PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
++   png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+ 
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+  * defs, and in scripts/symbols.def.
+@@ -3235,7 +3326,11 @@
+  * one to use is one more than this.)
+  */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++  PNG_EXPORT_LAST_ORDINAL(269);
++#else
+   PNG_EXPORT_LAST_ORDINAL(249);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+ 
+ #ifdef __cplusplus
+diff -Naru libpng-1.6.40.org/pngget.c libpng-1.6.40/pngget.c
+--- libpng-1.6.40.org/pngget.c	2023-09-10 11:09:32.954139030 +0900
++++ libpng-1.6.40/pngget.c	2023-09-10 11:08:58.922075757 +0900
+@@ -1257,4 +1257,166 @@
+ #  endif
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++             png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++    png_debug1(1, "in %s retrieval function", "acTL");
++
++    if (png_ptr != NULL && info_ptr != NULL &&
++        (info_ptr->valid & PNG_INFO_acTL) &&
++        num_frames != NULL && num_plays != NULL)
++    {
++        *num_frames = info_ptr->num_frames;
++        *num_plays = info_ptr->num_plays;
++        return (1);
++    }
++
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_num_frames()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->num_frames);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_num_plays()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->num_plays);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++             png_uint_32 *width, png_uint_32 *height,
++             png_uint_32 *x_offset, png_uint_32 *y_offset,
++             png_uint_16 *delay_num, png_uint_16 *delay_den,
++             png_byte *dispose_op, png_byte *blend_op)
++{
++    png_debug1(1, "in %s retrieval function", "fcTL");
++
++    if (png_ptr != NULL && info_ptr != NULL &&
++        (info_ptr->valid & PNG_INFO_fcTL) &&
++        width != NULL && height != NULL &&
++        x_offset != NULL && y_offset != NULL &&
++        delay_num != NULL && delay_den != NULL &&
++        dispose_op != NULL && blend_op != NULL)
++    {
++        *width = info_ptr->next_frame_width;
++        *height = info_ptr->next_frame_height;
++        *x_offset = info_ptr->next_frame_x_offset;
++        *y_offset = info_ptr->next_frame_y_offset;
++        *delay_num = info_ptr->next_frame_delay_num;
++        *delay_den = info_ptr->next_frame_delay_den;
++        *dispose_op = info_ptr->next_frame_dispose_op;
++        *blend_op = info_ptr->next_frame_blend_op;
++        return (1);
++    }
++
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_width()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_width);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_height()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_height);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_x_offset()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_x_offset);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_y_offset()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_y_offset);
++    return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_delay_num()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_delay_num);
++    return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_delay_den()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_delay_den);
++    return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_dispose_op()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_dispose_op);
++    return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_blend_op()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_blend_op);
++    return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_first_frame_is_hidden()");
++
++    if (png_ptr != NULL)
++       return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++    PNG_UNUSED(info_ptr)
++
++    return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* READ || WRITE */
+diff -Naru libpng-1.6.40.org/pnginfo.h libpng-1.6.40/pnginfo.h
+--- libpng-1.6.40.org/pnginfo.h	2022-11-24 08:37:51.507052183 +0900
++++ libpng-1.6.40/pnginfo.h	2023-09-10 11:08:58.922075757 +0900
+@@ -263,5 +263,18 @@
+    png_bytepp row_pointers;        /* the image bits */
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++   png_uint_32 num_frames; /* including default image */
++   png_uint_32 num_plays;
++   png_uint_32 next_frame_width;
++   png_uint_32 next_frame_height;
++   png_uint_32 next_frame_x_offset;
++   png_uint_32 next_frame_y_offset;
++   png_uint_16 next_frame_delay_num;
++   png_uint_16 next_frame_delay_den;
++   png_byte next_frame_dispose_op;
++   png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Naru libpng-1.6.40.org/pngpread.c libpng-1.6.40/pngpread.c
+--- libpng-1.6.40.org/pngpread.c	2022-11-24 08:37:51.507052183 +0900
++++ libpng-1.6.40/pngpread.c	2023-09-10 11:08:58.922075757 +0900
+@@ -195,6 +195,106 @@
+ 
+    chunk_name = png_ptr->chunk_name;
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++   if (png_ptr->num_frames_read > 0 &&
++       png_ptr->num_frames_read < info_ptr->num_frames)
++   {
++      if (chunk_name == png_IDAT)
++      {
++         /* Discard trailing IDATs for the first frame */
++         if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++            png_error(png_ptr, "out of place IDAT");
++
++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++
++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++         return;
++      }
++      else if (chunk_name == png_fdAT)
++      {
++         if (png_ptr->buffer_size < 4)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++
++         png_ensure_sequence_number(png_ptr, 4);
++
++         if (!(png_ptr->mode & PNG_HAVE_fcTL))
++         {
++            /* Discard trailing fdATs for frames other than the first */
++            if (png_ptr->num_frames_read < 2)
++               png_error(png_ptr, "out of place fdAT");
++
++            if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++            {
++               png_push_save_buffer(png_ptr);
++               return;
++            }
++
++            png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++            return;
++         }
++
++         else
++         {
++            /* frame data follows */
++            png_ptr->idat_size = png_ptr->push_length - 4;
++            png_ptr->mode |= PNG_HAVE_IDAT;
++            png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++            return;
++         }
++      }
++
++      else if (chunk_name == png_fcTL)
++      {
++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++
++         png_read_reset(png_ptr);
++         png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++         png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++         if (!(png_ptr->mode & PNG_HAVE_fcTL))
++            png_error(png_ptr, "missing required fcTL chunk");
++
++         png_read_reinit(png_ptr, info_ptr);
++         png_progressive_read_reset(png_ptr);
++
++         if (png_ptr->frame_info_fn != NULL)
++            (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++         return;
++      }
++
++      else
++      {
++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++         png_warning(png_ptr, "Skipped (ignored) a chunk "
++                              "between APNG chunks");
++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++         return;
++      }
++
++      return;
++   }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+    if (chunk_name == png_IDAT)
+    {
+       if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+@@ -261,6 +361,9 @@
+ 
+    else if (chunk_name == png_IDAT)
+    {
++#ifdef PNG_READ_APNG_SUPPORTED
++      png_have_info(png_ptr, info_ptr);
++#endif
+       png_ptr->idat_size = png_ptr->push_length;
+       png_ptr->process_mode = PNG_READ_IDAT_MODE;
+       png_push_have_info(png_ptr, info_ptr);
+@@ -406,6 +509,30 @@
+       png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+    }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++   else if (chunk_name == png_acTL)
++   {
++      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++      {
++         png_push_save_buffer(png_ptr);
++         return;
++      }
++
++      png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++   }
++
++   else if (chunk_name == png_fcTL)
++   {
++      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++      {
++         png_push_save_buffer(png_ptr);
++         return;
++      }
++
++      png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++   }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+ 
+    else
+    {
+@@ -539,7 +666,11 @@
+       png_byte chunk_tag[4];
+ 
+       /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++      PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+       PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+       png_push_fill_buffer(png_ptr, chunk_length, 4);
+       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+       png_reset_crc(png_ptr);
+@@ -547,17 +678,64 @@
+       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++      if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++      {
++          if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++          {
++              png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++              if (png_ptr->frame_end_fn != NULL)
++                 (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++              png_ptr->num_frames_read++;
++              return;
++          }
++          else
++          {
++              if (png_ptr->chunk_name == png_IEND)
++                  png_error(png_ptr, "Not enough image data");
++              if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++              {
++                 png_push_save_buffer(png_ptr);
++                 return;
++              }
++              png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++                                   "APNG chunks");
++              png_crc_finish(png_ptr, png_ptr->push_length);
++              png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++              return;
++          }
++      }
++      else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++      if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+       if (png_ptr->chunk_name != png_IDAT)
++#endif
+       {
+          png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ 
+          if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+             png_error(png_ptr, "Not enough compressed data");
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++         if (png_ptr->frame_end_fn != NULL)
++            (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++         png_ptr->num_frames_read++;
++#endif
++
+          return;
+       }
+ 
+       png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++      if (png_ptr->num_frames_read > 0)
++      {
++         png_ensure_sequence_number(png_ptr, 4);
++         png_ptr->idat_size -= 4;
++      }
++#endif
+    }
+ 
+    if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
+@@ -631,6 +809,15 @@
+    if (!(buffer_length > 0) || buffer == NULL)
+       png_error(png_ptr, "No IDAT data (internal error)");
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++   /* If the app is not APNG-aware, decode only the first frame */
++   if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++   {
++     png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++     return;
++   }
++#endif
++
+    /* This routine must process all the data it has been given
+     * before returning, calling the row callback as required to
+     * handle the uncompressed results.
+@@ -1085,6 +1272,18 @@
+    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++   png_progressive_frame_ptr frame_info_fn,
++   png_progressive_frame_ptr frame_end_fn)
++{
++   png_ptr->frame_info_fn = frame_info_fn;
++   png_ptr->frame_end_fn = frame_end_fn;
++   png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Naru libpng-1.6.40.org/pngpriv.h libpng-1.6.40/pngpriv.h
+--- libpng-1.6.40.org/pngpriv.h	2023-09-10 11:09:32.954139030 +0900
++++ libpng-1.6.40/pngpriv.h	2023-09-10 11:08:58.923075759 +0900
+@@ -628,6 +628,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
+ #define PNG_WROTE_eXIf            0x4000U
+ #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL            0x10000U
++#define PNG_HAVE_fcTL            0x20000U
++#endif
+ 
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR                 0x0001U
+@@ -864,6 +868,16 @@
+ #define png_tRNS PNG_U32(116,  82,  78,  83)
+ #define png_zTXt PNG_U32(122,  84,  88, 116)
+ 
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97,  99,  84,  76)
++#define png_fcTL PNG_U32(102,  99,  84,  76)
++#define png_fdAT PNG_U32(102, 100,  65,  84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN       0x0001U
++#define PNG_APNG_APP                 0x0002U
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+  * macro will fail on top-bit-set values because of the sign extension.
+  */
+@@ -1635,6 +1649,47 @@
+     */
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
++   png_uint_32 width, png_uint_32 height,
++   png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den,
++   png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
++   png_infop info_ptr),PNG_EMPTY);
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
++   png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
++   png_uint_32 width, png_uint_32 height,
++   png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den,
++   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
++   png_const_bytep data, png_size_t length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
++   png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Naru libpng-1.6.40.org/pngread.c libpng-1.6.40/pngread.c
+--- libpng-1.6.40.org/pngread.c	2022-11-24 08:37:51.508052181 +0900
++++ libpng-1.6.40/pngread.c	2023-09-10 11:08:58.923075759 +0900
+@@ -161,6 +161,9 @@
+ 
+       else if (chunk_name == png_IDAT)
+       {
++#ifdef PNG_READ_APNG_SUPPORTED
++         png_have_info(png_ptr, info_ptr);
++#endif
+          png_ptr->idat_size = length;
+          break;
+       }
+@@ -255,6 +258,17 @@
+          png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++      else if (chunk_name == png_acTL)
++         png_handle_acTL(png_ptr, info_ptr, length);
++
++      else if (chunk_name == png_fcTL)
++         png_handle_fcTL(png_ptr, info_ptr, length);
++
++      else if (chunk_name == png_fdAT)
++         png_handle_fdAT(png_ptr, info_ptr, length);
++#endif
++
+       else
+          png_handle_unknown(png_ptr, info_ptr, length,
+              PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -262,6 +276,72 @@
+ }
+ #endif /* SEQUENTIAL_READ */
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++    png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++    png_debug(0, "Reading frame head");
++
++    if (!(png_ptr->mode & PNG_HAVE_acTL))
++        png_error(png_ptr, "attempt to png_read_frame_head() but "
++                           "no acTL present");
++
++    /* do nothing for the main IDAT */
++    if (png_ptr->num_frames_read == 0)
++        return;
++
++    png_read_reset(png_ptr);
++    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++    png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++    have_chunk_after_DAT = 0;
++    for (;;)
++    {
++        png_uint_32 length = png_read_chunk_header(png_ptr);
++
++        if (png_ptr->chunk_name == png_IDAT)
++        {
++            /* discard trailing IDATs for the first frame */
++            if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++                png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++            png_crc_finish(png_ptr, length);
++        }
++
++        else if (png_ptr->chunk_name == png_fcTL)
++        {
++            png_handle_fcTL(png_ptr, info_ptr, length);
++            have_chunk_after_DAT = 1;
++        }
++
++        else if (png_ptr->chunk_name == png_fdAT)
++        {
++            png_ensure_sequence_number(png_ptr, length);
++
++            /* discard trailing fdATs for frames other than the first */
++            if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++                png_crc_finish(png_ptr, length - 4);
++            else if(png_ptr->mode & PNG_HAVE_fcTL)
++            {
++                png_ptr->idat_size = length - 4;
++                png_ptr->mode |= PNG_HAVE_IDAT;
++
++                break;
++            }
++            else
++                png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++        }
++        else
++        {
++            png_warning(png_ptr, "Skipped (ignored) a chunk "
++                                 "between APNG chunks");
++            png_crc_finish(png_ptr, length);
++        }
++    }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Naru libpng-1.6.40.org/pngrutil.c libpng-1.6.40/pngrutil.c
+--- libpng-1.6.40.org/pngrutil.c	2022-11-24 08:37:51.510052177 +0900
++++ libpng-1.6.40/pngrutil.c	2023-09-10 11:08:58.923075759 +0900
+@@ -864,6 +864,11 @@
+    filter_type = buf[11];
+    interlace_type = buf[12];
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++   png_ptr->first_frame_width = width;
++   png_ptr->first_frame_height = height;
++#endif
++
+    /* Set internal variables */
+    png_ptr->width = width;
+    png_ptr->height = height;
+@@ -2858,6 +2863,179 @@
+ }
+ #endif
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++void /* PRIVATE */
++png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++    png_byte data[8];
++    png_uint_32 num_frames;
++    png_uint_32 num_plays;
++    png_uint_32 didSet;
++
++    png_debug(1, "in png_handle_acTL");
++
++    if (!(png_ptr->mode & PNG_HAVE_IHDR))
++    {
++        png_error(png_ptr, "Missing IHDR before acTL");
++    }
++    else if (png_ptr->mode & PNG_HAVE_IDAT)
++    {
++        png_warning(png_ptr, "Invalid acTL after IDAT skipped");
++        png_crc_finish(png_ptr, length);
++        return;
++    }
++    else if (png_ptr->mode & PNG_HAVE_acTL)
++    {
++        png_warning(png_ptr, "Duplicate acTL skipped");
++        png_crc_finish(png_ptr, length);
++        return;
++    }
++    else if (length != 8)
++    {
++        png_warning(png_ptr, "acTL with invalid length skipped");
++        png_crc_finish(png_ptr, length);
++        return;
++    }
++
++    png_crc_read(png_ptr, data, 8);
++    png_crc_finish(png_ptr, 0);
++
++    num_frames = png_get_uint_31(png_ptr, data);
++    num_plays = png_get_uint_31(png_ptr, data + 4);
++
++    /* the set function will do error checking on num_frames */
++    didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
++    if(didSet)
++        png_ptr->mode |= PNG_HAVE_acTL;
++}
++
++void /* PRIVATE */
++png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++    png_byte data[22];
++    png_uint_32 width;
++    png_uint_32 height;
++    png_uint_32 x_offset;
++    png_uint_32 y_offset;
++    png_uint_16 delay_num;
++    png_uint_16 delay_den;
++    png_byte dispose_op;
++    png_byte blend_op;
++
++    png_debug(1, "in png_handle_fcTL");
++
++    png_ensure_sequence_number(png_ptr, length);
++
++    if (!(png_ptr->mode & PNG_HAVE_IHDR))
++    {
++        png_error(png_ptr, "Missing IHDR before fcTL");
++    }
++    else if (png_ptr->mode & PNG_HAVE_IDAT)
++    {
++        /* for any frames other then the first this message may be misleading,
++        * but correct. PNG_HAVE_IDAT is unset before the frame head is read
++        * i can't think of a better message */
++        png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
++        png_crc_finish(png_ptr, length-4);
++        return;
++    }
++    else if (png_ptr->mode & PNG_HAVE_fcTL)
++    {
++        png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
++        png_crc_finish(png_ptr, length-4);
++        return;
++    }
++    else if (length != 26)
++    {
++        png_warning(png_ptr, "fcTL with invalid length skipped");
++        png_crc_finish(png_ptr, length-4);
++        return;
++    }
++
++    png_crc_read(png_ptr, data, 22);
++    png_crc_finish(png_ptr, 0);
++
++    width = png_get_uint_31(png_ptr, data);
++    height = png_get_uint_31(png_ptr, data + 4);
++    x_offset = png_get_uint_31(png_ptr, data + 8);
++    y_offset = png_get_uint_31(png_ptr, data + 12);
++    delay_num = png_get_uint_16(data + 16);
++    delay_den = png_get_uint_16(data + 18);
++    dispose_op = data[20];
++    blend_op = data[21];
++
++    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
++    {
++        png_warning(png_ptr, "fcTL for the first frame must have zero offset");
++        return;
++    }
++
++    if (info_ptr != NULL)
++    {
++        if (png_ptr->num_frames_read == 0 &&
++            (width != info_ptr->width || height != info_ptr->height))
++        {
++            png_warning(png_ptr, "size in first frame's fcTL must match "
++                               "the size in IHDR");
++            return;
++        }
++
++        /* The set function will do more error checking */
++        png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
++                                x_offset, y_offset, delay_num, delay_den,
++                                dispose_op, blend_op);
++
++        png_read_reinit(png_ptr, info_ptr);
++
++        png_ptr->mode |= PNG_HAVE_fcTL;
++    }
++}
++
++void /* PRIVATE */
++png_have_info(png_structp png_ptr, png_infop info_ptr)
++{
++    if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
++    {
++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++        info_ptr->num_frames++;
++    }
++}
++
++void /* PRIVATE */
++png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++    png_ensure_sequence_number(png_ptr, length);
++
++    /* This function is only called from png_read_end(), png_read_info(),
++    * and png_push_read_chunk() which means that:
++    * - the user doesn't want to read this frame
++    * - or this is an out-of-place fdAT
++    * in either case it is safe to ignore the chunk with a warning */
++    png_warning(png_ptr, "ignoring fdAT chunk");
++    png_crc_finish(png_ptr, length - 4);
++    PNG_UNUSED(info_ptr)
++}
++
++void /* PRIVATE */
++png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
++{
++    png_byte data[4];
++    png_uint_32 sequence_number;
++
++    if (length < 4)
++        png_error(png_ptr, "invalid fcTL or fdAT chunk found");
++
++    png_crc_read(png_ptr, data, 4);
++    sequence_number = png_get_uint_31(png_ptr, data);
++
++    if (sequence_number != png_ptr->next_seq_num)
++        png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
++                           "number found");
++
++    png_ptr->next_seq_num++;
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
+ static int
+@@ -4166,7 +4344,38 @@
+       {
+          uInt avail_in;
+          png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++         png_uint_32 bytes_to_skip = 0;
++
++         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++         {
++            png_crc_finish(png_ptr, bytes_to_skip);
++            bytes_to_skip = 0;
+ 
++            png_ptr->idat_size = png_read_chunk_header(png_ptr);
++            if (png_ptr->num_frames_read == 0)
++            {
++               if (png_ptr->chunk_name != png_IDAT)
++                  png_error(png_ptr, "Not enough image data");
++            }
++            else
++            {
++               if (png_ptr->chunk_name == png_IEND)
++                  png_error(png_ptr, "Not enough image data");
++               if (png_ptr->chunk_name != png_fdAT)
++               {
++                  png_warning(png_ptr, "Skipped (ignored) a chunk "
++                                       "between APNG chunks");
++                  bytes_to_skip = png_ptr->idat_size;
++                  continue;
++               }
++
++               png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++               png_ptr->idat_size -= 4;
++            }
++         }
++#else
+          while (png_ptr->idat_size == 0)
+          {
+             png_crc_finish(png_ptr, 0);
+@@ -4178,7 +4387,7 @@
+             if (png_ptr->chunk_name != png_IDAT)
+                png_error(png_ptr, "Not enough image data");
+          }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+          avail_in = png_ptr->IDAT_read_size;
+ 
+          if (avail_in > png_ptr->idat_size)
+@@ -4241,6 +4450,9 @@
+ 
+          png_ptr->mode |= PNG_AFTER_IDAT;
+          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++         png_ptr->num_frames_read++;
++#endif
+ 
+          if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+             png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4678,4 +4890,80 @@
+ 
+    png_ptr->flags |= PNG_FLAG_ROW_INIT;
+ }
++
++#ifdef PNG_READ_APNG_SUPPORTED
++/* This function is to be called after the main IDAT set has been read and
++ * before a new IDAT is read. It resets some parts of png_ptr
++ * to make them usable by the read functions again */
++void /* PRIVATE */
++png_read_reset(png_structp png_ptr)
++{
++    png_ptr->mode &= ~PNG_HAVE_IDAT;
++    png_ptr->mode &= ~PNG_AFTER_IDAT;
++    png_ptr->row_number = 0;
++    png_ptr->pass = 0;
++}
++
++void /* PRIVATE */
++png_read_reinit(png_structp png_ptr, png_infop info_ptr)
++{
++    png_ptr->width = info_ptr->next_frame_width;
++    png_ptr->height = info_ptr->next_frame_height;
++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
++    png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
++        png_ptr->width);
++    if (png_ptr->prev_row)
++        memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
++}
++
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++/* same as png_read_reset() but for the progressive reader */
++void /* PRIVATE */
++png_progressive_read_reset(png_structp png_ptr)
++{
++#ifdef PNG_READ_INTERLACING_SUPPORTED
++   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
++
++   /* Start of interlace block */
++    const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
++
++    /* Offset to next interlace block */
++    const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
++
++    /* Start of interlace block in the y direction */
++    const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
++
++    /* Offset to next interlace block in the y direction */
++    const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
++
++    if (png_ptr->interlaced)
++    {
++        if (!(png_ptr->transformations & PNG_INTERLACE))
++            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
++                                png_pass_ystart[0]) / png_pass_yinc[0];
++        else
++            png_ptr->num_rows = png_ptr->height;
++
++        png_ptr->iwidth = (png_ptr->width +
++                           png_pass_inc[png_ptr->pass] - 1 -
++                           png_pass_start[png_ptr->pass]) /
++                           png_pass_inc[png_ptr->pass];
++    }
++    else
++#endif /* PNG_READ_INTERLACING_SUPPORTED */
++    {
++        png_ptr->num_rows = png_ptr->height;
++        png_ptr->iwidth = png_ptr->width;
++    }
++    png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
++    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
++        png_error(png_ptr, "inflateReset failed");
++    png_ptr->zstream.avail_in = 0;
++    png_ptr->zstream.next_in = 0;
++    png_ptr->zstream.next_out = png_ptr->row_buf;
++    png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
++        png_ptr->iwidth) + 1;
++}
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
+ #endif /* READ */
+diff -Naru libpng-1.6.40.org/pngset.c libpng-1.6.40/pngset.c
+--- libpng-1.6.40.org/pngset.c	2023-09-10 11:09:32.954139030 +0900
++++ libpng-1.6.40/pngset.c	2023-09-10 11:08:58.932075775 +0900
+@@ -280,6 +280,11 @@
+    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+ 
+    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
++
++#ifdef PNG_APNG_SUPPORTED
++   /* for non-animated png. this may be overwritten from an acTL chunk later */
++   info_ptr->num_frames = 1;
++#endif
+ }
+ 
+ #ifdef PNG_oFFs_SUPPORTED
+@@ -1149,6 +1154,147 @@
+ }
+ #endif /* sPLT */
+ 
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
++    png_uint_32 num_frames, png_uint_32 num_plays)
++{
++    png_debug1(1, "in %s storage function", "acTL");
++
++    if (png_ptr == NULL || info_ptr == NULL)
++    {
++        png_warning(png_ptr,
++                    "Call to png_set_acTL() with NULL png_ptr "
++                    "or info_ptr ignored");
++        return (0);
++    }
++    if (num_frames == 0)
++    {
++        png_warning(png_ptr,
++                    "Ignoring attempt to set acTL with num_frames zero");
++        return (0);
++    }
++    if (num_frames > PNG_UINT_31_MAX)
++    {
++        png_warning(png_ptr,
++                    "Ignoring attempt to set acTL with num_frames > 2^31-1");
++        return (0);
++    }
++    if (num_plays > PNG_UINT_31_MAX)
++    {
++        png_warning(png_ptr,
++                    "Ignoring attempt to set acTL with num_plays "
++                    "> 2^31-1");
++        return (0);
++    }
++
++    info_ptr->num_frames = num_frames;
++    info_ptr->num_plays = num_plays;
++
++    info_ptr->valid |= PNG_INFO_acTL;
++
++    return (1);
++}
++
++/* delay_num and delay_den can hold any 16-bit values including zero */
++png_uint_32 PNGAPI
++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++    png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den,
++    png_byte dispose_op, png_byte blend_op)
++{
++    png_debug1(1, "in %s storage function", "fcTL");
++
++    if (png_ptr == NULL || info_ptr == NULL)
++    {
++        png_warning(png_ptr,
++                    "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
++                    "ignored");
++        return (0);
++    }
++
++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++                             delay_num, delay_den, dispose_op, blend_op);
++
++    if (blend_op == PNG_BLEND_OP_OVER)
++    {
++        if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
++            !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
++        {
++          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
++                               "and wasteful for opaque images, ignored");
++          blend_op = PNG_BLEND_OP_SOURCE;
++        }
++    }
++
++    info_ptr->next_frame_width = width;
++    info_ptr->next_frame_height = height;
++    info_ptr->next_frame_x_offset = x_offset;
++    info_ptr->next_frame_y_offset = y_offset;
++    info_ptr->next_frame_delay_num = delay_num;
++    info_ptr->next_frame_delay_den = delay_den;
++    info_ptr->next_frame_dispose_op = dispose_op;
++    info_ptr->next_frame_blend_op = blend_op;
++
++    info_ptr->valid |= PNG_INFO_fcTL;
++
++    return (1);
++}
++
++void /* PRIVATE */
++png_ensure_fcTL_is_valid(png_structp png_ptr,
++    png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den,
++    png_byte dispose_op, png_byte blend_op)
++{
++    if (width == 0 || width > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
++    if (height == 0 || height > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
++    if (x_offset > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
++    if (y_offset > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
++    if (width + x_offset > png_ptr->first_frame_width ||
++        height + y_offset > png_ptr->first_frame_height)
++        png_error(png_ptr, "dimensions of a frame are greater than"
++                           "the ones in IHDR");
++
++    if (dispose_op != PNG_DISPOSE_OP_NONE &&
++        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
++        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
++        png_error(png_ptr, "invalid dispose_op in fcTL");
++
++    if (blend_op != PNG_BLEND_OP_SOURCE &&
++        blend_op != PNG_BLEND_OP_OVER)
++        png_error(png_ptr, "invalid blend_op in fcTL");
++
++    PNG_UNUSED(delay_num)
++    PNG_UNUSED(delay_den)
++}
++
++png_uint_32 PNGAPI
++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
++                              png_byte is_hidden)
++{
++    png_debug(1, "in png_first_frame_is_hidden()");
++
++    if (png_ptr == NULL)
++        return 0;
++
++    if (is_hidden)
++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++    else
++        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
++
++    PNG_UNUSED(info_ptr)
++
++    return 1;
++}
++#endif /* PNG_APNG_SUPPORTED */
++
+ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ static png_byte
+ check_location(png_const_structrp png_ptr, int location)
+diff -Naru libpng-1.6.40.org/pngstruct.h libpng-1.6.40/pngstruct.h
+--- libpng-1.6.40.org/pngstruct.h	2022-11-24 08:37:51.510052177 +0900
++++ libpng-1.6.40/pngstruct.h	2023-09-10 11:08:58.924075760 +0900
+@@ -399,6 +399,27 @@
+    png_byte filter_type;
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++   png_uint_32 apng_flags;
++   png_uint_32 next_seq_num;         /* next fcTL/fdAT chunk sequence number */
++   png_uint_32 first_frame_width;
++   png_uint_32 first_frame_height;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++   png_uint_32 num_frames_read;      /* incremented after all image data of */
++                                     /* a frame is read */
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++   png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
++   png_progressive_frame_ptr frame_end_fn;  /* frame data read callback */
++#endif
++#endif
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++   png_uint_32 num_frames_to_write;
++   png_uint_32 num_frames_written;
++#endif
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* New members added in libpng-1.2.0 */
+ 
+ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+diff -Naru libpng-1.6.40.org/pngtest.c libpng-1.6.40/pngtest.c
+--- libpng-1.6.40.org/pngtest.c	2023-09-10 11:12:23.044481879 +0900
++++ libpng-1.6.40/pngtest.c	2023-09-10 11:08:58.924075760 +0900
+@@ -875,6 +875,10 @@
+    volatile int num_passes;
+    int pass;
+    int bit_depth, color_type;
++#ifdef PNG_APNG_SUPPORTED
++   png_uint_32 num_frames;
++   png_uint_32 num_plays;
++#endif
+ 
+    row_buf = NULL;
+    error_parameters.file_name = inname;
+@@ -1383,6 +1387,22 @@
+       }
+    }
+ #endif
++
++#ifdef PNG_APNG_SUPPORTED
++   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++   {
++      if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
++      {
++         png_byte is_hidden;
++         pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
++                    num_frames, num_plays);
++         png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
++         is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
++         png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
++      }
++   }
++#endif
++
+ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+    {
+       png_unknown_chunkp unknowns;
+@@ -1463,6 +1483,110 @@
+    t_misc += (t_stop - t_start);
+    t_start = t_stop;
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++   {
++      png_uint_32 frame;
++      for (frame = 0; frame < num_frames; frame++)
++      {
++         png_uint_32 frame_width;
++         png_uint_32 frame_height;
++         png_uint_32 x_offset;
++         png_uint_32 y_offset;
++         png_uint_16 delay_num;
++         png_uint_16 delay_den;
++         png_byte dispose_op;
++         png_byte blend_op;
++         png_read_frame_head(read_ptr, read_info_ptr);
++         if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
++         {
++            png_get_next_frame_fcTL(read_ptr, read_info_ptr,
++                                    &frame_width, &frame_height,
++                                    &x_offset, &y_offset,
++                                    &delay_num, &delay_den,
++                                    &dispose_op, &blend_op);
++         }
++         else
++         {
++            frame_width = width;
++            frame_height = height;
++            x_offset = 0;
++            y_offset = 0;
++            delay_num = 1;
++            delay_den = 1;
++            dispose_op = PNG_DISPOSE_OP_NONE;
++            blend_op = PNG_BLEND_OP_SOURCE;
++         }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++         png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
++                              frame_width, frame_height,
++                              x_offset, y_offset,
++                              delay_num, delay_den,
++                              dispose_op, blend_op);
++#endif
++         for (pass = 0; pass < num_passes; pass++)
++         {
++#           ifdef calc_pass_height
++               png_uint_32 pass_height;
++
++               if (num_passes == 7) /* interlaced */
++               {
++                  if (PNG_PASS_COLS(frame_width, pass) > 0)
++                     pass_height = PNG_PASS_ROWS(frame_height, pass);
++
++                  else
++                     pass_height = 0;
++               }
++
++               else /* not interlaced */
++                  pass_height = frame_height;
++#           else
++#              define pass_height frame_height
++#           endif
++
++            pngtest_debug1("Writing row data for pass %d", pass);
++            for (y = 0; y < pass_height; y++)
++            {
++#ifndef SINGLE_ROWBUF_ALLOC
++               pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
++
++               row_buf = (png_bytep)png_malloc(read_ptr,
++                  png_get_rowbytes(read_ptr, read_info_ptr));
++
++               pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
++                  (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
++
++#endif /* !SINGLE_ROWBUF_ALLOC */
++               png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
++
++#ifdef PNG_WRITE_SUPPORTED
++#ifdef PNGTEST_TIMING
++               t_stop = (float)clock();
++               t_decode += (t_stop - t_start);
++               t_start = t_stop;
++#endif
++               png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
++#ifdef PNGTEST_TIMING
++               t_stop = (float)clock();
++               t_encode += (t_stop - t_start);
++               t_start = t_stop;
++#endif
++#endif /* PNG_WRITE_SUPPORTED */
++
++#ifndef SINGLE_ROWBUF_ALLOC
++               pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
++               png_free(read_ptr, row_buf);
++               row_buf = NULL;
++#endif /* !SINGLE_ROWBUF_ALLOC */
++            }
++         }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++         png_write_frame_tail(write_ptr, write_info_ptr);
++#endif
++      }
++   }
++   else
++#endif
+    for (pass = 0; pass < num_passes; pass++)
+    {
+ #     ifdef calc_pass_height
+diff -Naru libpng-1.6.40.org/pngwrite.c libpng-1.6.40/pngwrite.c
+--- libpng-1.6.40.org/pngwrite.c	2023-09-10 11:09:32.955139032 +0900
++++ libpng-1.6.40/pngwrite.c	2023-09-10 11:08:58.924075760 +0900
+@@ -128,6 +128,10 @@
+        * the application continues writing the PNG.  So check the 'invalid'
+        * flag here too.
+        */
++#ifdef PNG_WRITE_APNG_SUPPORTED
++      if (info_ptr->valid & PNG_INFO_acTL)
++         png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
++#endif
+ #ifdef PNG_GAMMA_SUPPORTED
+ #  ifdef PNG_WRITE_gAMA_SUPPORTED
+       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
+@@ -373,6 +377,11 @@
+       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+ #endif
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
++      png_error(png_ptr, "Not enough frames written");
++#endif
++
+    /* See if user wants us to write information chunks */
+    if (info_ptr != NULL)
+    {
+@@ -1475,6 +1484,43 @@
+ }
+ #endif
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void PNGAPI
++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
++    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++    png_byte blend_op)
++{
++    png_debug(1, "in png_write_frame_head");
++
++    /* there is a chance this has been set after png_write_info was called,
++    * so it would be set but not written. is there a way to be sure? */
++    if (!(info_ptr->valid & PNG_INFO_acTL))
++        png_error(png_ptr, "png_write_frame_head(): acTL not set");
++
++    png_write_reset(png_ptr);
++
++    png_write_reinit(png_ptr, info_ptr, width, height);
++
++    if ( !(png_ptr->num_frames_written == 0 &&
++           (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
++        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
++                       delay_num, delay_den, dispose_op, blend_op);
++
++    PNG_UNUSED(row_pointers)
++}
++
++void PNGAPI
++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_write_frame_tail");
++
++    png_ptr->num_frames_written++;
++
++    PNG_UNUSED(info_ptr)
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ 
+ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ /* Initialize the write structure - general purpose utility. */
+diff -Naru libpng-1.6.40.org/pngwutil.c libpng-1.6.40/pngwutil.c
+--- libpng-1.6.40.org/pngwutil.c	2022-11-24 08:37:51.511052176 +0900
++++ libpng-1.6.40/pngwutil.c	2023-09-10 11:08:58.952075811 +0900
+@@ -821,6 +821,11 @@
+    /* Write the chunk */
+    png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++   png_ptr->first_frame_width = width;
++   png_ptr->first_frame_height = height;
++#endif
++
+    if ((png_ptr->do_filter) == PNG_NO_FILTERS)
+    {
+       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+@@ -1002,8 +1007,17 @@
+                optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+ 
+-         if (size > 0)
+-            png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++            if (size > 0)
++#ifdef PNG_WRITE_APNG_SUPPORTED
++            {
++               if (png_ptr->num_frames_written == 0)
++#endif
++               png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++#ifdef PNG_WRITE_APNG_SUPPORTED
++               else
++                  png_write_fdAT(png_ptr, data, size);
++            }
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+          png_ptr->mode |= PNG_HAVE_IDAT;
+ 
+          png_ptr->zstream.next_out = data;
+@@ -1050,7 +1064,17 @@
+ #endif
+ 
+          if (size > 0)
++#ifdef PNG_WRITE_APNG_SUPPORTED
++         {
++            if (png_ptr->num_frames_written == 0)
++#endif
+             png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++#ifdef PNG_WRITE_APNG_SUPPORTED
++            else
++               png_write_fdAT(png_ptr, data, size);
++         }
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+          png_ptr->zstream.avail_out = 0;
+          png_ptr->zstream.next_out = NULL;
+          png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+@@ -1885,6 +1909,82 @@
+ }
+ #endif
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_acTL(png_structp png_ptr,
++    png_uint_32 num_frames, png_uint_32 num_plays)
++{
++    png_byte buf[8];
++
++    png_debug(1, "in png_write_acTL");
++
++    png_ptr->num_frames_to_write = num_frames;
++
++    if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
++        num_frames--;
++
++    png_save_uint_32(buf, num_frames);
++    png_save_uint_32(buf + 4, num_plays);
++
++    png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
++}
++
++void /* PRIVATE */
++png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++    png_byte blend_op)
++{
++    png_byte buf[26];
++
++    png_debug(1, "in png_write_fcTL");
++
++    if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
++        png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
++    if (png_ptr->num_frames_written == 0 &&
++        (width != png_ptr->first_frame_width ||
++         height != png_ptr->first_frame_height))
++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
++                           "don't match the ones in IHDR");
++
++    /* more error checking */
++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++                             delay_num, delay_den, dispose_op, blend_op);
++
++    png_save_uint_32(buf, png_ptr->next_seq_num);
++    png_save_uint_32(buf + 4, width);
++    png_save_uint_32(buf + 8, height);
++    png_save_uint_32(buf + 12, x_offset);
++    png_save_uint_32(buf + 16, y_offset);
++    png_save_uint_16(buf + 20, delay_num);
++    png_save_uint_16(buf + 22, delay_den);
++    buf[24] = dispose_op;
++    buf[25] = blend_op;
++
++    png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
++
++    png_ptr->next_seq_num++;
++}
++
++void /* PRIVATE */
++png_write_fdAT(png_structp png_ptr,
++    png_const_bytep data, png_size_t length)
++{
++    png_byte buf[4];
++
++    png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
++
++    png_save_uint_32(buf, png_ptr->next_seq_num);
++    png_write_chunk_data(png_ptr, buf, 4);
++
++    png_write_chunk_data(png_ptr, data, length);
++
++    png_write_chunk_end(png_ptr);
++
++    png_ptr->next_seq_num++;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ /* Initializes the row writing capability of libpng */
+ void /* PRIVATE */
+ png_write_start_row(png_structrp png_ptr)
+@@ -2778,4 +2878,39 @@
+    }
+ #endif /* WRITE_FLUSH */
+ }
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_reset(png_structp png_ptr)
++{
++    png_ptr->row_number = 0;
++    png_ptr->pass = 0;
++    png_ptr->mode &= ~PNG_HAVE_IDAT;
++}
++
++void /* PRIVATE */
++png_write_reinit(png_structp png_ptr, png_infop info_ptr,
++                 png_uint_32 width, png_uint_32 height)
++{
++    if (png_ptr->num_frames_written == 0 &&
++        (width != png_ptr->first_frame_width ||
++         height != png_ptr->first_frame_height))
++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
++                           "don't match the ones in IHDR");
++    if (width > png_ptr->first_frame_width ||
++        height > png_ptr->first_frame_height)
++        png_error(png_ptr, "width and/or height for a frame greater than"
++                           "the ones in IHDR");
++
++    png_set_IHDR(png_ptr, info_ptr, width, height,
++                 info_ptr->bit_depth, info_ptr->color_type,
++                 info_ptr->interlace_type, info_ptr->compression_type,
++                 info_ptr->filter_type);
++
++    png_ptr->width = width;
++    png_ptr->height = height;
++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
++    png_ptr->usr_width = png_ptr->width;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ #endif /* WRITE */
+diff -Naru libpng-1.6.40.org/scripts/symbols.def libpng-1.6.40/scripts/symbols.def
+--- libpng-1.6.40.org/scripts/symbols.def	2022-11-24 08:37:51.515052168 +0900
++++ libpng-1.6.40/scripts/symbols.def	2023-09-10 11:08:58.925075762 +0900
+@@ -253,3 +253,23 @@
+  png_set_eXIf @247
+  png_get_eXIf_1 @248
+  png_set_eXIf_1 @249
++ png_get_acTL @250
++ png_set_acTL @251
++ png_get_num_frames @252
++ png_get_num_plays @253
++ png_get_next_frame_fcTL @254
++ png_set_next_frame_fcTL @255
++ png_get_next_frame_width @256
++ png_get_next_frame_height @257
++ png_get_next_frame_x_offset @258
++ png_get_next_frame_y_offset @259
++ png_get_next_frame_delay_num @260
++ png_get_next_frame_delay_den @261
++ png_get_next_frame_dispose_op @262
++ png_get_next_frame_blend_op @263
++ png_get_first_frame_is_hidden @264
++ png_set_first_frame_is_hidden @265
++ png_read_frame_head @266
++ png_set_progressive_frame_fn @267
++ png_write_frame_head @268
++ png_write_frame_tail @269
diff --git a/thirdparty/openmpt_svn_version.h b/thirdparty/openmpt_svn_version.h
deleted file mode 100644
index a45ed9f22449e7a4164bd2a7881c5ae52f805087..0000000000000000000000000000000000000000
--- a/thirdparty/openmpt_svn_version.h
+++ /dev/null
@@ -1,10 +0,0 @@
-
-#pragma once
-#define OPENMPT_VERSION_SVNVERSION "17963"
-#define OPENMPT_VERSION_REVISION 17963
-#define OPENMPT_VERSION_DIRTY 0
-#define OPENMPT_VERSION_MIXEDREVISIONS 0
-#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.4.32"
-#define OPENMPT_VERSION_DATE "2022-09-25T14:19:05.052596Z"
-#define OPENMPT_VERSION_IS_PACKAGE 1
-
diff --git a/thirdparty/sdl2-mixer-ext.cmake b/thirdparty/sdl2-mixer-ext.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a52b11584ae747630ed4c44af6282fb8cc9dea75
--- /dev/null
+++ b/thirdparty/sdl2-mixer-ext.cmake
@@ -0,0 +1,39 @@
+if(TARGET SDL2_mixer_ext_Static)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'SDL2_mixer_ext::SDL2_mixer_ext'")
+
+set(SDL_MIXER_X_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES} CACHE BOOL "" FORCE)
+set(SDL_MIXER_X_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES} CACHE BOOL "" FORCE)
+set(SDL_MIXER_X_DISABLE_INSTALL ON CACHE BOOL "" FORCE)
+set(USE_SYSTEM_SDL2 ON CACHE BOOL "" FORCE)
+set(SDL2_INCLUDE_PATH ${SDL2_INCLUDE_DIR} CACHE PATH "" FORCE)
+set(USE_XMP OFF CACHE PATH "" FORCE)
+
+set(
+	internal_SDL2_mixer_ext_options
+		"SDL_MIXER_X_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
+		"SDL_MIXER_X_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
+		"SDL_MIXER_X_DISABLE_INSTALL ON"
+		"USE_SYSTEM_SDL2 ON"
+		"USE_XMP OFF"
+)
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	#list(APPEND internal_SDL2_mixer_ext_options "DOWNLOAD_AUDIO_CODECS_DEPENDENCY ON")
+	#set(DOWNLOAD_AUDIO_CODECS_DEPENDENCY ON CACHE BOOL "" FORCE)
+endif()
+
+include(FetchContent)
+
+
+FetchContent_Declare(
+	SDL2_mixer_ext
+	OPTIONS ${internal_SDL2_mixer_ext_options}
+	GIT_TAG "2.6.0-1"
+	GIT_REPOSITORY "https://github.com/STJr/SDL-Mixer-X.git"
+)
+
+FetchContent_MakeAvailable(SDL2_mixer_ext)
+
diff --git a/thirdparty/sdl2.cmake b/thirdparty/sdl2.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..16fbd7563b2f1c57a12a9202c3e89a69a2f9c191
--- /dev/null
+++ b/thirdparty/sdl2.cmake
@@ -0,0 +1,61 @@
+if(TARGET SDL2-static)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'SDL2::SDL2'")
+
+set(SDL_STATIC ON CACHE BOOL "" FORCE)
+set(SDL_SHARED OFF CACHE BOOL "" FORCE)
+set(SDL_TEST OFF CACHE BOOL "" FORCE)
+set(SDL2_DISABLE_INSTALL OFF CACHE BOOL "" FORCE)
+
+set(
+	internal_sdl2_options
+
+		"SDL_STATIC ON"
+		"SDL_SHARED OFF"
+		"SDL_TEST OFF"
+		"SDL2_DISABLE_INSTALL OFF"
+)
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
+	option(SDL2_DISABLE_SDL2MAIN   "Disable building/installation of SDL2main" OFF)
+	set(SDL2_DISABLE_SDL2MAIN OFF CACHE BOOL "" FORCE)
+endif()
+if(${CMAKE_SYSTEM} MATCHES Darwin)
+	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
+	option(SDL2_DISABLE_SDL2MAIN   "Disable building/installation of SDL2main" OFF)
+	set(SDL2_DISABLE_SDL2MAIN OFF CACHE BOOL "" FORCE)
+endif()
+if(${CMAKE_SYSTEM} MATCHES Linux)
+	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN ON")
+	option(SDL2_DISABLE_SDL2MAIN   "Disable building/installation of SDL2main" ON)
+	set(SDL2_DISABLE_SDL2MAIN ON CACHE BOOL "" FORCE)
+endif()
+
+include(FetchContent)
+
+if (SDL2_USE_THIRDPARTY)
+	FetchContent_Declare(
+		SDL2
+		VERSION 2.30.0
+		GITHUB_REPOSITORY "libsdl-org/SDL"
+		GIT_TAG release-2.30.0
+		OPTIONS ${internal_sdl2_options}
+		OVERRIDE_FIND_PACKAGE
+	)
+else()
+	FetchContent_Declare(
+		SDL2
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/SDL2/"
+		OPTIONS ${internal_sdl2_options}
+		OVERRIDE_FIND_PACKAGE
+	)
+endif()
+
+FetchContent_MakeAvailable(SDL2)
+
+set(SDL2_INCLUDE_DIR "${SDL2_BINARY_DIR}/include" CACHE PATH "" FORCE)
+set(SDL2_LIBRARY "${SDL2_BINARY_DIR}/SDL2-staticd.lib" CACHE PATH "" FORCE)
+set(SDL2_DIR ${SDL2_BINARY_DIR} CACHE PATH "" FORCE)
diff --git a/thirdparty/vcpkg-overlays/.placeholder b/thirdparty/vcpkg-overlays/.placeholder
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/thirdparty/zlib.cmake b/thirdparty/zlib.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..257609f775ae9f7c325665198f0e8804a5cb6030
--- /dev/null
+++ b/thirdparty/zlib.cmake
@@ -0,0 +1,36 @@
+if(TARGET ZLIB::ZLIB)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'ZLIB::ZLIB'")
+
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
+
+include(FetchContent)
+
+if (zlib_USE_THIRDPARTY)
+	FetchContent_Declare(
+		ZLIB
+		GITHUB_REPOSITORY "madler/zlib"
+		GIT_TAG v1.3.1
+		OVERRIDE_FIND_PACKAGE
+		OPTIONS
+			"ZLIB_BUILD_EXAMPLES OFF"
+	)
+else()
+	FetchContent_Declare(
+		ZLIB
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/zlib/"
+		OVERRIDE_FIND_PACKAGE
+		OPTIONS
+			"ZLIB_BUILD_EXAMPLES OFF"
+	)
+endif()
+
+FetchContent_MakeAvailable(ZLIB)
+
+
+add_library(ZLIB::ZLIB ALIAS zlibstatic)
+
+set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib" "${zlib_BINARY_DIR}" CACHE PATH "" FORCE)
+
diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json
new file mode 100644
index 0000000000000000000000000000000000000000..547114800f3088a704ec397b482c4bfed86cea3d
--- /dev/null
+++ b/vcpkg-configuration.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg-configuration.schema.json",
+  "overlay-ports": [
+    "./thirdparty/vcpkg-overlays"
+  ]
+}
diff --git a/vcpkg.json b/vcpkg.json
new file mode 100644
index 0000000000000000000000000000000000000000..07c4244ad3affde086c98bd46867ae8cd0d02b18
--- /dev/null
+++ b/vcpkg.json
@@ -0,0 +1,85 @@
+{
+  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
+  "name": "srb2",
+  "version": "1.0.0",
+  "builtin-baseline": "c823fd3e57035b10d970a96da2796a2db55e5df5",
+  "dependencies": [
+    "curl",
+    {
+      "name": "libgme",
+      "platform": "!(windows & mingw) & !native"
+    },
+    {
+      "name": "libopenmpt",
+      "platform": "!(windows & mingw)"
+    },
+    "libpng",
+    "miniupnpc",
+    "sdl2",
+    {
+      "name": "sdl2-mixer-ext",
+      "features": [
+        {
+          "name": "cmd",
+          "platform": "linux"
+        },
+        {
+          "name": "libflac",
+          "platform": "!(windows & mingw & !static)"
+        },
+        {
+          "name": "libgme",
+          "platform": "!(windows & mingw) & !native"
+        },
+        {
+          "name": "libmodplug",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "libopnmidi",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "libvorbis",
+          "platform": "!(windows & mingw & !static)"
+        },
+        {
+          "name": "libxmp",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "mpg123",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "nativemidi",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "opusfile",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "pxtone",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "timidity",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "wavpack",
+          "platform": "!(windows & mingw)"
+        }
+      ]
+    },
+    "zlib"
+  ],
+  "overrides": [
+    {
+      "name": "sdl2",
+      "version": "2.28.5",
+      "port-version": 1
+    }
+  ]
+}