diff --git a/.circleci/config.yml b/.circleci/config.yml
index b86b39f752a38aee24f50bb260f7b6b45d8b722f..9cf3c2a4e36338e88a9f08201a4df200395fdcf9 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,6 +7,7 @@ jobs:
         environment:
           CC: ccache gcc
           CCACHE_COMPRESS: true
+          CFLAGS: -Wno-error=unused-result
       #- image: ubuntu:trusty
       #  environment:
       #    CC: ccache gcc -m32
@@ -49,12 +50,15 @@ jobs:
           paths:
             - /home/circleci/.cache/apt
       - checkout
+      - run:
+         name: Create deps folder as needed
+         command: mkdir -p make/linux/64/SDL/deps/
       - run:
           name: make master depend file
-          command: find make/linux64/SDL/deps/ -type f -print0 | sort -z | xargs -r0 cat > make/linux64/SDL.deps
+          command: find make/linux/64/SDL/deps/ -type f -print0 | sort -z | xargs -r0 cat > make/linux/64/SDL.deps
       - restore_cache:
           keys:
-            - v1-SRB2-{{ .Branch }}-{{ checksum "make/linux64/SDL.deps" }}
+            - v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/64/SDL.deps" }}
       - run:
           name: Compile
           command: make -C src LINUX64=1 ERRORMODE=1 -k -j4
@@ -62,6 +66,6 @@ jobs:
           path: /home/circleci/SRB2/bin/
           destination: bin
       - save_cache:
-          key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux64/SDL.deps" }}
+          key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/64/SDL.deps" }}
           paths:
             - /home/circleci/.ccache
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml b/.gitlab/ci/jobs/alpine-3-gcc-dedicated-makefile.yml
similarity index 86%
rename from .gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
rename to .gitlab/ci/jobs/alpine-3-gcc-dedicated-makefile.yml
index 242ddd0eaa3f0e45504fa0fe258e08c63e0845df..fe63e09c8368cca1da7203b81411f55b3165ac44 100644
--- a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
+++ b/.gitlab/ci/jobs/alpine-3-gcc-dedicated-makefile.yml
@@ -1,18 +1,18 @@
-Alpine 3 GCC Dedicated:
-  extends: Alpine 3 GCC
+Alpine 3 GCC Dedicated Makefile:
+  extends: Alpine 3 GCC Makefile
 
   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"
+    expose_as: "Apline-3-Dedicated-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated-makefile"
 
   script:
     - - |
           # apk_toolchain
           echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
+      - apk add gcc g++
       - |
           # apk_toolchain
           echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-makefile.yml b/.gitlab/ci/jobs/alpine-3-gcc-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2cc656ca78a5641a594ee894a07f591c628ee36f
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc-makefile.yml
@@ -0,0 +1,135 @@
+Alpine 3 GCC Makefile:
+  stage: build
+
+  when: manual
+
+  image: alpine:3
+
+  allow_failure: true
+
+  cache:
+    - key: apk-$CI_JOB_IMAGE-makefile
+      paths:
+        - apk-cache
+      unprotect: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-makefile"
+
+  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 g++
+      - |
+          # 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 cmake musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev elfutils-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/alpine-3-gcc.yml b/.gitlab/ci/jobs/alpine-3-gcc.yml
index b3b12e40167a568e3ced2abc7a09ed0045e0cc99..1881bf3c2a445b3a517e20f49fd2ecec34b81460 100644
--- a/.gitlab/ci/jobs/alpine-3-gcc.yml
+++ b/.gitlab/ci/jobs/alpine-3-gcc.yml
@@ -15,8 +15,8 @@ Alpine 3 GCC:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.alpine3/bin/"
+      - "build.alpine3/src/config.h"
     expose_as: "Apline-3"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
 
@@ -50,7 +50,7 @@ Alpine 3 GCC:
     - - |
           # 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 add cmake make git ccache nasm
       - |
           # apk_common
           echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
@@ -95,7 +95,7 @@ Alpine 3 GCC:
     - - |
           # apk_toolchain
           echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
+      - apk add gcc g++
       - |
           # apk_toolchain
           echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
@@ -103,15 +103,23 @@ Alpine 3 GCC:
     - - |
           # 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 add cmake musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev elfutils-dev
       - |
           # apk_development
           echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.alpine3 -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_EXECINFO=NO -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=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 --directory=build.alpine3 --keep-going || make --directory=build.alpine3 --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/batocera-arm64-makefile.yml b/.gitlab/ci/jobs/batocera-arm64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9a590807de1d819d2be713011a2d8a1fbb61d1d1
--- /dev/null
+++ b/.gitlab/ci/jobs/batocera-arm64-makefile.yml
@@ -0,0 +1,38 @@
+batocera:arm64 Makefile:
+  extends: Debian stable:arm64 Makefile
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64-makefile"
+
+  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/batocera-arm64.yml b/.gitlab/ci/jobs/batocera-arm64.yml
index 3e43aa8753a0a1500abdc52e9f594863bd4b3691..c83a5badb0e096a48a83cc6fc32388a05ed245dd 100644
--- a/.gitlab/ci/jobs/batocera-arm64.yml
+++ b/.gitlab/ci/jobs/batocera-arm64.yml
@@ -7,8 +7,8 @@ batocera:arm64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian old arm64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
 
@@ -29,10 +29,18 @@ batocera:arm64:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS=ON -DSRB2_CONFIG_USE_GME=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=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 --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-amd64-makefile.yml b/.gitlab/ci/jobs/debian-oldstable-amd64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ba2e745bd423326fa326e18ee2985f659a235401
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64-makefile.yml
@@ -0,0 +1,40 @@
+Debian oldstable:amd64 Makefile:
+  extends: Debian stable:amd64 Makefile
+
+  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 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64-makefile"
+
+  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-amd64.yml b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
index 3929ecdcd10f8f448072d2c859de6a7dd31d94c7..32c7f3e40f6f9ac8145a6c679c86856ff879212a 100644
--- a/.gitlab/ci/jobs/debian-oldstable-amd64.yml
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
@@ -9,8 +9,8 @@ Debian oldstable:amd64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian old amd64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
 
@@ -31,10 +31,18 @@ Debian oldstable:amd64:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_USE_GME=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=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 --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-arm64-makefile.yml b/.gitlab/ci/jobs/debian-oldstable-arm64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..79e282bc62bbaf450e67da14041cb89bfbd910ca
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64-makefile.yml
@@ -0,0 +1,40 @@
+Debian oldstable:arm64 Makefile:
+  extends: Debian stable:arm64 Makefile
+
+  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 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64-makefile"
+
+  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-arm64.yml b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
index b18d538cd0824041650f3f8a5361b7b07c85f206..4bf324e3be14425830c4ff6d218d5ec33c35e559 100644
--- a/.gitlab/ci/jobs/debian-oldstable-arm64.yml
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
@@ -9,8 +9,8 @@ Debian oldstable:arm64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian old arm64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
 
@@ -31,10 +31,18 @@ Debian oldstable:arm64:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS=ON -DSRB2_CONFIG_USE_GME=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=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 --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-amd64-makefile.yml b/.gitlab/ci/jobs/debian-stable-amd64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6dfe176cd5fda3b28f545f8d5e7907e2538f07de
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-amd64-makefile.yml
@@ -0,0 +1,45 @@
+Debian stable:amd64 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian amd64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64-makefile"
+
+  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-amd64.yml b/.gitlab/ci/jobs/debian-stable-amd64.yml
index 4a757afe0d519f268bb4541cda49ba03a3181600..533a3151d5d81e1d9df62e31471269c6bf2b89da 100644
--- a/.gitlab/ci/jobs/debian-stable-amd64.yml
+++ b/.gitlab/ci/jobs/debian-stable-amd64.yml
@@ -5,8 +5,8 @@ Debian stable:amd64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian amd64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
 
@@ -36,10 +36,18 @@ Debian stable:amd64:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=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=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-arm64-makefile.yml b/.gitlab/ci/jobs/debian-stable-arm64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d932e9f4236d1983950ca61a9e41715af4aed5f5
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-arm64-makefile.yml
@@ -0,0 +1,46 @@
+Debian stable:arm64 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian arm64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64-makefile"
+
+  variables:
+    CC: aarch64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: aarch64-linux-gnu-objcopy
+    OBJDUMP: aarch64-linux-gnu-objdump
+    LD: aarch64-linux-gnu-ld
+    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-arm64.yml b/.gitlab/ci/jobs/debian-stable-arm64.yml
index 879391affebe7586e019e7bb7f8d77a0599983e2..db82ee38a0ac4c7ad483479bb81ab78cdba0a98a 100644
--- a/.gitlab/ci/jobs/debian-stable-arm64.yml
+++ b/.gitlab/ci/jobs/debian-stable-arm64.yml
@@ -7,8 +7,8 @@ Debian stable:arm64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian arm64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
 
@@ -17,6 +17,7 @@ Debian stable:arm64:
     LDFLAGS: -Wl,-fuse-ld=gold
     OBJCOPY: aarch64-linux-gnu-objcopy
     OBJDUMP: aarch64-linux-gnu-objdump
+    LD: aarch64-linux-gnu-ld
     PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
 
   script:
@@ -36,10 +37,18 @@ Debian stable:arm64:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS=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=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 --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-i386-makefile.yml b/.gitlab/ci/jobs/debian-stable-i386-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bbabee4a6cde37050ee3e6bbbc89e918914e275f
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-i386-makefile.yml
@@ -0,0 +1,45 @@
+Debian stable:i386 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian i386 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686-makefile"
+
+  variables:
+    CC: i686-linux-gnu-gcc
+    OBJCOPY: i686-linux-gnu-objcopy
+    OBJDUMP: i686-linux-gnu-objdump
+    LD: i686-linux-gnu-ld
+    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-stable-i386.yml b/.gitlab/ci/jobs/debian-stable-i386.yml
index cd6206e55e9a497d7065d3ea652c1ed3c6bd8d23..8d9ea49644a700490c471414248e671eef8e3e00 100644
--- a/.gitlab/ci/jobs/debian-stable-i386.yml
+++ b/.gitlab/ci/jobs/debian-stable-i386.yml
@@ -7,8 +7,8 @@ Debian stable:i386:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian i386"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
 
@@ -16,6 +16,7 @@ Debian stable:i386:
     CC: i686-linux-gnu-gcc
     OBJCOPY: i686-linux-gnu-objcopy
     OBJDUMP: i686-linux-gnu-objdump
+    LD: i686-linux-gnu-ld
     PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
 
   script:
@@ -35,10 +36,18 @@ Debian stable:i386:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=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=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-testing-gcc-amd64-makefile.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5edaddf3373e3cdcad9d0a6eda0167df2d813c2e
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64-makefile.yml
@@ -0,0 +1,46 @@
+Debian testing GCC Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  image: debian:testing-slim
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "testing-gcc-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc-makefile"
+
+  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/debian-testing-gcc-amd64.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
index 10799b3053e45a3d98fcfa1f63281e36ebadae9d..458c6d1efdc203da3d248a41ac5a29e583a53882 100644
--- a/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
@@ -11,8 +11,8 @@ Debian testing GCC:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "testing-gcc"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
 
@@ -37,10 +37,18 @@ Debian testing GCC:
           # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=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=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # 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
index 3928413610a048460dfe05d0dfc8f92e9da76848..a9e31773e6b2d58ffa4fce856085a83ad0f8bece 100644
--- a/.gitlab/ci/jobs/macos-arm64.yml
+++ b/.gitlab/ci/jobs/macos-arm64.yml
@@ -30,7 +30,7 @@ osxcross arm64:
     - - |
           # 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"
+      - 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_FORCE_NO_MS_BITFIELDS:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
       - |
           # 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
index 818028e49a43624f3e29a357d7d7614ef4dd5118..525a919c8a6976308d752bc82e68143233d59798 100644
--- a/.gitlab/ci/jobs/macos-x86_64.yml
+++ b/.gitlab/ci/jobs/macos-x86_64.yml
@@ -3,6 +3,30 @@ osxcross x86_64:
 
   stage: build
 
+  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
+
+    - key: vcpkg-root
+      paths:
+        - build/vcpkg-root
+      unprotect: true
+
+    - key: vcpkg-binary-cache-x64-osx
+      paths:
+        - build/vcpkg-binary-cache
+      unprotect: true
+
   artifacts:
     paths:
       - "build.osxcross/bin/"
@@ -15,6 +39,27 @@ osxcross x86_64:
     LD: x86_64-apple-darwin21.4-ld
 
   script:
+    - |
+        # vcpkg
+        echo -e "\e[0Ksection_start:`date +%s`:vcpkg-root[collapsed=true]\r\e[0KUpdating vcpkg"
+
+        if [ -d "build/vcpkg-root" ]; then
+          pushd build/vcpkg-root
+          git fetch https://github.com/Microsoft/vcpkg master
+          git reset --hard FETCH_HEAD
+          popd
+        else
+          mkdir -p build
+          git clone https://github.com/Microsoft/vcpkg build/vcpkg-root
+        fi
+
+        export VCPKG_ROOT=$(pwd)/build/vcpkg-root
+        export VCPKG_BINARY_SOURCES="clear;files,$(pwd)/build/vcpkg-binary-cache,readwrite"
+
+        mkdir -p "build/vcpkg-binary-cache"
+
+        echo -e "\e[0Ksection_end:`date +%s`:vcpkg-root\r\e[0K"
+
     - - |
           # apt_development
           echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
@@ -38,3 +83,33 @@ osxcross x86_64:
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\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"
+
+    - - |
+          # vcpkg_clean
+          echo -e "\e[0Ksection_start:`date +%s`:vcpkg_clean[collapsed=true]\r\e[0KCleaning vcpkg-root"
+
+          if [ -d "build/vcpkg-root" ]; then
+            pushd "build/vcpkg-root"
+            git clean
+            popd
+          fi
+
+          echo -e "\e[0Ksection_end:`date +%s`:vcpkg_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/.gitlab/ci/jobs/windows-x64-makefile.yml b/.gitlab/ci/jobs/windows-x64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f28fa219cc09550684abeddb5300927f00882d1a
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x64-makefile.yml
@@ -0,0 +1,35 @@
+Windows x64 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win64-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64-makefile"
+
+  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-x64.yml b/.gitlab/ci/jobs/windows-x64.yml
index da8d960bd1330229a2265ed9b015a487f1040e75..180fa773c34823e9eebd8254500233d1be8215a7 100644
--- a/.gitlab/ci/jobs/windows-x64.yml
+++ b/.gitlab/ci/jobs/windows-x64.yml
@@ -9,8 +9,8 @@ Windows x64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Win64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
 
@@ -26,10 +26,26 @@ Windows x64:
           # 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 ninja-build
+      - |
+          # 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.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-mingw-static -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/toolchains/mingw.cmake
+      - |
+          # 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=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 --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x86-makefile.yml b/.gitlab/ci/jobs/windows-x86-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9601cd6e68013b1971b6d3276802bad932a5a95c
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x86-makefile.yml
@@ -0,0 +1,35 @@
+Windows x86 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win32-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32-makefile"
+
+  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/jobs/windows-x86.yml b/.gitlab/ci/jobs/windows-x86.yml
index 311c767bbd9cd31d1063a248f68c0a6793dd47d5..2d885508570913bdb71bbb2bab1bd34f03c7e67a 100644
--- a/.gitlab/ci/jobs/windows-x86.yml
+++ b/.gitlab/ci/jobs/windows-x86.yml
@@ -3,12 +3,38 @@ Windows x86:
 
   stage: build
 
-  when: on_success
+  when: manual
+
+  allow_failure: true
+
+  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
+
+    - key: vcpkg-root
+      paths:
+        - build/vcpkg-root
+      unprotect: true
+
+    - key: vcpkg-binary-cache-x86-mingw-static
+      paths:
+        - build/vcpkg-binary-cache
+      unprotect: true
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build/ninja-x86_mingw_static_vcpkg-debug/bin/"
+      - "build/ninja-x86_mingw_static_vcpkg-debug/src/config.h"
     expose_as: "Win32"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
 
@@ -18,6 +44,27 @@ Windows x86:
     CXX: /usr/bin/i686-w64-mingw32-g++-posix
 
   script:
+    - |
+        # vcpkg
+        echo -e "\e[0Ksection_start:`date +%s`:vcpkg-root[collapsed=true]\r\e[0KUpdating vcpkg"
+
+        if [ -d "build/vcpkg-root" ]; then
+          pushd build/vcpkg-root
+          git fetch https://github.com/Microsoft/vcpkg master
+          git reset --hard FETCH_HEAD
+          popd
+        else
+          mkdir -p build
+          git clone https://github.com/Microsoft/vcpkg build/vcpkg-root
+        fi
+
+        export VCPKG_ROOT=$(pwd)/build/vcpkg-root
+        export VCPKG_BINARY_SOURCES="clear;files,$(pwd)/build/vcpkg-binary-cache,readwrite"
+
+        mkdir -p "build/vcpkg-binary-cache"
+
+        echo -e "\e[0Ksection_end:`date +%s`:vcpkg-root\r\e[0K"
+
     - - |
           # apt_toolchain
           echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
@@ -26,10 +73,58 @@ Windows x86:
           # 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 ninja-build
+      - |
+          # 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
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake --preset ninja-x86_mingw_static_vcpkg-debug -G "Unix Makefiles" -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
+      - |
+          # 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=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
+      - cmake --build --preset ninja-x86_mingw_static_vcpkg-debug --parallel 1 -- --keep-going || cmake --build --preset ninja-x86_mingw_static_vcpkg-debug --parallel 1 -- --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\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"
+
+    - - |
+          # vcpkg_clean
+          echo -e "\e[0Ksection_start:`date +%s`:vcpkg_clean[collapsed=true]\r\e[0KCleaning vcpkg-root"
+
+          if [ -d "build/vcpkg-root" ]; then
+            pushd "build/vcpkg-root"
+            git clean -f
+            popd
+          fi
+
+          echo -e "\e[0Ksection_end:`date +%s`:vcpkg_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 3b08a9facc348aad76f77b55a5700b8929859333..a4c631102606ee3177c94f1bb7a35b100694bf4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,7 @@ endif()
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
 include(CMakeDependentOption)
+include(CheckCXXCompilerFlag)
 
 file(STRINGS src/version.h SRB2_VERSION)
 string(REGEX MATCH "[0-9]+\\.[0-9.]+" SRB2_VERSION ${SRB2_VERSION})
@@ -72,6 +73,7 @@ option(SRB2_CONFIG_MOBJCONSISTANCY "Compile with MOBJCONSISTANCY defined." OFF)
 option(SRB2_CONFIG_PACKETDROP "Compile with PACKETDROP defined." OFF)
 option(SRB2_CONFIG_EXECINFO "Enable stack trace dump support." ON)
 option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF)
+option(SRB2_CONFIG_FORCE_NO_MS_BITFIELDS "Compile without -mno-ms-bitfields compiler flag" OFF)
 # SRB2_CONFIG_PROFILEMODE is probably superceded by some CMake setting.
 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.")
diff --git a/assets/README.txt b/assets/README.txt
index fe238dec09ec619becc718ab0fc60b7224e407e4..1ddacc999d7bde07f18e9c4fbb9041467dbda619 100644
--- a/assets/README.txt
+++ b/assets/README.txt
@@ -33,9 +33,6 @@ https://discord.gg/b3BGb8A
 Twitter:
 https://twitter.com/SonicTeamJr
 
-Facebook:
-https://facebook.com/SonicRoboBlast2
-
 
 COPYRIGHT AND DISCLAIMER
 
diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg
index 41ad998891154f56fe850cdfe457a48189dd648f..7ef5ab1e170dcb00041a0a341a8d7a82da0072d2 100644
--- a/extras/conf/SRB2-22.cfg
+++ b/extras/conf/SRB2-22.cfg
@@ -41,7 +41,7 @@ linetagindicatesectors = true;
 
 // The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
 formatinterface = "SRB2MapSetIO";
-	
+
 //Maximum safe map size check (0 means skip check)
 safeboundary = 0;
 
@@ -502,7 +502,7 @@ gen_sectortypes
 	{
 		0 = "Normal";
 		512 = "Wind/Current <deprecated>";
-		1024 = "Conveyor Belt <deprecated>";		 
+		1024 = "Conveyor Belt <deprecated>";
 		1280 = "Speed Pad";
 		1536 = "Flip Gravity on Jump";
 	}
@@ -3730,7 +3730,7 @@ thingtypes
 
 		3328 = "3D Mode Start";
 	}
-	
+
 	starts
 	{
 		color = 1; // Blue
diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg
index e5cafead431c0d79eaaef734eee008eeab89dd15..9bf882f56a11346709b7c7c263e37dd86ffad173 100644
--- a/extras/conf/udb/Includes/SRB222_common.cfg
+++ b/extras/conf/udb/Includes/SRB222_common.cfg
@@ -96,7 +96,7 @@ mapformat_udmf
 	{
 		include("SRB222_misc.cfg", "universalfields");
 	}
-	
+
 	// Disable Doom-related modes that don't make sense for SRB2
 	soundsupport = false;
 	automapsupport = false;
@@ -195,4 +195,4 @@ mapformat_udmf
 	{
 		include("SRB222_linedefs.cfg", "udmf");
 	}
-}
\ No newline at end of file
+}
diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index fc505fb6025b02782d1a309b247f569a63dd96fd..ce1979581fb7e1251ad76882154eab80ec204f06 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -8,7 +8,7 @@ udmf
 		{
 			title = "None";
 		}
-		
+
 		6
 		{
 			title = "Sector Set Portal";
@@ -897,7 +897,7 @@ udmf
 				}
 			}
 		}
-		
+
 		190
 		{
 			title = "Rising";
diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index c37c29ce0def1f471565d7d4494ac7ab833eb054..e5786977bd4e9c3a543c2113d0f20fa8b84939a1 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -240,7 +240,7 @@ universalfields
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		comment
 		{
 			type = 2;
@@ -252,19 +252,19 @@ universalfields
 			type = 2;
 			default = "";
 		}
-		
+
 		stringarg0
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		stringarg1
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		executordelay
 		{
 			type = 0;
@@ -279,19 +279,19 @@ universalfields
 			type = 2;
 			default = "";
 		}
-		
+
 		light
 		{
 			type = 0;
 			default = 0;
 		}
-		
+
 		lightabsolute
 		{
 			type = 3;
 			default = false;
 		}
-		
+
 		//light_top
 		//{
 		//	type = 0;
@@ -326,8 +326,8 @@ universalfields
 		//{
 		//	type = 3;
 		//	default = false;
-		//}		
-		
+		//}
+
 		offsetx_bottom
 		{
 			type = 1;
@@ -339,7 +339,7 @@ universalfields
 			type = 1;
 			default = 0.0;
 		}
-		
+
 		offsetx_top
 		{
 			type = 1;
@@ -357,43 +357,43 @@ universalfields
 			type = 1;
 			default = 0.0;
 		}
-		
+
 		offsety_top
 		{
 			type = 1;
 			default = 0.0;
 		}
-		
+
 		scalex_bottom
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scalex_mid
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scalex_top
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley_bottom
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley_mid
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley_top
 		{
 			type = 1;
@@ -408,41 +408,41 @@ universalfields
 			type = 2;
 			default = "";
 		}
-		
+
 		pitch
 		{
 			type = 0;
 		}
-		
+
 		roll
 		{
 			type = 0;
 		}
-		
+
 		scalex
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		stringarg0
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		stringarg1
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		mobjscale
 		{
 			type = 1;
@@ -450,7 +450,7 @@ universalfields
 			managed = false;
 		}
 	}
-	
+
 	sector
 	{
 		comment
@@ -530,7 +530,7 @@ universalfields
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		yscalefloor
 		{
 			type = 1;
@@ -542,7 +542,7 @@ universalfields
 			type = 0;
 			default = 0;
 		}
-		
+
 		lightfloorabsolute
 		{
 			type = 3;
@@ -572,7 +572,7 @@ universalfields
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		yscaleceiling
 		{
 			type = 1;
@@ -584,7 +584,7 @@ universalfields
 			type = 0;
 			default = 0;
 		}
-		
+
 		lightceilingabsolute
 		{
 			type = 3;
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index c028f9439c493d156e1ded87f7a116cc4b14d9d7..8b1e29751b7bb4b3e771813b414d80f9017a4f68 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -1127,12 +1127,12 @@ udmf
 				}
 			}
 		}
-		
+
 		bossinvisibles
 		{
 			title = "Misc. Invisible";
 			color = 15; // White
-			
+
 			290
 			{
 				arrow = 0;
@@ -2021,7 +2021,7 @@ udmf
 			}
 		}
 	}
-	
+
 	hazards
 	{
 		color = 17; // Orange
@@ -2983,7 +2983,7 @@ udmf
 		{
 			title = "Mace Spawnpoints";
 			color = 11;
-			
+
 			1104
 			{
 				title = "Mace Spawn";
@@ -3188,7 +3188,7 @@ udmf
 					title = "Flags";
 					type = 12;
 					enum = "maceflags";
-	
+
 				}
 			}
 			1108
@@ -3320,7 +3320,7 @@ udmf
 				}
 			}
 		}
-		
+
 		1100
 		{
 			title = "Chain (Decorative)";
@@ -3570,12 +3570,12 @@ udmf
 		color = 2; // Green
 		title = "Arid Canyon";
 
-		
+
 		cacti
 		{
 			title = "Cacti";
 			color = 17;
-			
+
 			1203
 			{
 				title = "Tiny Red Flower Cactus";
@@ -3654,12 +3654,12 @@ udmf
 				height = 60;
 			}
 		}
-		
+
 		minecarts
 		{
 			title = "Minecart";
 			color = 11;
-			
+
 			1219
 			{
 				title = "Minecart Spawner";
@@ -3706,7 +3706,7 @@ udmf
 				}
 			}
 		}
-		
+
 		1200
 		{
 			title = "Tumbleweed (Big)";
@@ -4611,7 +4611,7 @@ udmf
 		title = "Botanic Serenity";
 		width = 16;
 		height = 32;
-		
+
 		flowers
 		{
 			title = "Flowers";
@@ -4706,7 +4706,7 @@ udmf
 				sprite = "BSZ3F0";
 			}
 		}
-		
+
 		tulips
 		{
 			title = "Tulips";
@@ -4771,7 +4771,7 @@ udmf
 				sprite = "BSZ5F0";
 			}
 		}
-		
+
 		bushes
 		{
 			title = "Bushes";
@@ -4806,7 +4806,7 @@ udmf
 				sprite = "BSZ6F0";
 			}
 		}
-		
+
 		vines
 		{
 			title = "Vines";
@@ -5063,7 +5063,7 @@ udmf
 			}
 		}
 	}
-	
+
 	mario
 	{
 		color = 2; // Green
@@ -5574,7 +5574,7 @@ udmf
 			}
 		}
 	}
-	
+
 	editor
 	{
 		color = 15; // White
@@ -5587,4 +5587,4 @@ udmf
 
 		3328 = "3D Mode Start";
 	}
-}
\ No newline at end of file
+}
diff --git a/extras/conf/udb/SRB2-22binary.cfg b/extras/conf/udb/SRB2-22binary.cfg
index 3073b76c4570cb9a8f7f62a3e675cbffc7814614..2144ff7a61591b1c9a6865013cd44499179f2183 100644
--- a/extras/conf/udb/SRB2-22binary.cfg
+++ b/extras/conf/udb/SRB2-22binary.cfg
@@ -41,7 +41,7 @@ linetagindicatesectors = true;
 
 // The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
 formatinterface = "DoomMapSetIO";
-	
+
 //Maximum safe map size check (0 means skip check)
 safeboundary = 0;
 
@@ -502,7 +502,7 @@ gen_sectortypes
 	{
 		0 = "Normal";
 		512 = "Wind/Current <deprecated>";
-		1024 = "Conveyor Belt <deprecated>";		 
+		1024 = "Conveyor Belt <deprecated>";
 		1280 = "Speed Pad";
 		1536 = "Flip Gravity on Jump";
 	}
@@ -3636,7 +3636,7 @@ thingtypes
 
 		3328 = "3D Mode Start";
 	}
-	
+
 	starts
 	{
 		color = 1; // Blue
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fbd29cddda5e3caae29aaee01bbed579375730a5..2cfb56f6e9645b126320f1242da095737ac866d5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -234,9 +234,12 @@ endif()
 
 # Compatibility flag with later versions of GCC
 # We should really fix our code to not need this
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
-	if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64|em64t|EM64T)")
-		target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+if (NOT SRB2_CONFIG_FORCE_NO_MS_BITFIELDS)
+	if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+		check_cxx_compiler_flag("-mno-ms-bitfields" HAS_NO_MS_BITFIELDS)
+		if(HAS_NO_MS_BITFIELDS)
+			target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+		endif()
 	endif()
 endif()
 
diff --git a/src/command.c b/src/command.c
index 29f491e295d7378be64cf72a2c0115c5dd51e676..ab6cfc08af7c4cde9f756d868b02e42ffd29229d 100644
--- a/src/command.c
+++ b/src/command.c
@@ -705,7 +705,7 @@ static void add_alias(char *newname, char *newcmd)
 	{
 		if (!stricmp(newname, a->name))
 		{
-			Z_Free(a->value); // Free old cmd 
+			Z_Free(a->value); // Free old cmd
 			a->value = newcmd;
 			return;
 		}
diff --git a/src/config.h.in b/src/config.h.in
index a6dabcbafa1fbb331c89b56b0b80fed9b4f425a7..0f24cfc4466e3b8387777ba68a1b83ead3f3dbc3 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -41,12 +41,13 @@
  * Last updated 2023 / 09 / 06 - v2.2.12 - patch.pk3
  * Last updated 2023 / 09 / 09 - v2.2.13 - none
  * Last updated 2025 / 01 / 16 - v2.2.14 - main assets
+ * Last updated 2025 / 01 / 24 - v2.2.15 - main assets
  */
-#define ASSET_HASH_SRB2_PK3   "c1d9a4b3452b350d4662f41eb301dc6c"
-#define ASSET_HASH_ZONES_PK3  "2ab758817fff96bc60ee9dec85e0b534"
-#define ASSET_HASH_CHARACTERS_PK3 "97ce7008d16152731fe037141309aa24"
+#define ASSET_HASH_SRB2_PK3       "3182ce524acc2072ddaa81acf4b6a9aa"
+#define ASSET_HASH_ZONES_PK3      "88ff4c300851ccdb0406698eadd89907"
+#define ASSET_HASH_CHARACTERS_PK3 "5c5936b8a690e007c0939bd0785a41fb"
 #ifdef USE_PATCH_DTA
-#define ASSET_HASH_PATCH_PK3  "3c7b73f34af7e9a7bceb2d5260f76172"
+#define ASSET_HASH_PATCH_PK3      "00000000000000000000000000000000"
 #endif
 
 #endif
diff --git a/src/d_main.c b/src/d_main.c
index bb742029938347bd939f7ba86301b2f8742abf1e..d75a4d5013d9a92e7abccad7211721b3fa1f00b5 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1179,7 +1179,7 @@ static void IdentifyVersion(void)
 	// Add the maps
 	D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "zones.pk3"));
 
-	// Add the players
+	// Add the characters
 	D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "characters.pk3"));
 
 #ifdef USE_PATCH_DTA
diff --git a/src/d_player.h b/src/d_player.h
index 5f5bf53d63f04f356aee6850752ac51126e38d3e..cdb547d3b863147798fe28cd5100ed54be0f23c0 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -45,14 +45,15 @@ typedef enum
 	SF_MARIODAMAGE      = SF_NOJUMPDAMAGE|SF_STOMPDAMAGE, // The Mario method of being able to damage enemies, etc.
 	SF_MACHINE          = 1<<10, // Beep boop. Are you a robot?
 	SF_DASHMODE         = 1<<11, // Sonic Advance 2 style top speed increase?
-	SF_FASTEDGE         = 1<<12, // Faster edge teeter?
-	SF_MULTIABILITY     = 1<<13, // Revenge of Final Demo.
-	SF_NONIGHTSROTATION = 1<<14, // Disable sprite rotation for NiGHTS
-	SF_NONIGHTSSUPER    = 1<<15, // Disable super colors for NiGHTS (if you have SF_SUPER)
-	SF_NOSUPERSPRITES   = 1<<16, // Don't use super sprites while super
-	SF_NOSUPERJUMPBOOST = 1<<17, // Disable the jump boost given while super (i.e. Knuckles)
-	SF_CANBUSTWALLS     = 1<<18, // Can naturally bust walls on contact? (i.e. Knuckles)
-	SF_NOSHIELDABILITY  = 1<<19, // Disable shield abilities
+	SF_FASTWAIT         = 1<<12, // Faster wait animation?
+	SF_FASTEDGE         = 1<<13, // Faster edge teeter?
+	SF_MULTIABILITY     = 1<<14, // Revenge of Final Demo.
+	SF_NONIGHTSROTATION = 1<<15, // Disable sprite rotation for NiGHTS
+	SF_NONIGHTSSUPER    = 1<<16, // Disable super colors for NiGHTS (if you have SF_SUPER)
+	SF_NOSUPERSPRITES   = 1<<17, // Don't use super sprites while super
+	SF_NOSUPERJUMPBOOST = 1<<18, // Disable the jump boost given while super (i.e. Knuckles)
+	SF_CANBUSTWALLS     = 1<<19, // Can naturally bust walls on contact? (i.e. Knuckles)
+	SF_NOSHIELDABILITY  = 1<<20, // Disable shield abilities
 
 	// free up to and including 1<<31
 } skinflags_t;
@@ -158,10 +159,6 @@ typedef enum
 	PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs
 	PF_CANCARRY    = 1<<29, // Can carry another player?
 	PF_FINISHED    = 1<<30, // The player finished the level. NOT the same as exiting
-	
-	// True if shield button down last tic
-	// This may be the final flag, but 2.3 could free up the others
-	PF_SHIELDDOWN    = 1<<31,
 
 	// up to 1<<31 is free
 } pflags_t;
diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h
index 43eb0f00b8df58da69c2dc7123d274d69070c104..2481ed738b23769a546fef840500d10ba7b024f5 100644
--- a/src/d_ticcmd.h
+++ b/src/d_ticcmd.h
@@ -26,23 +26,20 @@
 // Button/action code definitions.
 typedef enum
 {
-	// First 3 bits are weapon change info, DO NOT USE!
-	BT_WEAPONMASK = 0x07,  //our first three bits.
-	
-	BT_SHIELD     = 1<<3,  // shield or super action
+	// First 4 bits are weapon change info, DO NOT USE!
+	BT_WEAPONMASK = 0x0F, //our first four bits.
 
-	BT_WEAPONNEXT = 1<<4,  // select next weapon
-	BT_WEAPONPREV = 1<<5,  // select previous weapon
+	BT_WEAPONNEXT = 1<<4,
+	BT_WEAPONPREV = 1<<5,
+
+	BT_ATTACK     = 1<<6, // shoot rings
+	BT_SPIN       = 1<<7,
+	BT_CAMLEFT    = 1<<8, // turn camera left
+	BT_CAMRIGHT   = 1<<9, // turn camera right
+	BT_TOSSFLAG   = 1<<10,
+	BT_JUMP       = 1<<11,
+	BT_FIRENORMAL = 1<<12, // Fire a normal ring no matter what
 
-	BT_ATTACK     = 1<<6,  // shoot rings
-	BT_SPIN       = 1<<7,  // spin action
-	BT_CAMLEFT    = 1<<8,  // turn camera left
-	BT_CAMRIGHT   = 1<<9,  // turn camera right
-	BT_TOSSFLAG   = 1<<10, // toss flag or emeralds
-	BT_JUMP       = 1<<11, // jump action
-	BT_FIRENORMAL = 1<<12, // fire a normal ring no matter what
-	
-	// custom lua buttons
 	BT_CUSTOM1    = 1<<13,
 	BT_CUSTOM2    = 1<<14,
 	BT_CUSTOM3    = 1<<15,
diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c
index ab872713a850be2a8b8ca9cf86c121594b34f16f..643e24f5afb677f450dab073097388661c35c98a 100644
--- a/src/dedicated/i_system.c
+++ b/src/dedicated/i_system.c
@@ -1573,4 +1573,3 @@ boolean I_GetTextInputMode(void)
 }
 
 #include "../sdl/dosstr.c"
-
diff --git a/src/dedicated/i_video.c b/src/dedicated/i_video.c
index 2c998117accb71be25850438bdac2ee6c4db0509..19f2d0cbd51bba44266ca0b92627b542cb8c948b 100644
--- a/src/dedicated/i_video.c
+++ b/src/dedicated/i_video.c
@@ -1,4 +1,4 @@
-#include "../doomdef.h"
+#include "../doomdef.h"
 #include "../command.h"
 #include "../i_video.h"
 
@@ -76,4 +76,3 @@ void I_ReadScreen(UINT8 *scr)
 void I_BeginRead(void){}
 
 void I_EndRead(void){}
-
diff --git a/src/deh_lua.c b/src/deh_lua.c
index e5b3b03de4349dbf97d158471af20df7a18e00d3..48f737a1ff5c6587414b2efe2edbc566c9c25034 100644
--- a/src/deh_lua.c
+++ b/src/deh_lua.c
@@ -11,7 +11,6 @@
 /// \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.
@@ -600,20 +599,12 @@ 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 these aliases
-	else if (fastcmp(word, "BT_USE"))
+	// TODO: 2.3: Delete this alias
+	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)) {
diff --git a/src/deh_soc.c b/src/deh_soc.c
index df11a3e6df59ecdba4b7dc74078b071bce405b88..343beb3012676b93256af35c0bd57ff6ba7e9076 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -1,7 +1,7 @@
 // SONIC ROBO BLAST 2
 //-----------------------------------------------------------------------------
 // Copyright (C) 1998-2000 by DooM Legacy Team.
-// Copyright (C) 1999-2024 by Sonic Team Junior.
+// Copyright (C) 1999-2025 by Sonic Team Junior.
 //
 // This program is free software distributed under the
 // terms of the GNU General Public License, version 2.
@@ -286,6 +286,7 @@ void readPlayer(MYFILE *f, INT32 num)
 				}
 				if (playertext)
 				{
+					// PLAYERTEXT is really weird, so this doesn't use deh_strlcpy.
 					strlcpy(description[num].notes, playertext, NOTE_SIZE);
 					strlcat(description[num].notes,
 						myhashfgets(playertext, NOTE_SIZE, f), NOTE_SIZE);
@@ -324,7 +325,8 @@ void readPlayer(MYFILE *f, INT32 num)
 			if (fastcmp(word, "PICNAME"))
 			{
 				SLOTFOUND
-				strncpy(description[num].picname, word2, sizeof(description[num].picname)-1);
+				deh_strlcpy(description[num].picname, word2, sizeof description[num].picname,
+					va("Character %d: picname", num));
 			}
 			else if (fastcmp(word, "DISPLAYNAME"))
 			{
@@ -345,7 +347,8 @@ void readPlayer(MYFILE *f, INT32 num)
 					cur = strchr(cur, '#');
 				}
 
-				strlcpy(description[num].displayname, stringvalue, sizeof description[num].displayname);
+				deh_strlcpy(description[num].displayname, stringvalue, sizeof description[num].displayname,
+					va("Character %d: displayname", num));
 			}
 			else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR"))
 			{
@@ -355,7 +358,8 @@ void readPlayer(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME"))
 			{
 				SLOTFOUND
-				strncpy(description[num].nametag, word2, sizeof(description[num].nametag)-1);
+				deh_strlcpy(description[num].nametag, word2, sizeof description[num].nametag,
+					va("Character %d: nametag", num));
 			}
 			else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR"))
 			{
@@ -387,7 +391,8 @@ void readPlayer(MYFILE *f, INT32 num)
 			{
 				// Send to free slot.
 				SLOTFOUND
-				strlcpy(description[num].skinname, word2, sizeof description[num].skinname);
+				deh_strlcpy(description[num].skinname, word2, sizeof description[num].skinname,
+					va("Character %d: skinname", num));
 				strlwr(description[num].skinname);
 			}
 			else if (!failure)
@@ -1196,6 +1201,7 @@ void readgametype(MYFILE *f, char *gtname)
 				}
 				if (descr)
 				{
+					// DESCRIPTION is really weird, so this doesn't use deh_strlcpy.
 					strlcpy(gtdescription, descr, sizeof (gtdescription));
 					strlcat(gtdescription,
 						myhashfgets(descr, sizeof (gtdescription), f),
@@ -1402,7 +1408,7 @@ void readlevelheader(MYFILE *f, INT32 num)
 			{
 				deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
 					sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
-				strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once
+				strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_strlcpy so only complains once
 				continue;
 			}
 			// CHEAP HACK: move this over here for lowercase subtitles
@@ -1445,10 +1451,10 @@ void readlevelheader(MYFILE *f, INT32 num)
 				// Newly allocated
 				modoption = &mapheaderinfo[num-1]->customopts[j];
 
-				strncpy(modoption->option, word,  31);
-				modoption->option[31] = '\0';
-				strncpy(modoption->value,  word2, 255);
-				modoption->value[255] = '\0';
+				deh_strlcpy(modoption->option, word, sizeof(modoption->option),
+					va("Level header %d: custom option %d key", num, j));
+				deh_strlcpy(modoption->value, word2, sizeof(modoption->value),
+					va("Level header %d: custom option %d value", num, j));
 				continue;
 			}
 
@@ -1626,7 +1632,7 @@ void readlevelheader(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "KEYWORDS"))
 			{
 				deh_strlcpy(mapheaderinfo[num-1]->keywords, word2,
-						sizeof(mapheaderinfo[num-1]->keywords), va("Level header %d: keywords", num));
+					sizeof(mapheaderinfo[num-1]->keywords), va("Level header %d: keywords", num));
 			}
 			else if (fastcmp(word, "MUSIC"))
 			{
@@ -1675,7 +1681,8 @@ void readlevelheader(MYFILE *f, INT32 num)
 			}
 			else if (fastcmp(word, "FORCECHARACTER"))
 			{
-				strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1);
+				deh_strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, sizeof mapheaderinfo[num-1]->forcecharacter,
+					va("Level header %d: forcecharacter", num));
 				strlwr(mapheaderinfo[num-1]->forcecharacter); // skin names are lowercase
 			}
 			else if (fastcmp(word, "WEATHER"))
@@ -1683,7 +1690,10 @@ 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, sizeof(mapheaderinfo[num-1]->interscreen)-1);
+			{
+				deh_strlcpy(mapheaderinfo[num-1]->interscreen, word2, sizeof mapheaderinfo[num-1]->interscreen,
+					va("Level header %d: interscreen", num));
+			}
 			else if (fastcmp(word, "PRECUTSCENENUM"))
 				mapheaderinfo[num-1]->precutscenenum = (UINT8)i;
 			else if (fastcmp(word, "CUTSCENENUM"))
@@ -1985,14 +1995,17 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
 				picid = (UINT8)atoi(word + 3);
 				if (picid > 8 || picid == 0)
 				{
-					deh_warning("CutSceneScene %d: unknown word '%s'", num, word);
+					deh_warning("Cutscene %d, scene %d: pic number %d out of range (1 - %d)",
+						num + 1, scenenum + 1, picid, 8);
 					continue;
 				}
 				--picid;
 
 				if (fastcmp(word+4, "NAME"))
 				{
-					strncpy(cutscenes[num]->scene[scenenum].picname[picid], word2, 8);
+					deh_strlcpy(cutscenes[num]->scene[scenenum].picname[picid], word2,
+						sizeof cutscenes[num]->scene[scenenum].picname[picid],
+						va("Cutscene %d, scene %d, pic %d: name", num + 1, scenenum + 1, picid + 1));
 				}
 				else if (fastcmp(word+4, "HIRES"))
 				{
@@ -2011,12 +2024,13 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
 					cutscenes[num]->scene[scenenum].ycoord[picid] = usi;
 				}
 				else
-					deh_warning("CutSceneScene %d: unknown word '%s'", num, word);
+					deh_warning("Cutscene %d, scene %d: unknown word '%s'", num + 1, scenenum + 1, word);
 			}
 			else if (fastcmp(word, "MUSIC"))
 			{
-				strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7);
-				cutscenes[num]->scene[scenenum].musswitch[6] = 0;
+				deh_strlcpy(cutscenes[num]->scene[scenenum].musswitch, word2,
+					sizeof cutscenes[num]->scene[scenenum].musswitch,
+					va("Cutscene %d, scene %d: music", num + 1, scenenum + 1));
 			}
 			else if (fastcmp(word, "MUSICTRACK"))
 			{
@@ -2051,7 +2065,7 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
 				cutscenes[num]->scene[scenenum].fadecolor = (UINT8)i;
 			}
 			else
-				deh_warning("CutSceneScene %d: unknown word '%s'", num, word);
+				deh_warning("Cutscene %d, scene %d: unknown word '%s'", num + 1, scenenum + 1, word);
 		}
 	} while (!myfeof(f)); // finish when the line is empty
 
@@ -2109,11 +2123,10 @@ void readcutscene(MYFILE *f, INT32 num)
 					readcutscenescene(f, num, value - 1);
 				}
 				else
-					deh_warning("Scene number %d out of range (1 - 128)", value);
-
+					deh_warning("Cutscene %d: scene number %d out of range (1 - 128)", num + 1, value);
 			}
 			else
-				deh_warning("Cutscene %d: unknown word '%s', Scene <num> expected.", num, word);
+				deh_warning("Cutscene %d: unknown word '%s', Scene <num> expected.", num + 1, word);
 		}
 	} while (!myfeof(f)); // finish when the line is empty
 
@@ -2234,7 +2247,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 
 					for (picid = 0; picid < MAX_PROMPT_PICS; picid++)
 					{
-						strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8);
+						// Doesn't use deh_strlcpy because it's not copying input.
+						strlcpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], sizeof textprompts[num]->page[pagenum].picname[picid]);
 						textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid];
 						textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid];
 						textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid];
@@ -2247,14 +2261,17 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 				picid = (UINT8)atoi(word + 3);
 				if (picid > MAX_PROMPT_PICS || picid == 0)
 				{
-					deh_warning("textpromptscene %d: unknown word '%s'", num, word);
+					deh_warning("Text prompt %d, page %d: pic number %d out of range (1 - %d)",
+						num + 1, pagenum + 1, picid, MAX_PROMPT_PICS);
 					continue;
 				}
 				--picid;
 
 				if (fastcmp(word+4, "NAME"))
 				{
-					strncpy(textprompts[num]->page[pagenum].picname[picid], word2, 8);
+					deh_strlcpy(textprompts[num]->page[pagenum].picname[picid], word2,
+						sizeof textprompts[num]->page[pagenum].picname[picid],
+						va("Text prompt %d, page %d, pic %d: name", num + 1, pagenum + 1, picid + 1));
 				}
 				else if (fastcmp(word+4, "HIRES"))
 				{
@@ -2273,12 +2290,16 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 					textprompts[num]->page[pagenum].ycoord[picid] = usi;
 				}
 				else
-					deh_warning("textpromptscene %d: unknown word '%s'", num, word);
+				{
+					deh_warning("Text prompt %d, page %d: unknown word '%s'",
+						num + 1, pagenum + 1, word);
+				}
 			}
 			else if (fastcmp(word, "MUSIC"))
 			{
-				strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7);
-				textprompts[num]->page[pagenum].musswitch[6] = 0;
+				deh_strlcpy(textprompts[num]->page[pagenum].musswitch, word2,
+					sizeof textprompts[num]->page[pagenum].musswitch,
+					va("Text prompt %d, page %d: music", num + 1, pagenum + 1));
 			}
 			else if (fastcmp(word, "MUSICTRACK"))
 			{
@@ -2293,30 +2314,35 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 			{
 				if (*word2 != '\0')
 				{
-					INT32 j;
+					size_t j;
 
 					// HACK: Add yellow control char now
 					// so the drawing function doesn't call it repeatedly
-					char name[34];
+					char name[32 + 2];
 					name[0] = '\x82'; // color yellow
-					name[1] = 0;
-					strncat(name, word2, 32);
-					name[33] = 0;
+
+					// So that we still get a warning.
+					deh_strlcpy(name + 1, word2, (sizeof(name)) - 1,
+						va("Text prompt %d, page %d: name", num + 1, pagenum + 1));
 
 					// Replace _ with ' '
-					for (j = 0; j < 32 && name[j]; j++)
+					for (j = 1; j < sizeof(name) && name[j]; j++)
 					{
 						if (name[j] == '_')
 							name[j] = ' ';
 					}
 
-					strncpy(textprompts[num]->page[pagenum].name, name, sizeof(textprompts[num]->page[pagenum].name));
+					strlcpy(textprompts[num]->page[pagenum].name, name, sizeof(textprompts[num]->page[pagenum].name));
 				}
 				else
 					*textprompts[num]->page[pagenum].name = '\0';
 			}
 			else if (fastcmp(word, "ICON"))
-				strncpy(textprompts[num]->page[pagenum].iconname, word2, 8);
+			{
+				deh_strlcpy(textprompts[num]->page[pagenum].iconname, word2,
+					sizeof textprompts[num]->page[pagenum].iconname,
+					va("Text prompt %d, page %d: icon", num + 1, pagenum + 1));
+			}
 			else if (fastcmp(word, "ICONALIGN"))
 				textprompts[num]->page[pagenum].rightside = (i || word2[0] == 'R');
 			else if (fastcmp(word, "ICONFLIP"))
@@ -2383,8 +2409,9 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 				{
 					UINT8 metapagenum = usi - 1;
 
-					strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32);
-					strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8);
+					// Doesn't use deh_strlcpy because it's not copying input.
+					strlcpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, sizeof textprompts[num]->page[pagenum].name);
+					strlcpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, sizeof textprompts[num]->page[pagenum].iconname);
 					textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside;
 					textprompts[num]->page[pagenum].iconflip = textprompts[num]->page[metapagenum].iconflip;
 					textprompts[num]->page[pagenum].lines = textprompts[num]->page[metapagenum].lines;
@@ -2399,17 +2426,25 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 				}
 			}
 			else if (fastcmp(word, "TAG"))
-				strncpy(textprompts[num]->page[pagenum].tag, word2, 33);
+			{
+				deh_strlcpy(textprompts[num]->page[pagenum].tag, word2,
+					sizeof textprompts[num]->page[pagenum].tag,
+					va("Text prompt %d, page %d: tag", num + 1, pagenum + 1));
+			}
 			else if (fastcmp(word, "NEXTPROMPT"))
 				textprompts[num]->page[pagenum].nextprompt = usi;
 			else if (fastcmp(word, "NEXTPAGE"))
 				textprompts[num]->page[pagenum].nextpage = usi;
 			else if (fastcmp(word, "NEXTTAG"))
-				strncpy(textprompts[num]->page[pagenum].nexttag, word2, 33);
+			{
+				deh_strlcpy(textprompts[num]->page[pagenum].nexttag, word2,
+					sizeof textprompts[num]->page[pagenum].nexttag,
+					va("Text prompt %d, page %d: nexttag", num + 1, pagenum + 1));
+			}
 			else if (fastcmp(word, "TIMETONEXT"))
 				textprompts[num]->page[pagenum].timetonext = get_number(word2);
 			else
-				deh_warning("PromptPage %d: unknown word '%s'", num, word);
+				deh_warning("Text prompt %d, page %d: unknown word '%s'", num + 1, pagenum + 1, word);
 		}
 	} while (!myfeof(f)); // finish when the line is empty
 
@@ -2469,11 +2504,11 @@ void readtextprompt(MYFILE *f, INT32 num)
 					readtextpromptpage(f, num, value - 1);
 				}
 				else
-					deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES);
+					deh_warning("Prompt %d: page number %d out of range (1 - %d)", num + 1, value, MAX_PAGES);
 
 			}
 			else
-				deh_warning("Prompt %d: unknown word '%s', Page <num> expected.", num, word);
+				deh_warning("Prompt %d: unknown word '%s', Page <num> expected.", num + 1, word);
 		}
 	} while (!myfeof(f)); // finish when the line is empty
 
@@ -2522,7 +2557,8 @@ void readmenu(MYFILE *f, INT32 num)
 
 			if (fastcmp(word, "BACKGROUNDNAME"))
 			{
-				strncpy(menupres[num].bgname, word2, 8);
+				deh_strlcpy(menupres[num].bgname, word2,
+					sizeof menupres[num].bgname, va("Menu %d: backgroundname", num));
 				titlechanged = true;
 			}
 			else if (fastcmp(word, "HIDEBACKGROUND"))
@@ -2565,7 +2601,8 @@ void readmenu(MYFILE *f, INT32 num)
 			}
 			else if (fastcmp(word, "TITLEPICSNAME"))
 			{
-				strncpy(menupres[num].ttname, word2, 9);
+				deh_strlcpy(menupres[num].ttname, word2,
+					sizeof menupres[num].ttname, va("Menu %d: titlepicsname", num));
 				titlechanged = true;
 			}
 			else if (fastcmp(word, "TITLEPICSX"))
@@ -2601,8 +2638,8 @@ void readmenu(MYFILE *f, INT32 num)
 			}
 			else if (fastcmp(word, "MUSIC"))
 			{
-				strncpy(menupres[num].musname, word2, 7);
-				menupres[num].musname[6] = 0;
+				deh_strlcpy(menupres[num].musname, word2,
+					sizeof menupres[num].musname, va("Menu %d: music", num));
 				titlechanged = true;
 			}
 			else if (fastcmp(word, "MUSICTRACK"))
@@ -3590,9 +3627,7 @@ void readmaincfg(MYFILE *f)
 					lumpnum_t lumpnum;
 					char newname[9];
 
-					strncpy(newname, word2, 8);
-
-					newname[8] = '\0';
+					deh_strlcpy(newname, word2, sizeof newname, va("Maincfg: execcfg"));
 
 					lumpnum = W_CheckNumForName(newname);
 
@@ -3800,7 +3835,7 @@ void readmaincfg(MYFILE *f)
 			}
 			else if (fastcmp(word, "TITLEPICSNAME"))
 			{
-				strncpy(ttname, word2, sizeof(ttname)-1);
+				deh_strlcpy(ttname, word2, sizeof ttname, va("Maincfg: titlepicsname"));
 				titlechanged = true;
 			}
 			else if (fastcmp(word, "TITLEPICSX"))
@@ -3910,7 +3945,7 @@ void readmaincfg(MYFILE *f)
 			}
 			else if (fastcmp(word, "CUSTOMVERSION"))
 			{
-				strlcpy(customversionstring, word2, sizeof (customversionstring));
+				deh_strlcpy(customversionstring, word2, sizeof customversionstring, va("Maincfg: customversion"));
 				//titlechanged = true;
 			}
 			else if (fastcmp(word, "BOOTMAP"))
diff --git a/src/deh_tables.c b/src/deh_tables.c
index 8fa32558baf8338d68a485ea6ef0b64edfb78db4..d7146325352fe35a873d4bcfe2229e394e0346c0 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -1081,11 +1081,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	"S_FANG_FIRE1",
 	"S_FANG_FIRE2",
 	"S_FANG_FIRE3",
-	"S_FANG_FIRE4",
 	"S_FANG_FIREREPEAT",
 	"S_FANG_LOBSHOT0",
 	"S_FANG_LOBSHOT1",
 	"S_FANG_LOBSHOT2",
+	"S_FANG_LOBSHOT3",
 	"S_FANG_WAIT1",
 	"S_FANG_WAIT2",
 	"S_FANG_WALLHIT",
@@ -1107,6 +1107,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	"S_FANG_PINCHLOBSHOT2",
 	"S_FANG_PINCHLOBSHOT3",
 	"S_FANG_PINCHLOBSHOT4",
+	"S_FANG_PINCHLOBSHOT5",
 	"S_FANG_DIE1",
 	"S_FANG_DIE2",
 	"S_FANG_DIE3",
@@ -2256,11 +2257,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	// FHZ
 	"S_FHZICE1",
 	"S_FHZICE2",
-	"S_ROSY_IDLE1",
-	"S_ROSY_IDLE2",
-	"S_ROSY_IDLE3",
-	"S_ROSY_IDLE4",
+	"S_ROSY_IDLE",
 	"S_ROSY_JUMP",
+	"S_ROSY_FALL",
 	"S_ROSY_WALK",
 	"S_ROSY_HUG",
 	"S_ROSY_PAIN",
@@ -2920,69 +2919,6 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	"S_BHORIZ7",
 	"S_BHORIZ8",
 
-	// Yellow Trampoline
-	"S_YELLOWTRAMPOLINE",
-	"S_YELLOWTRAMPOLINE2",
-	"S_YELLOWTRAMPOLINE3",
-	"S_YELLOWTRAMPOLINE4",
-	"S_YELLOWTRAMPOLINE5",
-
-	// Red Trampoline
-	"S_REDTRAMPOLINE",
-	"S_REDTRAMPOLINE2",
-	"S_REDTRAMPOLINE3",
-	"S_REDTRAMPOLINE4",
-	"S_REDTRAMPOLINE5",
-
-	// Blue Trampoline
-	"S_BLUETRAMPOLINE",
-	"S_BLUETRAMPOLINE2",
-	"S_BLUETRAMPOLINE3",
-	"S_BLUETRAMPOLINE4",
-	"S_BLUETRAMPOLINE5",
-
-	// Horizontal Yellow Trampoline
-	"S_HORIZYELLOWTRAMPOLINE",
-	"S_HORIZYELLOWTRAMPOLINE2",
-	"S_HORIZYELLOWTRAMPOLINE3",
-	"S_HORIZYELLOWTRAMPOLINE4",
-	"S_HORIZYELLOWTRAMPOLINE5",
-
-	// Horizontal Red Trampoline
-	"S_HORIZREDTRAMPOLINE",
-	"S_HORIZREDTRAMPOLINE2",
-	"S_HORIZREDTRAMPOLINE3",
-	"S_HORIZREDTRAMPOLINE4",
-	"S_HORIZREDTRAMPOLINE5",
-
-	// Horizontal Blue Trampoline
-	"S_HORIZBLUETRAMPOLINE",
-	"S_HORIZBLUETRAMPOLINE2",
-	"S_HORIZBLUETRAMPOLINE3",
-	"S_HORIZBLUETRAMPOLINE4",
-	"S_HORIZBLUETRAMPOLINE5",
-
-	// Diagonal Yellow Trampoline
-	"S_DIAGYELLOWTRAMPOLINE",
-	"S_DIAGYELLOWTRAMPOLINE2",
-	"S_DIAGYELLOWTRAMPOLINE3",
-	"S_DIAGYELLOWTRAMPOLINE4",
-	"S_DIAGYELLOWTRAMPOLINE5",
-
-	// Diagonal Red Trampoline
-	"S_DIAGREDTRAMPOLINE",
-	"S_DIAGREDTRAMPOLINE2",
-	"S_DIAGREDTRAMPOLINE3",
-	"S_DIAGREDTRAMPOLINE4",
-	"S_DIAGREDTRAMPOLINE5",
-
-	// Diagonal Blue Trampoline
-	"S_DIAGBLUETRAMPOLINE",
-	"S_DIAGBLUETRAMPOLINE2",
-	"S_DIAGBLUETRAMPOLINE3",
-	"S_DIAGBLUETRAMPOLINE4",
-	"S_DIAGBLUETRAMPOLINE5",
-
 	// Booster
 	"S_BOOSTERSOUND",
 	"S_YELLOWBOOSTERROLLER",
@@ -3255,28 +3191,37 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 
 	"S_RINGEXPLODE",
 
-	// Mario-specific stuff
-	"S_COIN",
+	"S_COIN1",
+	"S_COIN2",
+	"S_COIN3",
 	"S_COINSPARKLE1",
 	"S_COINSPARKLE2",
+	"S_COINSPARKLE3",
+	"S_COINSPARKLE4",
 	"S_GOOMBA1",
 	"S_GOOMBA1B",
 	"S_GOOMBA2",
 	"S_GOOMBA3",
 	"S_GOOMBA4",
 	"S_GOOMBA5",
+	"S_GOOMBA6",
+	"S_GOOMBA7",
+	"S_GOOMBA8",
+	"S_GOOMBA9",
 	"S_GOOMBA_DEAD",
-	"S_GOOMBA_DEAD2",
-	"S_GOOMBA_DEAD3",
 	"S_BLUEGOOMBA1",
 	"S_BLUEGOOMBA1B",
 	"S_BLUEGOOMBA2",
 	"S_BLUEGOOMBA3",
 	"S_BLUEGOOMBA4",
 	"S_BLUEGOOMBA5",
+	"S_BLUEGOOMBA6",
+	"S_BLUEGOOMBA7",
+	"S_BLUEGOOMBA8",
+	"S_BLUEGOOMBA9",
 	"S_BLUEGOOMBA_DEAD",
-	"S_BLUEGOOMBA_DEAD2",
-	"S_BLUEGOOMBA_DEAD3",
+
+	// Mario-specific stuff
 	"S_FIREFLOWER1",
 	"S_FIREFLOWER2",
 	"S_FIREFLOWER3",
@@ -3284,13 +3229,6 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	"S_FIREBALL",
 	"S_FIREBALLTRAIL1",
 	"S_FIREBALLTRAIL2",
-	"S_GREENKOOPASPAWN",
-	"S_GREENKOOPA1",
-	"S_GREENKOOPA2",
-	"S_GREENKOOPA3",
-	"S_GREENKOOPA4",
-	"S_GREENKOOPADEATH1",
-	"S_GREENKOOPADEATH2",
 	"S_SHELL",
 	"S_PUMA_START1",
 	"S_PUMA_START2",
@@ -3316,68 +3254,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	"S_MARIOBUSH1",
 	"S_MARIOBUSH2",
 	"S_TOAD",
-	"S_PTZSHROOM",
-	"S_PTZFLAG1",
-	"S_PTZFLAG2",
-	"S_PTZFLAG3",
-	"S_PTZFLAG4",
-	"S_PTZFLAG5",
-	"S_MARIOBUSH",
-	"S_BSBSHROOM",
-	"S_BLBSHROOM",
-	"S_BNWSHROOM",
-	"S_REDMFLOWER",
-	"S_BLUEMFLOWER",
-	"S_YELLOWMFLOWER",
-	"S_WHITEDANDELION",
-	"S_MAR64TREE",
-
-	// Power up mushrooms
-	"S_LIFESHROOM",
-	"S_LIFESHROOM2",
-	"S_LIFESHROOMD",
-	"S_LIFESHROOM_INVISIBLE",
-	"S_LIFESHROOM_INVISIBLE_TOUCH",
-
-	"S_POISONSHROOM",
-	"S_POISONSHROOM2",
-	"S_POISONSHROOMD",
-
-	"S_NUKESHROOM",
-	"S_NUKESHROOM2",
-	"S_NUKESHROOMD",
-
-	"S_FORCESHROOM",
-	"S_FORCESHROOM2",
-	"S_FORCESHROOMD",
-
-	"S_ATTRACTSHROOM",
-	"S_ATTRACTSHROOM2",
-	"S_ATTRACTSHROOMD",
-
-	"S_ELEMENTALSHROOM",
-	"S_ELEMENTALSHROOM2",
-	"S_ELEMENTALSHROOMD",
-
-	"S_CLOUDSHROOM",
-	"S_CLOUDSHROOM2",
-	"S_CLOUDSHROOMD",
-
-	"S_STARMAN",
-	"S_STARMAN1",
-	"S_STARMAN2",
-	"S_STARMAN3",
-	"S_STARMAND",
-
-	"S_SPEEDWINGS",
-	"S_SPEEDWINGSD",
-	
-	"S_PARTICLEPICKUP1",
-	"S_PARTICLEPICKUP2",
-	"S_1000SCOREAWARD",
-	"S_POWERUPAWARD",
-	"S_POWERUPAWARD1",
-	"S_POWERUPAWARD2",
+
 
 	// Nights-specific stuff
 	"S_NIGHTSDRONE_MAN1",
@@ -3680,11 +3557,6 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 	"S_REDBRICKDEBRIS",
 	"S_BLUEBRICKDEBRIS",
 	"S_YELLOWBRICKDEBRIS",
-	"S_MARIOBRICKDEBRIS",
-	"S_MARIOBRICKDEBRISS",
-	"S_MARIOBRICKDEBRISB",
-	"S_MARIOBRICKDEBRISC",
-	"S_MARIOBRICKDEBRISM",
 
 	"S_NAMECHECK",
 
@@ -3867,16 +3739,6 @@ const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for sanity t
 	"MT_REDHORIZ",
 	"MT_BLUEHORIZ",
 
-	"MT_YELLOWTRAMPOLINE",
-	"MT_REDTRAMPOLINE",
-	"MT_BLUETRAMPOLINE",
-	"MT_HORIZYELLOWTRAMPOLINE",
-	"MT_HORIZREDTRAMPOLINE",
-	"MT_HORIZBLUETRAMPOLINE",
-	"MT_DIAGYELLOWTRAMPOLINE",
-	"MT_DIAGREDTRAMPOLINE",
-	"MT_DIAGBLUETRAMPOLINE",
-
 	"MT_BOOSTERSEG",
 	"MT_BOOSTERROLLER",
 	"MT_YELLOWBOOSTER",
@@ -4377,7 +4239,6 @@ const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for sanity t
 	"MT_FIREFLOWER",
 	"MT_FIREBALL",
 	"MT_FIREBALLTRAIL",
-	"MT_GREENKOOPA",
 	"MT_SHELL",
 	"MT_PUMA",
 	"MT_PUMATRAIL",
@@ -4388,30 +4249,6 @@ const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for sanity t
 	"MT_MARIOBUSH1",
 	"MT_MARIOBUSH2",
 	"MT_TOAD",
-	"MT_PTZSHROOM",
-	"MT_PTZFLAG",
-	"MT_BSBSHROOM",
-	"MT_BLBSHROOM",
-	"MT_BNWSHROOM",
-	"MT_MARIOBUSH",
-	"MT_REDMFLOWER",
-	"MT_BLUEMFLOWER",
-	"MT_YELLOWMFLOWER",
-	"MT_WHITEDANDELION",
-	"MT_MAR64TREE",
-
-	// Power up mushrooms
-	"MT_LIFESHROOM",
-	"MT_LIFESHROOM_INVISIBLE",
-	"MT_POISONSHROOM",
-	"MT_NUKESHROOM",
-	"MT_FORCESHROOM",
-	"MT_ATTRACTSHROOM",
-	"MT_ELEMENTALSHROOM",
-	"MT_CLOUDSHROOM",
-	"MT_STARMAN",
-	"MT_SPEEDWINGS",
-	"MT_POWERUPAWARD",
 
 	// NiGHTS Stuff
 	"MT_AXIS",
@@ -4509,11 +4346,6 @@ const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for sanity t
 	"MT_REDBRICKDEBRIS",
 	"MT_BLUEBRICKDEBRIS",
 	"MT_YELLOWBRICKDEBRIS",
-	"MT_MARIOBRICKDEBRIS",
-	"MT_MARIOBRICKDEBRISS",
-	"MT_MARIOBRICKDEBRISB",
-	"MT_MARIOBRICKDEBRISC",
-	"MT_MARIOBRICKDEBRISM",
 
 	"MT_NAMECHECK",
 	"MT_RAY",
@@ -5426,6 +5258,7 @@ struct int_const_s const INT_CONST[] = {
 	{"SF_MARIODAMAGE",SF_MARIODAMAGE},
 	{"SF_MACHINE",SF_MACHINE},
 	{"SF_DASHMODE",SF_DASHMODE},
+	{"SF_FASTWAIT",SF_FASTWAIT},
 	{"SF_FASTEDGE",SF_FASTEDGE},
 	{"SF_MULTIABILITY",SF_MULTIABILITY},
 	{"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION},
@@ -5774,8 +5607,7 @@ struct int_const_s const INT_CONST[] = {
 	{"ROTAXIS_Z",ROTAXIS_Z},
 
 	// Buttons (ticcmd_t)
-	{"BT_WEAPONMASK",BT_WEAPONMASK}, //our first three bits.
-	{"BT_SHIELD",BT_SHIELD},
+	{"BT_WEAPONMASK",BT_WEAPONMASK}, //our first four bits.
 	{"BT_WEAPONNEXT",BT_WEAPONNEXT},
 	{"BT_WEAPONPREV",BT_WEAPONPREV},
 	{"BT_ATTACK",BT_ATTACK}, // shoot rings
@@ -5934,7 +5766,6 @@ 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},
@@ -5956,7 +5787,9 @@ struct int_const_s const INT_CONST[] = {
 	{"GC_WEPSLOT5",GC_WEPSLOT5},
 	{"GC_WEPSLOT6",GC_WEPSLOT6},
 	{"GC_WEPSLOT7",GC_WEPSLOT7},
-	{"GC_SHIELD",GC_SHIELD},
+	{"GC_WEPSLOT8",GC_WEPSLOT8},
+	{"GC_WEPSLOT9",GC_WEPSLOT9},
+	{"GC_WEPSLOT10",GC_WEPSLOT10},
 	{"GC_FIRE",GC_FIRE},
 	{"GC_FIRENORMAL",GC_FIRENORMAL},
 	{"GC_TOSSFLAG",GC_TOSSFLAG},
diff --git a/src/doomstat.h b/src/doomstat.h
index 5246349deef6f859bbb6f34ff8f078b3c15fe500..b5b2984407cc7cf03d213de8cb70f3bab720fc88 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -2,7 +2,7 @@
 //-----------------------------------------------------------------------------
 // Copyright (C) 1993-1996 by id Software, Inc.
 // Copyright (C) 1998-2000 by DooM Legacy Team.
-// Copyright (C) 1999-2024 by Sonic Team Junior.
+// Copyright (C) 1999-2025 by Sonic Team Junior.
 //
 // This program is free software distributed under the
 // terms of the GNU General Public License, version 2.
@@ -209,19 +209,19 @@ typedef struct
 	UINT8 picmode; // sequence mode after displaying last pic, 0 = persist, 1 = loop, 2 = destroy
 	UINT8 pictoloop; // if picmode == loop, which pic to loop to?
 	UINT8 pictostart; // initial pic number to show
-	char picname[MAX_PROMPT_PICS][8];
+	char picname[MAX_PROMPT_PICS][8+1];
 	UINT8 pichires[MAX_PROMPT_PICS];
 	UINT16 xcoord[MAX_PROMPT_PICS]; // gfx
 	UINT16 ycoord[MAX_PROMPT_PICS]; // gfx
 	UINT16 picduration[MAX_PROMPT_PICS];
 
-	char   musswitch[7];
+	char   musswitch[6+1];
 	UINT16 musswitchflags;
 	UINT8 musicloop;
 
-	char tag[33]; // page tag
-	char name[34]; // narrator name, extra char for color
-	char iconname[8]; // narrator icon lump
+	char tag[32+1]; // page tag
+	char name[32+2]; // narrator name, extra char for color
+	char iconname[8+1]; // narrator icon lump
 	boolean rightside; // narrator side, false = left, true = right
 	boolean iconflip; // narrator flip icon horizontally
 	UINT8 hidehud; // hide hud, 0 = show all, 1 = hide depending on prompt position (top/bottom), 2 = hide all
@@ -233,7 +233,7 @@ typedef struct
 	sfxenum_t textsfx; // sfx_ id for printing text
 	UINT8 nextprompt; // next prompt to jump to, one-based. 0 = current prompt
 	UINT8 nextpage; // next page to jump to, one-based. 0 = next page within prompt->numpages
-	char nexttag[33]; // next tag to jump to. If set, this overrides nextprompt and nextpage.
+	char nexttag[32+1]; // next tag to jump to. If set, this overrides nextprompt and nextpage.
 	INT32 timetonext; // time in tics to jump to next page automatically. 0 = don't jump automatically
 	char *text;
 } textpage_t;
@@ -287,8 +287,8 @@ typedef struct
 // (This is not ifdeffed so the map header structure can stay identical, just in case.)
 typedef struct
 {
-	char option[32]; // 31 usable characters
-	char value[256]; // 255 usable characters. If this seriously isn't enough then wtf.
+	char option[31+1]; // 31 usable characters
+	char value[255+1]; // 255 usable characters. If this seriously isn't enough then wtf.
 } customoption_t;
 
 /** Map header information.
@@ -303,7 +303,7 @@ typedef struct
 	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.
+	char musname[6+1];          ///< 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.
@@ -330,7 +330,7 @@ typedef struct
 	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.
+	char selectheading[21+1];   ///< 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.
@@ -352,9 +352,9 @@ typedef struct
 
 	// Music stuff.
 	UINT32 musinterfadeout;     ///< Fade out level music on intermission screen in milliseconds
-	char musintername[7];       ///< Intermission screen music.
+	char musintername[6+1];     ///< Intermission screen music.
 
-	char muspostbossname[7];    ///< Post-bossdeath music.
+	char muspostbossname[6+1];  ///< Post-bossdeath music.
 	UINT16 muspostbosstrack;    ///< Post-bossdeath track.
 	UINT32 muspostbosspos;      ///< Post-bossdeath position
 	UINT32 muspostbossfadein;   ///< Post-bossdeath fade-in milliseconds.
diff --git a/src/f_finale.c b/src/f_finale.c
index 119e6daba7290ae61d66a8c15b71c7268aa19dcc..c6d957292138915a6def4b975648e81e708cfd5a 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -1121,11 +1121,11 @@ static const char *credits[] = {
 	"Alice \"Alacroix\" de Lemos",
 	"Logan \"Hyperchaotix\" McCloud",
 	"Alexander \"DrTapeworm\" Moench-Ford",
+    "\"orbitalviolet\"", // summit showdown hehehehe (aka Evertone)
 	"Andrew \"Senku Niola\" Moran",
 	"\"MotorRoach\"",
 	"Phillip \"TelosTurntable\" Robinson",
 	"\"Scizor300\"",
-	"\"Skydusk\"",
 	"Wessel \"sphere\" Smit",
 	"David \"Instant Sonic\" Spencer Jr.",
 	"\"SSNTails\"",
@@ -1173,11 +1173,9 @@ static const char *credits[] = {
 	"Mujamel \"MK\" Khan",
 	"\"Kaito Sinclaire\"",
 	"Alexander \"DrTapeworm\" Moench-Ford",
-	"\"orbitalviolet\"", // summit showdown hehehehe (aka Evertone)
 	"\"Radicalicious\"",
 	"\"Revan\"",
 	"Anna \"QueenDelta\" Sandlin",
-	"\"Skydusk\"",
 	"Wessel \"sphere\" Smit",
 	"\"SSNTails\"",
 	"Aaron \"Othius\" Stojkov",
diff --git a/src/filesrch.c b/src/filesrch.c
index 67a2e8976f88548c0f6f77b2143fbef6888d820f..7f104f8cac58ba1e109605b5b0598f14b3a86ce6 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -698,7 +698,7 @@ static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
 		dirpathindex[depthleft]--;
 }
 
-//sortdir by name? 
+//sortdir by name?
 static int lumpnamecompare(const void *A, const void *B)
 {
 	const lumpinfo_t *pA = A;
diff --git a/src/g_demo.c b/src/g_demo.c
index 8315e716bfad9f80387d438d1128078aa3e2ca0f..479020905ee9bb12f78fda614b4da70d13c75bbc 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -100,7 +100,7 @@ demoghost *ghosts = NULL;
 // DEMO RECORDING
 //
 
-#define DEMOVERSION 0x0012
+#define DEMOVERSION 0x0011
 #define DEMOHEADER  "\xF0" "SRB2Replay" "\x0F"
 
 #define DF_GHOST        0x01 // This demo contains ghost data too!
@@ -185,11 +185,7 @@ 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)
diff --git a/src/g_game.c b/src/g_game.c
index 8940635851adbbf56b95e296c1fa908da642b828..1c186ae03149780b254c72f5243ed3d551350e52 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -401,29 +401,27 @@ 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_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);
+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);
 
 player_t *seenplayer; // player we're aiming at right now
 
@@ -894,9 +892,6 @@ 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;
@@ -970,9 +965,6 @@ 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;
@@ -1340,10 +1332,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONPREV))
 		cmd->buttons |= BT_WEAPONPREV; // Previous Weapon
 
-#if NUM_WEAPONS > 7
-"Add extra inputs to g_input.h/gamecontrols_e, and fix conflicts in d_ticcmd.h/ticcmd_t/buttons"
+#if NUM_WEAPONS > 10
+"Add extra inputs to g_input.h/gamecontrols_e"
 #endif
-	//use the three avaliable bits to determine the weapon.
+	//use the four avaliable bits to determine the weapon.
 	cmd->buttons &= ~BT_WEAPONMASK;
 	for (i = 0; i < NUM_WEAPONS; ++i)
 		if (PLAYERINPUTDOWN(ssplayer, GC_WEPSLOT1 + i))
@@ -1362,15 +1354,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	if (PLAYERINPUTDOWN(ssplayer, GC_FIRENORMAL) || (usejoystick && axis > 0))
 		cmd->buttons |= BT_FIRENORMAL;
 
-	// Toss flag button
 	if (PLAYERINPUTDOWN(ssplayer, GC_TOSSFLAG))
 		cmd->buttons |= BT_TOSSFLAG;
 
-	// Shield button
-	axis = PlayerJoyAxis(ssplayer, JA_SHIELD);
-	if (PLAYERINPUTDOWN(ssplayer, GC_SHIELD) || (usejoystick && axis > 0))
-		cmd->buttons |= BT_SHIELD;
-
 	// Lua scriptable buttons
 	if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM1))
 		cmd->buttons |= BT_CUSTOM1;
@@ -2777,7 +2763,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
 	p->pflags |= PF_SPINDOWN;
 	p->pflags |= PF_ATTACKDOWN;
 	p->pflags |= PF_JUMPDOWN;
-	p->pflags |= PF_SHIELDDOWN;
 
 	p->playerstate = PST_LIVE;
 	p->panim = PA_IDLE; // standing animation
diff --git a/src/g_game.h b/src/g_game.h
index 2680fa973be8e43353f474475fed6b1004e53705..f72ea6b41b1b29b4b263b9039c0ad588bc78de17 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_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_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_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest;
 
 // hi here's some new controls
@@ -100,7 +100,6 @@ 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 3ba709978d3d8779a92ce14a9144050ca4d51908..4fbdf5e7586d41c4dd09f0a5e5c3e2aafa67c99d 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -576,7 +576,9 @@ static const char *gamecontrolname[NUM_GAMECONTROLS] =
 	"weapon5",
 	"weapon6",
 	"weapon7",
-	"shield",
+	"weapon8",
+	"weapon9",
+	"weapon10",
 	"fire",
 	"firenormal",
 	"tossflag",
@@ -691,7 +693,6 @@ void G_DefineDefaultControls(void)
 	gamecontroldefault[gcs_fps][GC_CENTERVIEW ][0] = KEY_LCTRL;
 	gamecontroldefault[gcs_fps][GC_JUMP       ][0] = KEY_SPACE;
 	gamecontroldefault[gcs_fps][GC_SPIN       ][0] = KEY_LSHIFT;
-	gamecontroldefault[gcs_fps][GC_SHIELD     ][0] = KEY_LALT;
 	gamecontroldefault[gcs_fps][GC_FIRE       ][0] = KEY_RCTRL;
 	gamecontroldefault[gcs_fps][GC_FIRE       ][1] = KEY_MOUSE1+0;
 	gamecontroldefault[gcs_fps][GC_FIRENORMAL ][0] = KEY_RALT;
@@ -712,7 +713,6 @@ void G_DefineDefaultControls(void)
 	gamecontroldefault[gcs_platform][GC_CENTERVIEW ][0] = KEY_END;
 	gamecontroldefault[gcs_platform][GC_JUMP       ][0] = KEY_SPACE;
 	gamecontroldefault[gcs_platform][GC_SPIN       ][0] = KEY_LSHIFT;
-	gamecontroldefault[gcs_platform][GC_SHIELD     ][0] = KEY_LALT;
 	gamecontroldefault[gcs_platform][GC_FIRE       ][0] = 's';
 	gamecontroldefault[gcs_platform][GC_FIRE       ][1] = KEY_MOUSE1+0;
 	gamecontroldefault[gcs_platform][GC_FIRENORMAL ][0] = 'w';
@@ -728,6 +728,9 @@ void G_DefineDefaultControls(void)
 		gamecontroldefault[i][GC_WEPSLOT5     ][0] = '5';
 		gamecontroldefault[i][GC_WEPSLOT6     ][0] = '6';
 		gamecontroldefault[i][GC_WEPSLOT7     ][0] = '7';
+		gamecontroldefault[i][GC_WEPSLOT8     ][0] = '8';
+		gamecontroldefault[i][GC_WEPSLOT9     ][0] = '9';
+		gamecontroldefault[i][GC_WEPSLOT10    ][0] = '0';
 		gamecontroldefault[i][GC_TOSSFLAG     ][0] = '\'';
 		gamecontroldefault[i][GC_CAMTOGGLE    ][0] = 'v';
 		gamecontroldefault[i][GC_CAMRESET     ][0] = 'r';
@@ -743,34 +746,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_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_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_CAMTOGGLE    ][1] = KEY_JOY1+9; // Right Stick
-		gamecontroldefault[i][GC_SCORES       ][1] = KEY_JOY1+6; // Back
+		gamecontroldefault[i][GC_CAMTOGGLE    ][1] = KEY_JOY1+4; // LB
+		gamecontroldefault[i][GC_CENTERVIEW   ][1] = KEY_JOY1+5; // RB
+		gamecontroldefault[i][GC_SCREENSHOT   ][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_SCORES       ][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_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_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_CAMTOGGLE    ][1] = KEY_2JOY1+9; // Right Stick
-		//gamecontrolbisdefault[i][GC_SCORES       ][1] = KEY_2JOY1+6; // Back
+		gamecontrolbisdefault[i][GC_CAMTOGGLE    ][1] = KEY_2JOY1+4; // LB
+		gamecontrolbisdefault[i][GC_CENTERVIEW   ][1] = KEY_2JOY1+5; // RB
+		gamecontrolbisdefault[i][GC_SCREENSHOT   ][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_SCORES       ][1] = KEY_2HAT1+1; // D-Pad Down
 	}
 }
 
diff --git a/src/g_input.h b/src/g_input.h
index 48c103076667df50884767685386b98bd4865a02..e9c909e6e2c222360086874ddb27e2495b4e0381 100644
--- a/src/g_input.h
+++ b/src/g_input.h
@@ -74,7 +74,9 @@ typedef enum
 	GC_WEPSLOT5,
 	GC_WEPSLOT6,
 	GC_WEPSLOT7,
-	GC_SHIELD,
+	GC_WEPSLOT8,
+	GC_WEPSLOT9,
+	GC_WEPSLOT10,
 	GC_FIRE,
 	GC_FIRENORMAL,
 	GC_TOSSFLAG,
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index 5503f3ed94a09aa4f8a6344d4e7b4e18a08a84d7..9011ff05ec855c45291c95946adf110365c2839b 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -485,15 +485,6 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_SSWY
 	&lspr[NOLIGHT],     // SPR_SSWR
 	&lspr[NOLIGHT],     // SPR_SSWB
-	&lspr[NOLIGHT],     // SPR_MPRY
-	&lspr[NOLIGHT],     // SPR_MPRR
-	&lspr[NOLIGHT],     // SPR_MPRB
-	&lspr[NOLIGHT],     // SPR_MSWY
-	&lspr[NOLIGHT],     // SPR_MSWR
-	&lspr[NOLIGHT],     // SPR_MSWB
-	&lspr[NOLIGHT],     // SPR_MDIY
-	&lspr[NOLIGHT],     // SPR_MDIR
-	&lspr[NOLIGHT],     // SPR_MDIB
 	&lspr[NOLIGHT],     // SPR_BSTY
 	&lspr[NOLIGHT],     // SPR_BSTR
 
@@ -552,7 +543,6 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_BGOM
 	&lspr[REDBALL_L],     // SPR_FFWR
 	&lspr[SMALLREDBALL_L], // SPR_FBLL
-	&lspr[NOLIGHT],		// SPR_MKOP
 	&lspr[NOLIGHT],     // SPR_SHLL
 	&lspr[REDBALL_L],   // SPR_PUMA
 	&lspr[NOLIGHT],     // SPR_HAMM
@@ -623,22 +613,6 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT], // SPR_BRIR
 	&lspr[NOLIGHT], // SPR_BRIB
 	&lspr[NOLIGHT], // SPR_BRIY
-	&lspr[NOLIGHT], // SPR_MBRI
-	&lspr[NOLIGHT], // SPR_MBRS
-	&lspr[NOLIGHT], // SPR_MBRB
-	&lspr[NOLIGHT], // SPR_MBRC
-	&lspr[NOLIGHT], // SPR_MTRI
-	&lspr[NOLIGHT], // SPR_MARS
-	&lspr[NOLIGHT], // SPR_MRFL
-	&lspr[NOLIGHT], // SPR_MAUH
-	&lspr[NOLIGHT], // SPR_MBSA
-	&lspr[NOLIGHT], // SPR_MBSB
-	&lspr[NOLIGHT], // SPR_MBSC
-	&lspr[NOLIGHT], // SPR_MFRE
-	&lspr[NOLIGHT], // SPR_MFYE
-	&lspr[NOLIGHT], // SPR_MFBE
-	&lspr[NOLIGHT], // SPR_MFWD
-	&lspr[NOLIGHT], // SPR_MUS3
 
 	// Gravity Well Objects
 	&lspr[NOLIGHT],     // SPR_GWLG
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index e426bcdddf56d36c3796c101d4b3a628b964ed5b..a5befe112c60bc704e58b3c3467944b2dd1ed971 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -2491,16 +2491,16 @@ static void HWR_Subsector(size_t num)
 			rover; rover = rover->next)
 		{
 			fixed_t bottomCullHeight, topCullHeight, centerHeight;
-			
+
 			if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES))
 				continue;
 			if (sub->validcount == validcount)
 				continue;
-			
+
 			// rendering heights for bottom and top planes
 			bottomCullHeight = P_GetFFloorBottomZAt(rover, viewx, viewy);
 			topCullHeight = P_GetFFloorTopZAt(rover, viewx, viewy);
-			
+
 			if (gl_frontsector->cullheight)
 			{
 				if (HWR_DoCulling(gl_frontsector->cullheight, viewsector->cullheight, gl_viewz, FIXED_TO_FLOAT(*rover->bottomheight), FIXED_TO_FLOAT(*rover->topheight)))
@@ -3105,7 +3105,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 	// baseWallVerts is used to know the final shape to easily get the vertex
 	// co-ordinates
 	memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
-	
+
 	fixed_t newalpha = spr->mobj->alpha;
 
 	// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
@@ -3150,7 +3150,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 		blend = HWR_GetBlendModeFlag(blendmode)|occlusion;
 		if (!occlusion) use_linkdraw_hack = true;
 	}
-	
+
 	Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
 
 	if (HWR_UseShader())
@@ -3349,7 +3349,7 @@ static void HWR_DrawBoundingBox(gl_vissprite_t *vis)
 		v[15].y = v[16].y = v[17].y = v[21].y = v[22].y = v[23].y = vis->gzt; // top
 
 	Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj));
-	
+
 	HWR_ProcessPolygon(&Surf, v, 24, (cv_renderhitboxgldepth.value ? 0 : PF_NoDepthTest)|PF_Modulated|PF_NoTexture|PF_WireFrame, SHADER_NONE, false);
 }
 
@@ -3645,7 +3645,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
 			blend = HWR_GetBlendModeFlag(blendmode)|occlusion;
 			if (!occlusion) use_linkdraw_hack = true;
 		}
-		
+
 		Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
 
 		if (spr->renderflags & RF_SHADOWEFFECTS)
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 011b478e58c38c95813dfe8170a7facaa2fa178d..931867142200338b7635d7b04307df587eafa129 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1373,7 +1373,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		// Apparently people don't like jump frames like that, so back it goes
 		if (tics > durs)
 			durs = tics;
-		
+
 		// Make linkdraw objects use their tracer's alpha value
 		fixed_t newalpha = spr->mobj->alpha;
 		if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
@@ -1392,7 +1392,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff;
 			Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode);
 		}
-		
+
 		Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
 
 		// don't forget to enable the depth test because we can't do this
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index e11dd4f166cb8e068cc8fb99d2e2bd0661832755..02a32957a2b940ac15490c0e83fb57658da24c5e 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -713,7 +713,7 @@ EXPORT boolean HWRAPI(InitShaders) (void)
 #ifdef GL_SHADERS
 	if (!pglUseProgram)
 		return false;
-	
+
 	gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER);
 	gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER);
 
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index cf8ec969a16cd5b8dfc58eb537372062b05e582b..7f2560bcc4adc2f398d87aa8066119ee9ec3b455 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -1304,7 +1304,7 @@ static void HU_drawMiniChat(void)
 
 				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_MONOSPACE|transflag, true, colormap);
 				dx += charwidth;
-				
+
 				if (dx >= boxw-charwidth-2)
 				{
 					dx = 0;
@@ -1555,9 +1555,9 @@ static void HU_DrawChat(void)
 				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; 
+					continue;
 				else if ((n == 3) && !(w_chat[3] == '0') && (!((i == 3) || ((i >= 30) && (i <= 31)))))
-					continue; 
+					continue;
 				else	// general case.
 					if (i != n) continue;
 			}
diff --git a/src/info.c b/src/info.c
index cf635c0114b16a838503b44752ab83ef7e4d41e8..4d3468e10fac23edeeea539cdac550ad9ab6057a 100644
--- a/src/info.c
+++ b/src/info.c
@@ -396,15 +396,6 @@ char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
 	"SSWY", // Yellow Side Spring
 	"SSWR", // Red Side Spring
 	"SSWB", // Blue Side Spring
-	"MPRY", // Yellow trampoline
-	"MPRR", // Red trampoline
-	"MPRB", // Blue trampoline
-	"MSWY", // Yellow horizontal trampoline
-	"MSWR", // Red horizontal trampoline
-	"MSWB", // Blue horizontal trampoline
-	"MDIY", // Yellow diagonal trampoline
-	"MDIR", // Red diagonal trampoline
-	"MDIB", // Blue diagonal trampoline
 	"BSTY", // Yellow Booster
 	"BSTR", // Red Booster
 
@@ -463,7 +454,6 @@ char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
 	"BGOM",
 	"FFWR",
 	"FBLL",
-	"MKOP",
 	"SHLL",
 	"PUMA",
 	"HAMM",
@@ -473,29 +463,6 @@ char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
 	"MUS1",
 	"MUS2",
 	"TOAD",
-	"MARS",
-	"MRFL",
-	"MAUH",
-	"MBSA",
-	"MBSB",
-	"MBSC",
-	"MFRE",
-	"MFYE",
-	"MFBE",
-	"MFWD",
-	"MUS3",
-
-	// Mario powerups
-	"MSIV", // invincibility
-	"MS1P", // 1-up
-	"MSAT", // attract
-	"MSFO", // force
-	"MSAR", // nuke
-	"MSWW", // whirlwind
-	"MSEL", // elemental
-	"MSSP", // speed shoes
-	"MEGH", // poison
-	"UPPB", // particle pickup
 
 	// NiGHTS Stuff
 	"NDRN", // NiGHTS drone
@@ -557,11 +524,6 @@ char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
 	"BRIR", // CEZ3 colored bricks
 	"BRIB", // CEZ3 colored bricks
 	"BRIY", // CEZ3 colored bricks
-	"MBRI",
-	"MBRS",
-	"MBRB",
-	"MBRC",
-	"MTRI",
 
 	// Gravity Well Objects
 	"GWLG",
@@ -638,6 +600,17 @@ char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1] =
 	"TALB",
 	"TALC",
 
+	"MSC0",
+	"MSC1",
+	"MSC2",
+	"MSC3",
+	"MSC4",
+	"MSC5",
+	"MSC6",
+	"MSC7",
+	"MSC8",
+	"MSC9",
+
 	"CNT1",
 	"CNT2",
 	"CNT3",
@@ -716,6 +689,17 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
 	SPR2_TAL0, // SPR2_TALB,
 	SPR2_TAL6, // SPR2_TALC,
 
+	0, // SPR2_MSC0,
+	0, // SPR2_MSC1,
+	0, // SPR2_MSC2,
+	0, // SPR2_MSC3,
+	0, // SPR2_MSC4,
+	0, // SPR2_MSC5,
+	0, // SPR2_MSC6,
+	0, // SPR2_MSC7,
+	0, // SPR2_MSC8,
+	0, // SPR2_MSC9,
+
 	SPR2_WAIT, // SPR2_CNT1,
 	SPR2_FALL, // SPR2_CNT2,
 	SPR2_SPNG, // SPR2_CNT3,
@@ -754,7 +738,7 @@ state_t states[NUMSTATES] =
 
 	// Player
 	{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_WAIT,                16, {NULL}, 0,  0, S_PLAY_WAIT, 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
@@ -1413,116 +1397,117 @@ state_t states[NUMSTATES] =
 	// Boss 5
 	{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, 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_PLAY, SPR2_ROLL, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5, 0}, // S_FANG_INTRO4
+	{SPR_PLAY, SPR2_ROLL, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6, 0}, // S_FANG_INTRO5
+	{SPR_PLAY, SPR2_ROLL, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7, 0}, // S_FANG_INTRO6
+	{SPR_PLAY, SPR2_ROLL, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8, 0}, // S_FANG_INTRO7
+	{SPR_PLAY, SPR2_ROLL, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5, 0}, // S_FANG_INTRO8
+	{SPR_PLAY, SPR2_MSC0|FF_ANIMATE, 50, {NULL}, 0, 4, S_FANG_INTRO10, 0}, // S_FANG_INTRO9
+	{SPR_PLAY, SPR2_MSC1, 5, {NULL}, 0, 0, S_FANG_INTRO11, 0}, // S_FANG_INTRO10
+	{SPR_PLAY, SPR2_MSC2, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12, 0}, // S_FANG_INTRO11
+	{SPR_PLAY, SPR2_CNT1|FF_ANIMATE, 50, {NULL}, 0, 4, S_FANG_IDLE1, 0}, // S_FANG_INTRO12
+
+	{SPR_PLAY, SPR2_SPNG, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2, 0}, // S_FANG_CLONE1
+	{SPR_PLAY, SPR2_SPNG, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3, 0}, // S_FANG_CLONE2
+	{SPR_PLAY, SPR2_FALL, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4, 0}, // S_FANG_CLONE3
+	{SPR_PLAY, SPR2_FALL, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4, 0}, // S_FANG_CLONE4
+
+	{SPR_PLAY,         0,  0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1, 0}, // S_FANG_IDLE0
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE2, 0}, // S_FANG_IDLE1
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE3, 0}, // S_FANG_IDLE2
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE4, 0}, // S_FANG_IDLE3
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE5, 0}, // S_FANG_IDLE4
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE6, 0}, // S_FANG_IDLE5
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE7, 0}, // S_FANG_IDLE6
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE8, 0}, // S_FANG_IDLE7
+	{SPR_PLAY, SPR2_WAIT, 16, {A_Look}, 1, 0, S_FANG_IDLE1, 0}, // S_FANG_IDLE8
+
+	{SPR_PLAY,         0, 0, {A_DoNPCPain}, FRACUNIT, 0, S_FANG_PAIN2, 0}, // S_FANG_PAIN1
+	{SPR_PLAY, SPR2_PAIN, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART1, S_FANG_PINCHPATHINGSTART1, S_FANG_PAIN2, 0}, // S_FANG_PAIN2
+
+	{SPR_PLAY,         0, 0, {A_Boss5ExtraRepeat}, 5, 4, S_FANG_PATHINGSTART2, 0}, // S_FANG_PATHINGSTART1
+	{SPR_PLAY,         0, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHING, 0}, // S_FANG_PATHINGSTART2
+	{SPR_PLAY,         0, 0, {A_Boss5FindWaypoint}, 0, 0, S_FANG_BOUNCE1, 0}, // S_FANG_PATHING
+
+	{SPR_PLAY, SPR2_LAND, 2, {A_Thrust}, 0, 1, S_FANG_BOUNCE2, 0}, // S_FANG_BOUNCE1
+	{SPR_PLAY, SPR2_LAND, 2, {NULL}, 0, 0, S_FANG_BOUNCE3, 0}, // S_FANG_BOUNCE2
+	{SPR_PLAY, SPR2_LAND, 1, {A_Boss5Jump}, 0, 0, S_FANG_BOUNCE4, 0}, // S_FANG_BOUNCE3
+	{SPR_PLAY, SPR2_BNCE, 1, {A_Boss5CheckFalling}, S_FANG_CHECKPATH1, S_FANG_FALL1, S_FANG_BOUNCE4, 0}, // S_FANG_BOUNCE4
+
+	{SPR_PLAY, SPR2_FALL, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL2, 0}, // S_FANG_FALL1
+	{SPR_PLAY, SPR2_FALL, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL1, 0}, // S_FANG_FALL2
+
+	{SPR_PLAY,         0, 0, {A_Boss5Calm}, 0, 0, S_FANG_CHECKPATH2, 0}, // S_FANG_CHECKPATH1
+	{SPR_PLAY,         0, 0, {A_Repeat}, 0, S_FANG_PATHINGCONT1, S_FANG_SKID1, 0}, // S_FANG_CHECKPATH2
+
+	{SPR_PLAY,         0, 0, {A_Boss5PinchShot}, MT_FBOMB, -16, S_FANG_PATHINGCONT2, 0}, // S_FANG_PATHINGCONT1
+	{SPR_PLAY,         0, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHINGCONT3, 0}, // S_FANG_PATHINGCONT2
+	{SPR_PLAY, SPR2_LAND, 2, {A_Thrust}, 0, 1, S_FANG_PATHING, 0}, // S_FANG_PATHINGCONT3
+
+	{SPR_PLAY,         0,  0, {A_PlayAttackSound}, 0, 0, S_FANG_SKID2, 0}, // S_FANG_SKID1
+	{SPR_PLAY, SPR2_SKID,  1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2, 0}, // S_FANG_SKID2
+	{SPR_PLAY, SPR2_SKID, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK, 0}, // S_FANG_SKID3
+
+	{SPR_PLAY,         0, 0, {A_RandomState}, S_FANG_LOBSHOT0, S_FANG_FIRESTART1, S_NULL, 0}, // S_FANG_CHOOSEATTACK
+
+	{SPR_PLAY,         0,  0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2, 0}, // S_FANG_FIRESTART1 // Reset loop
+	{SPR_PLAY, SPR2_FIRE, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1, 0}, // S_FANG_FIRESTART2
+	{SPR_PLAY, SPR2_FIRE,  2, {A_FireShot}, MT_CORK, -16, S_FANG_FIRE2, 0}, // S_FANG_FIRE1 // Start of loop
+	{SPR_PLAY, SPR2_FIRE,  2, {NULL}, 0, 0, S_FANG_FIRE3, 0}, // S_FANG_FIRE2
+	{SPR_PLAY, SPR2_FIRE, 16, {NULL}, 0, 0, S_FANG_FIREREPEAT, 0}, // S_FANG_FIRE3
+	{SPR_PLAY,         0,  0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1, 0}, // S_FANG_FIREREPEAT // End of loop
+
+	{SPR_PLAY, SPR2_MSC3, 14, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT1, 0}, // S_FANG_LOBSHOT0
+	{SPR_PLAY, SPR2_MSC3,  2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2, 0}, // S_FANG_LOBSHOT1
+	{SPR_PLAY, SPR2_MSC3,  2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT3, 0}, // S_FANG_LOBSHOT2
+	{SPR_PLAY, SPR2_MSC3, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1, 0}, // S_FANG_LOBSHOT3
+
+	{SPR_PLAY, SPR2_MLEL|FF_ANIMATE, 70, {NULL}, 0, 5, S_FANG_WAIT2, 0}, // S_FANG_WAIT1
+	{SPR_PLAY,            SPR2_STND, 35, {A_Look}, 1, 0, S_FANG_IDLE1, 0}, // S_FANG_WAIT2
+
+	{SPR_PLAY, SPR2_FALL, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART2, S_FANG_PINCHPATHINGSTART1, S_FANG_WALLHIT, 0}, // S_FANG_WALLHIT
+
+	{SPR_PLAY,         0,  0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2, 0}, // S_FANG_PINCHPATHINGSTART1
+	{SPR_PLAY,         0,  0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING, 0}, // S_FANG_PINCHPATHINGSTART2
+	{SPR_PLAY,         0,  0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE0, 0}, // S_FANG_PINCHPATHING
+	{SPR_PLAY,         0,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_FANG_PINCHBOUNCE1, 0}, // S_FANG_PINCHBOUNCE0
+	{SPR_PLAY, SPR2_LAND,  2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2, 0}, // S_FANG_PINCHBOUNCE1
+	{SPR_PLAY, SPR2_LAND,  2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3, 0}, // S_FANG_PINCHBOUNCE2
+	{SPR_PLAY, SPR2_LAND,  2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4, 0}, // S_FANG_PINCHBOUNCE3
+	{SPR_PLAY, SPR2_BNCE,  1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL0, S_FANG_PINCHBOUNCE4, 0}, // S_FANG_PINCHBOUNCE4
+	{SPR_PLAY,         0,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 1, S_FANG_PINCHFALL1, 0}, // S_FANG_PINCHFALL0
+	{SPR_PLAY, SPR2_FALL,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2, 0}, // S_FANG_PINCHFALL1
+	{SPR_PLAY, SPR2_FALL,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1, 0}, // S_FANG_PINCHFALL2
+	{SPR_PLAY,         0,  0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2, 0}, // S_FANG_PINCHSKID1
+	{SPR_PLAY, SPR2_SKID,  1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT0, 0, S_FANG_PINCHSKID2, 0}, // S_FANG_PINCHSKID2
+	{SPR_PLAY, SPR2_MSC3, 16, {A_FaceTarget}, 1, 5, S_FANG_PINCHLOBSHOT1, 0}, // S_FANG_PINCHLOBSHOT0
+	{SPR_PLAY, SPR2_MSC3,  2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2, 0}, // S_FANG_PINCHLOBSHOT1
+	{SPR_PLAY, SPR2_MSC3,  2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT3, 0}, // S_FANG_PINCHLOBSHOT2
+	{SPR_PLAY, SPR2_MSC3, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT4, 0}, // S_FANG_PINCHLOBSHOT3
+	{SPR_PLAY, SPR2_STND, 18, {A_LinedefExecuteFromArg}, 4, 0, S_FANG_PINCHLOBSHOT5, 0}, // S_FANG_PINCHLOBSHOT4
+	{SPR_PLAY,         0,  0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1, 0}, // S_FANG_PINCHLOBSHOT5
+
+	{SPR_PLAY,         0, 0, {A_DoNPCPain},                    0, 0, S_FANG_DIE2, 0}, // S_FANG_DIE1
+	{SPR_PLAY, SPR2_MSC4, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2, 0}, // S_FANG_DIE2
+
+	{SPR_PLAY,         0,  0, {A_Scream}, 0, 0, S_FANG_DIE4, 0}, // S_FANG_DIE3
+	{SPR_PLAY, SPR2_MSC5, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5, 0}, // S_FANG_DIE4
+
+	{SPR_PLAY,         0, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6, 0}, // S_FANG_DIE5
+	{SPR_PLAY, SPR2_JUMP, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7, 0}, // S_FANG_DIE6
+	{SPR_PLAY, SPR2_JUMP, 1, {A_Boss5CheckFalling}, S_FANG_FLEEPATHING1, S_FANG_DIE8, S_FANG_DIE7, 0}, // S_FANG_DIE7
+	{SPR_PLAY, SPR2_FALL, 1, {A_Boss5CheckOnGround}, S_FANG_FLEEPATHING1, 0, S_FANG_DIE8, 0}, // S_FANG_DIE8
+
+	{SPR_PLAY,         0,  0, {A_PlayActiveSound}, 0, 0, S_FANG_FLEEPATHING2, 0}, // S_FANG_FLEEPATHING1
+	{SPR_PLAY, SPR2_LAND,  2, {A_Boss5FindWaypoint}, 2, 0, S_FANG_FLEEBOUNCE1, 0}, // S_FANG_FLEEPATHING2
+	{SPR_PLAY, SPR2_LAND,  2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2, 0}, // S_FANG_FLEEBOUNCE1
+	{SPR_PLAY, SPR2_LAND, -1, {A_BossDeath}, 0, 0, S_NULL, 0}, // S_FANG_FLEEBOUNCE2
+
+	{SPR_PLAY, SPR2_DEAD, 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
@@ -1805,22 +1790,22 @@ state_t states[NUMSTATES] =
 	// Metal Sonic
 	{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_PLAY,               SPR2_WALK, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_FLOAT
+	{SPR_PLAY, SPR2_MSC1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN, 0}, // S_METALSONIC_VECTOR
+	{SPR_PLAY,               SPR2_MSC0, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},// S_METALSONIC_STUN
+	{SPR_PLAY, SPR2_SPNG, 20, {NULL},         0, 0, S_METALSONIC_GATHER, 0}, // S_METALSONIC_RAISE
+	{SPR_PLAY, SPR2_MSC2, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_GATHER
+	{SPR_PLAY, SPR2_DASH|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE, 0}, // S_METALSONIC_DASH
+	{SPR_PLAY, SPR2_MSC2|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_BOUNCE
+	{SPR_PLAY, SPR2_PAIN, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_BADBOUNCE
+	{SPR_PLAY, SPR2_SPNG, -1, {NULL},         0, 0, S_METALSONIC_GATHER, 0}, // S_METALSONIC_SHOOT
+	{SPR_PLAY, SPR2_FLT, 40, {A_Pain},       0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_PAIN
+	{SPR_PLAY, SPR2_SPNG,  2, {A_Fall},       0, 0, S_METALSONIC_DEATH2, 0}, // S_METALSONIC_DEATH1
+	{SPR_PLAY, SPR2_SPNG,  4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3, 0}, // S_METALSONIC_DEATH2
+	{SPR_PLAY, SPR2_SPNG,  0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4, 0}, // S_METALSONIC_DEATH3
+	{SPR_PLAY, SPR2_SPNG, -1, {A_BossDeath},  0, 0, S_NULL, 0}, // S_METALSONIC_DEATH4
+	{SPR_PLAY, SPR2_FLT,  1, {A_BossScream},         0, 0, S_METALSONIC_FLEE2, 0}, // S_METALSONIC_FLEE1
+	{SPR_PLAY, SPR2_FLT,  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
@@ -2685,16 +2670,15 @@ state_t states[NUMSTATES] =
 	// FHZ
 	{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
+	// Amy FHZ cameo
+	{SPR_PLAY, SPR2_CNT1|FF_ANIMATE,      -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_IDLE
+	{SPR_PLAY,            SPR2_MSC0,      -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_JUMP
+	{SPR_PLAY,            SPR2_MSC1,      -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_FALL
+	{SPR_PLAY,            SPR2_WALK,      -1, {NULL}, 7, 0, S_NULL, 0}, // S_ROSY_WALK
+	{SPR_PLAY,            SPR2_MSC2,      -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_HUG
+	{SPR_PLAY,            SPR2_PAIN,      -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_PAIN
+	{SPR_PLAY, SPR2_WAIT|FF_ANIMATE,      -1, {NULL}, 0, 5, S_NULL, 0}, // S_ROSY_STND
+	{SPR_PLAY, SPR2_MSC3|FF_ANIMATE, TICRATE, {NULL}, 0, 4, S_ROSY_WALK, 0}, // S_ROSY_UNHAPPY
 
 	// Halloween Scenery
 	// Pumpkins
@@ -3354,69 +3338,6 @@ state_t states[NUMSTATES] =
 	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ8, 0},   // S_BHORIZ7
 	{SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1, 0},   // S_BHORIZ8
 
-	// Yellow trampoline
-	{SPR_MPRY, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_YELLOWTRAMPOLINE
-	{SPR_MPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWTRAMPOLINE3, 0}, // S_YELLOWTRAMPOLINE2
-	{SPR_MPRY, 3, 1, {NULL}, 0, 0, S_YELLOWTRAMPOLINE4, 0},   // S_YELLOWTRAMPOLINE3
-	{SPR_MPRY, 2, 1, {NULL}, 0, 0, S_YELLOWTRAMPOLINE5, 0},   // S_YELLOWTRAMPOLINE4
-	{SPR_MPRY, 1, 1, {NULL}, 0, 0, S_YELLOWTRAMPOLINE, 0},   // S_YELLOWTRAMPOLINE5
-
-	// Red trampoline
-	{SPR_MPRR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_REDTRAMPOLINE
-	{SPR_MPRR, 4, 4, {A_Pain}, 0, 0, S_REDTRAMPOLINE3, 0}, // S_REDTRAMPOLINE2
-	{SPR_MPRR, 3, 1, {NULL}, 0, 0, S_REDTRAMPOLINE4, 0},   // S_REDTRAMPOLINE3
-	{SPR_MPRR, 2, 1, {NULL}, 0, 0, S_REDTRAMPOLINE5, 0},   // S_REDTRAMPOLINE4
-	{SPR_MPRR, 1, 1, {NULL}, 0, 0, S_REDTRAMPOLINE, 0},   // S_REDTRAMPOLINE5
-
-	// Blue trampoline
-	{SPR_MPRB, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_BLUETRAMPOLINE
-	{SPR_MPRB, 4, 4, {A_Pain}, 0, 0, S_BLUETRAMPOLINE3, 0}, // S_BLUETRAMPOLINE2
-	{SPR_MPRB, 3, 1, {NULL}, 0, 0, S_BLUETRAMPOLINE4, 0},   // S_BLUETRAMPOLINE3
-	{SPR_MPRB, 2, 1, {NULL}, 0, 0, S_BLUETRAMPOLINE5, 0},   // S_BLUETRAMPOLINE4
-	{SPR_MPRB, 1, 1, {NULL}, 0, 0, S_BLUETRAMPOLINE, 0},   // S_BLUETRAMPOLINE5
-
-	// Yellow horizontal trampoline
-	{SPR_MSWY, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_HORIZYELLOWTRAMPOLINE
-	{SPR_MSWY, 4, 4, {A_Pain}, 0, 0, S_HORIZYELLOWTRAMPOLINE3, 0}, // S_HORIZYELLOWTRAMPOLINE2
-	{SPR_MSWY, 3, 1, {NULL}, 0, 0, S_HORIZYELLOWTRAMPOLINE4, 0},   // S_HORIZYELLOWTRAMPOLINE3
-	{SPR_MSWY, 2, 1, {NULL}, 0, 0, S_HORIZYELLOWTRAMPOLINE5, 0},   // S_HORIZYELLOWTRAMPOLINE4
-	{SPR_MSWY, 1, 1, {NULL}, 0, 0, S_HORIZYELLOWTRAMPOLINE, 0},   // S_HORIZYELLOWTRAMPOLINE5
-
-	// Red horizontal trampoline
-	{SPR_MSWR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_HORIZREDTRAMPOLINE
-	{SPR_MSWR, 4, 4, {A_Pain}, 0, 0, S_HORIZREDTRAMPOLINE3, 0}, // S_HORIZREDTRAMPOLINE2
-	{SPR_MSWR, 3, 1, {NULL}, 0, 0, S_HORIZREDTRAMPOLINE4, 0},   // S_HORIZREDTRAMPOLINE3
-	{SPR_MSWR, 2, 1, {NULL}, 0, 0, S_HORIZREDTRAMPOLINE5, 0},   // S_HORIZREDTRAMPOLINE4
-	{SPR_MSWR, 1, 1, {NULL}, 0, 0, S_HORIZREDTRAMPOLINE, 0},   // S_HORIZREDTRAMPOLINE5
-
-	// Blue horizontal trampoline
-	{SPR_MSWB, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_HORIZBLUETRAMPOLINE
-	{SPR_MSWB, 4, 4, {A_Pain}, 0, 0, S_HORIZBLUETRAMPOLINE3, 0}, // S_HORIZBLUETRAMPOLINE2
-	{SPR_MSWB, 3, 1, {NULL}, 0, 0, S_HORIZBLUETRAMPOLINE4, 0},   // S_HORIZBLUETRAMPOLINE3
-	{SPR_MSWB, 2, 1, {NULL}, 0, 0, S_HORIZBLUETRAMPOLINE5, 0},   // S_HORIZBLUETRAMPOLINE4
-	{SPR_MSWB, 1, 1, {NULL}, 0, 0, S_HORIZBLUETRAMPOLINE, 0},   // S_HORIZBLUETRAMPOLINE5
-	
-	// Yellow diagonal trampoline
-	{SPR_MDIY, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_DIAGYELLOWTRAMPOLINE
-	{SPR_MDIY, 4, 4, {A_Pain}, 0, 0, S_DIAGYELLOWTRAMPOLINE3, 0}, // S_DIAGYELLOWTRAMPOLINE2
-	{SPR_MDIY, 3, 1, {NULL}, 0, 0, S_DIAGYELLOWTRAMPOLINE4, 0},   // S_DIAGYELLOWTRAMPOLINE3
-	{SPR_MDIY, 2, 1, {NULL}, 0, 0, S_DIAGYELLOWTRAMPOLINE5, 0},   // S_DIAGYELLOWTRAMPOLINE4
-	{SPR_MDIY, 1, 1, {NULL}, 0, 0, S_DIAGYELLOWTRAMPOLINE, 0},   // S_DIAGYELLOWTRAMPOLINE5
-
-	// Red diagonal trampoline
-	{SPR_MDIR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_DIAGREDTRAMPOLINE
-	{SPR_MDIR, 4, 4, {A_Pain}, 0, 0, S_DIAGREDTRAMPOLINE3, 0}, // S_DIAGREDTRAMPOLINE2
-	{SPR_MDIR, 3, 1, {NULL}, 0, 0, S_DIAGREDTRAMPOLINE4, 0},   // S_DIAGREDTRAMPOLINE3
-	{SPR_MDIR, 2, 1, {NULL}, 0, 0, S_DIAGREDTRAMPOLINE5, 0},   // S_DIAGREDTRAMPOLINE4
-	{SPR_MDIR, 1, 1, {NULL}, 0, 0, S_DIAGREDTRAMPOLINE, 0},   // S_DIAGREDTRAMPOLINE5
-
-	// Blue diagonal trampoline
-	{SPR_MDIB, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_DIAGBLUETRAMPOLINE
-	{SPR_MDIB, 4, 4, {A_Pain}, 0, 0, S_DIAGBLUETRAMPOLINE3, 0}, // S_DIAGBLUETRAMPOLINE2
-	{SPR_MDIB, 3, 1, {NULL}, 0, 0, S_DIAGBLUETRAMPOLINE4, 0},   // S_DIAGBLUETRAMPOLINE3
-	{SPR_MDIB, 2, 1, {NULL}, 0, 0, S_DIAGBLUETRAMPOLINE5, 0},   // S_DIAGBLUETRAMPOLINE4
-	{SPR_MDIB, 1, 1, {NULL}, 0, 0, S_DIAGBLUETRAMPOLINE, 0},   // S_DIAGBLUETRAMPOLINE5
-
 	// Boosters
 	{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
@@ -3712,33 +3633,41 @@ state_t states[NUMSTATES] =
 	{SPR_NULL, 0, 1, {A_RingExplode}, 0, 0, S_XPLD1, 0}, // S_RINGEXPLODE
 
 	// Coin
-	{SPR_COIN,  FF_ANIMATE,  32, {NULL}, 15, 2, S_COIN, 0}, // S_COIN
+	{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, 1|FF_FULLBRIGHT|FF_TRANS30|FF_ADD, 2, {A_ForceStop}, 0, 0, S_COINSPARKLE2, 0}, // S_COINSPARKLE1
-	{SPR_CPRK, 2|FF_FULLBRIGHT|FF_ANIMATE|FF_TRANS30|FF_ADD, 20, {NULL}, 9, 2, S_NULL, 0}, // S_COINSPARKLE2
+	{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, 0}, // S_GOOMBA1
 	{SPR_GOOM, 1, 6, {A_Look}, 0, 0, S_GOOMBA1, 0},  // S_GOOMBA1B
-	{SPR_GOOM, 0, 6, {A_Chase}, 0, 0, S_GOOMBA3, 0}, // S_GOOMBA2
-	{SPR_GOOM, 1, 6, {A_Chase}, 0, 0, S_GOOMBA4, 0}, // S_GOOMBA3
-	{SPR_GOOM, 2, 6, {A_Chase}, 0, 0, S_GOOMBA5, 0}, // S_GOOMBA4
-	{SPR_GOOM, 3, 6, {A_Chase}, 0, 0, S_GOOMBA2, 0}, // S_GOOMBA5
-	{SPR_GOOM, 4, 8, {A_Scream}, 0, 0, S_GOOMBA_DEAD2, 0},  // S_GOOMBA_DEAD
-	{SPR_GOOM, 5, 4, {NULL}, 0, 0, S_GOOMBA_DEAD3, 0},  // S_GOOMBA_DEAD2
-	{SPR_GOOM, 4, 15, {NULL}, 0, 0, S_NULL, 0},  // S_GOOMBA_DEAD3
+	{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, 0}, // S_BLUEGOOMBA1
 	{SPR_BGOM, 1, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1, 0},  // S_BLUEGOOMBA1B
-	{SPR_BGOM, 0, 6, {A_Chase}, 0, 0, S_BLUEGOOMBA3, 0}, // S_BLUEGOOMBA2
-	{SPR_BGOM, 1, 6, {A_Chase}, 0, 0, S_BLUEGOOMBA4, 0}, // S_BLUEGOOMBA3
-	{SPR_BGOM, 2, 6, {A_Chase}, 0, 0, S_BLUEGOOMBA5, 0}, // S_BLUEGOOMBA4
-	{SPR_BGOM, 3, 6, {A_Chase}, 0, 0, S_BLUEGOOMBA2, 0}, // S_BLUEGOOMBA5
-	{SPR_BGOM, 4, 8, {A_Scream}, 0, 0, S_BLUEGOOMBA_DEAD2, 0},  // S_BLUEGOOMBA_DEAD
-	{SPR_BGOM, 5, 4, {NULL}, 0, 0, S_BLUEGOOMBA_DEAD3, 0},  // S_BLUEGOOMBA_DEAD2
-	{SPR_BGOM, 4, 15, {NULL}, 0, 0, S_NULL, 0},  // S_BLUEGOOMBA_DEAD3
+	{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, 0}, // S_FIREFLOWER1
@@ -3751,16 +3680,7 @@ state_t states[NUMSTATES] =
 	{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
 
-	// Green Koopa
-	{SPR_MKOP, 0, 1, {A_Look}, 0, 0, S_GREENKOOPASPAWN, 0}, // S_GREENKOOPASPAWN
-	{SPR_MKOP, 0, 5, {A_GuardChase}, 1, 0, S_GREENKOOPA2, 0}, // S_GREENKOOPA1
-	{SPR_MKOP, 1, 5, {A_GuardChase}, 1, 0, S_GREENKOOPA3, 0}, // S_GREENKOOPA2
-	{SPR_MKOP, 2, 5, {A_GuardChase}, 1, 0, S_GREENKOOPA4, 0}, // S_GREENKOOPA3
-	{SPR_MKOP, 3, 5, {A_GuardChase}, 1, 0, S_GREENKOOPA1, 0}, // S_GREENKOOPA4
-	{SPR_MKOP, 3, 1, {A_Scream}, 0, 0, S_GREENKOOPADEATH2, 0}, // S_GREENKOOPADEATH1
-	{SPR_MKOP, 3, 1, {A_SpawnObjectRelative}, 0|0, 0|MT_SHELL, S_NULL, 0}, // S_GREENKOOPADEATH2
-
-	// Koopa Shell
+	// Turtle Shell
 	{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHELL
 
 	// Puma (Mario fireball)
@@ -3798,70 +3718,6 @@ state_t states[NUMSTATES] =
 	{SPR_MUS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MARIOBUSH2
 	{SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TOAD
 
-	{SPR_MARS, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_PTZSHROOM
-	{SPR_MRFL, 0|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_PTZFLAG2, 0}, // S_PTZFLAG1
-	{SPR_MRFL, 1|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_PTZFLAG3, 0}, // S_PTZFLAG2
-	{SPR_MRFL, 2|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_PTZFLAG4, 0}, // S_PTZFLAG3
-	{SPR_MRFL, 3|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_PTZFLAG5, 0}, // S_PTZFLAG4
-	{SPR_MRFL, 4|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_PTZFLAG1, 0}, // S_PTZFLAG5
-	{SPR_MAUH, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MARIOBUSH
-	{SPR_MBSA, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSBSHROOM
-	{SPR_MBSB, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLBSHROOM
-	{SPR_MBSC, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BNWSHROOM
-	{SPR_MFRE, FF_ANIMATE, -1, {NULL}, 3, 4, S_NULL, 0}, // S_REDMFLOWER
-	{SPR_MFBE, FF_ANIMATE, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BLUEMFLOWER
-	{SPR_MFYE, FF_ANIMATE, -1, {NULL}, 3, 4, S_NULL, 0}, // S_YELLOWMFLOWER
-	{SPR_MFWD, FF_ANIMATE, -1, {NULL}, 3, 6, S_NULL, 0}, // S_WHITEDANDELION
-	{SPR_MUS3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MAR64TREE
-
-	// Mario powerups
-	{SPR_MS1P, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_LIFESHROOM2, 0}, // S_LIFESHROOM
-	{SPR_MS1P, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_LIFESHROOM, 0}, // S_LIFESHROOM2
-	{SPR_MS1P, 0, 1, {A_ExtraLife}, 0, 0, S_PARTICLEPICKUP1, 0}, // S_LIFESHROOMD
-
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LIFESHROOM_INVISIBLE
-	{SPR_NULL, 0, 1, {A_ExtraLife}, 0, 0, S_NULL, 0}, // S_LIFESHROOM_INVISIBLE_TOUCH
-
-	{SPR_MEGH, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_POISONSHROOM2, 0}, // S_POISONSHROOM
-	{SPR_MEGH, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_POISONSHROOM, 0}, // S_POISONSHROOM2
-	{SPR_MEGH, 0, 1, {A_EggmanBox}, 0, 0, S_PARTICLEPICKUP1, 0}, // S_POISONSHROOMD
-
-	{SPR_MSAR, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_NUKESHROOM2, 0}, // S_NUKESHROOM
-	{SPR_MSAR, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_NUKESHROOM, 0}, // S_NUKESHROOM2
-	{SPR_MSAR, 0, 1, {A_GiveShield}, SH_ARMAGEDDON, 0, S_1000SCOREAWARD, 0}, // S_NUKESHROOMD
-
-	{SPR_MSFO, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_FORCESHROOM2, 0}, // S_FORCESHROOM
-	{SPR_MSFO, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_FORCESHROOM, 0}, // S_FORCESHROOM2
-	{SPR_MSFO, 0, 1, {A_GiveShield}, SH_FORCE|1, 0, S_1000SCOREAWARD, 0}, // S_FORCESHROOMD
-
-	{SPR_MSAT, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_ATTRACTSHROOM2, 0}, // S_ATTRACTSHROOM
-	{SPR_MSAT, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_ATTRACTSHROOM, 0}, // S_ATTRACTSHROOM2
-	{SPR_MSAT, 0, 1, {A_GiveShield}, SH_ATTRACT, 0, S_1000SCOREAWARD, 0}, // S_ATTRACTSHROOMD
-
-	{SPR_MSEL, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_ELEMENTALSHROOM2, 0}, // S_ELEMENTALSHROOM
-	{SPR_MSEL, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_ELEMENTALSHROOM, 0}, // S_ELEMENTALSHROOM2
-	{SPR_MSEL, 0, 1, {A_GiveShield}, SH_ELEMENTAL, 0, S_1000SCOREAWARD, 0}, // S_ELEMENTALSHROOMD
-
-	{SPR_MSWW, 0, 1, {A_FlickyHop}, FRACUNIT/6, 5*FRACUNIT, S_CLOUDSHROOM2, 0}, // S_CLOUDSHROOM
-	{SPR_MSWW, 0, 1, {A_FlickyAim}, ANGLE_90, 64*FRACUNIT, S_CLOUDSHROOM, 0}, // S_CLOUDSHROOM2
-	{SPR_MSWW, 0, 1, {A_GiveShield}, SH_WHIRLWIND, 0, S_1000SCOREAWARD, 0}, // S_CLOUDSHROOMD
-
-	{SPR_MSIV, 0, 1, {A_Look}, 3, 1, S_STARMAN, 0}, // S_STARMAN
-	{SPR_MSIV, 0, 2, {A_BunnyHop}, 7, 6, S_STARMAN2, 0}, // S_STARMAN1
-	{SPR_MSIV, 0, 1, {A_SmokeTrailer}, MT_BOXSPARKLE, 0, S_STARMAN3, 0}, // S_STARMAN2
-	{SPR_MSIV, 0, 1, {A_GhostMe}, 0, 0, S_STARMAN1, 0}, // S_STARMAN3
-	{SPR_MSIV, 0, 1, {A_Invincibility}, 0, 0, S_PARTICLEPICKUP1, 0}, // S_STARMAND
-
-	{SPR_MSSP, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SPEEDWINGS
-	{SPR_MSSP, 0, 1, {A_SuperSneakers}, 0, 0, S_NULL, 0}, // S_SPEEDWINGSD
-
-	{SPR_UPPB, FF_ADD, 1, {A_ForceStop}, 0, 0, S_PARTICLEPICKUP2, 0}, // S_PARTICLEPICKUP1
-	{SPR_UPPB, 1|FF_ANIMATE|FF_ADD, 19, {NULL}, 18, 1, S_NULL, 0}, // S_PARTICLEPICKUP2
-	{SPR_NULL, 0, 1, {A_SpawnObjectRelative}, 0, MT_POWERUPAWARD, S_PARTICLEPICKUP1, 0}, // S_1000SCOREAWARD
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_POWERUPAWARD1, 0}, // S_POWERUPAWARD
-	{SPR_NULL, 0, 1, {A_FindTarget}, MT_PLAYER, 0, S_POWERUPAWARD2, 0}, // S_POWERUPAWARD1
-	{SPR_NULL, 0, 1, {A_AwardScore}, 0, 0, S_NULL, 0}, // S_POWERUPAWARD2
-
 	// Nights Drone
 	{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
@@ -4174,11 +4030,6 @@ state_t states[NUMSTATES] =
 	{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_MBRI, FF_ANIMATE, 50, {NULL}, 9, 2, S_NULL, 0}, // S_MARIOBRICKDEBRIS
-	{SPR_MBRS, FF_ANIMATE, 50, {NULL}, 9, 2, S_NULL, 0}, // S_MARIOBRICKDEBRISS
-	{SPR_MBRB, FF_ANIMATE, 50, {NULL}, 9, 2, S_NULL, 0}, // S_MARIOBRICKDEBRISB
-	{SPR_MBRC, FF_ANIMATE, 50, {NULL}, 9, 2, S_NULL, 0}, // S_MARIOBRICKDEBRISC
-	{SPR_MTRI, FF_ANIMATE, 50, {NULL}, 3, 4, S_NULL, 0}, // S_MARIOBRICKDEBRISM
 
 	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL, 0}, // S_NAMECHECK
 
@@ -7991,249 +7842,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_BHORIZ2       // raisestate
 	},
 
-	{           // MT_YELLOWTRAMPOLINE
-		1814,            // doomednum
-		S_YELLOWTRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		20*FRACUNIT,    // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_YELLOWTRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_REDTRAMPOLINE
-		1815,            // doomednum
-		S_REDTRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		32*FRACUNIT,    // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_REDTRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_BLUETRAMPOLINE
-		1813,            // doomednum
-		S_BLUETRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		11*FRACUNIT,    // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_BLUETRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_HORIZYELLOWTRAMPOLINE
-		1817,            // doomednum
-		S_HORIZYELLOWTRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		0,    			// mass
-		36*FRACUNIT,    // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_HORIZYELLOWTRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_HORIZREDTRAMPOLINE
-		1818,            // doomednum
-		S_HORIZREDTRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		0,			    // mass
-		72*FRACUNIT,    // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_HORIZREDTRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_HORIZBLUETRAMPOLINE
-		1816,            // doomednum
-		S_HORIZBLUETRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		0,   			// mass
-		18*FRACUNIT,    // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_HORIZBLUETRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_DIAGYELLOWTRAMPOLINE
-		2551,           // doomednum
-		S_DIAGYELLOWTRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		20*FRACUNIT,    // mass
-		20*FRACUNIT,    // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_DIAGYELLOWTRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_DIAGREDTRAMPOLINE
-		2552,           // doomednum
-		S_DIAGREDTRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		32*FRACUNIT,    // mass
-		32*FRACUNIT,    // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_DIAGREDTRAMPOLINE2 // raisestate
-	},
-
-	{           // MT_DIAGBLUETRAMPOLINE
-		2550,           // doomednum
-		S_DIAGBLUETRAMPOLINE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_mariob,     // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		20*FRACUNIT,    // radius
-		16*FRACUNIT,    // height
-		0,              // display offset
-		11*FRACUNIT,    // mass
-		11*FRACUNIT,    // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SPRING, // flags
-		S_DIAGBLUETRAMPOLINE2 // raisestate
-	},
-
 	{          // MT_BOOSTERSEG
 		-1,             // doomednum
 		S_INVISIBLE,    // spawnstate
@@ -15202,7 +14810,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_ROSY
 		2104,           // doomednum
-		S_ROSY_IDLE1,   // spawnstate
+		S_ROSY_IDLE,    // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -19502,7 +19110,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_COIN
 		1800,           // doomednum
-		S_COIN,	        // spawnstate
+		S_COIN1,        // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -19529,7 +19137,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_FLINGCOIN
 		-1,             // doomednum
-		S_COIN,        	// spawnstate
+		S_COIN1,        // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -19689,33 +19297,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL               // raisestate
 	},
 
-	{           // MT_GREENKOOPA
-		1832,           	// doomednum
-		S_GREENKOOPASPAWN,  // spawnstate
-		1,              	// spawnhealth
-		S_GREENKOOPA1,      // seestate
-		sfx_None,      		// seesound
-		1,             		// reactiontime
-		sfx_None,      		// attacksound
-		S_NULL,         	// painstate
-		0,              	// painchance
-		sfx_None,       	// painsound
-		S_NULL,         	// meleestate
-		S_NULL,         	// missilestate
-		S_GREENKOOPADEATH1,	// deathstate
-		S_NULL,         	// xdeathstate
-		sfx_mario2,       	// deathsound
-		12,             	// speed
-		16*FRACUNIT,    	// radius
-		48*FRACUNIT,    	// height
-		0,              	// display offset
-		100,              	// mass
-		1,              	// damage
-		sfx_mario1,     	// activesound
-		MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY, // flags
-		S_NULL          	// raisestate
-	},
-
 	{           // MT_SHELL
 		1804,           // doomednum
 		S_SHELL,        // spawnstate
@@ -19985,9 +19566,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_PTZSHROOM
-		1811,           // doomednum
-		S_PTZSHROOM,    // spawnstate
+	{           // MT_AXIS
+		1700,           // doomednum
+		S_INVISIBLE,    // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -20001,20 +19582,20 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // deathstate
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		96*FRACUNIT,    // height
+		10*FRACUNIT,    // speed
+		256*FRACUNIT,   // radius
+		1*FRACUNIT,     // height
 		0,              // display offset
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
+		MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP, // flags
 		S_NULL          // raisestate
 	},
 
-	{           // MT_PTZFLAG
-		1812,           // doomednum
-		S_PTZFLAG1,     // spawnstate
+	{           // MT_AXISTRANSFER
+		1701,           // doomednum
+		S_INVISIBLE,    // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -20028,20 +19609,20 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // deathstate
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
-		0,              // speed
+		10,             // speed
 		16*FRACUNIT,    // radius
-		96*FRACUNIT,    // height
+		1,              // height
 		0,              // display offset
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP,    // flags
 		S_NULL          // raisestate
 	},
 
-	{           // MT_MARIOBUSH
-		1819,           // doomednum
-		S_MARIOBUSH,    // spawnstate
+	{           // MT_AXISTRANSFERLINE
+		1702,           // doomednum
+		S_INVISIBLE,    // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -20055,27 +19636,27 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // deathstate
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		96*FRACUNIT,    // height
+		10,             // speed
+		32*FRACUNIT,    // radius
+		1,              // height
 		0,              // display offset
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP,    // flags
 		S_NULL          // raisestate
 	},
 
-	{           // MT_BSBSHROOM
-		1820,           // doomednum
-		S_BSBSHROOM,    // spawnstate
-		1000,           // spawnhealth
+	{           // MT_NIGHTSDRONE
+		1703,           // doomednum
+		S_INVISIBLE,  // spawnstate
+		120,            // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
-		8,              // reactiontime
+		0,              // reactiontime
 		sfx_None,       // attacksound
 		S_NULL,         // painstate
-		0,              // painchance
+		255,            // painchance
 		sfx_None,       // painsound
 		S_NULL,         // meleestate
 		S_NULL,         // missilestate
@@ -20084,621 +19665,27 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		sfx_None,       // deathsound
 		0,              // speed
 		16*FRACUNIT,    // radius
-		96*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
+		80*FRACUNIT,    // height
+		1,              // display offset
+		1000,           // mass
 		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
+		sfx_ideya,      // activesound
+		MF_NOGRAVITY|MF_NOCLIP|MF_SPECIAL, // flags
 		S_NULL          // raisestate
 	},
 
-	{           // MT_BLBSHROOM
-		1821,           // doomednum
-		S_BLBSHROOM,    // spawnstate
-		1000,           // spawnhealth
+	{           // MT_NIGHTSDRONE_MAN
+		-1,           // doomednum
+		S_INVISIBLE,  // spawnstate
+		120,            // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
-		8,              // reactiontime
+		0,              // reactiontime
 		sfx_None,       // attacksound
 		S_NULL,         // painstate
-		0,              // painchance
+		255,            // painchance
 		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		96*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_BNWSHROOM
-		1822,           // doomednum
-		S_BNWSHROOM,    // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		96*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_REDMFLOWER
-		1823,           // doomednum
-		S_REDMFLOWER,   // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_BLUEMFLOWER
-		1842,           // doomednum
-		S_BLUEMFLOWER,  // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_YELLOWMFLOWER
-		1824,           // doomednum
-		S_YELLOWMFLOWER,// spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_WHITEDANDELION
-		1840,           // doomednum
-		S_WHITEDANDELION,   // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOCLIP|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_MAR64TREE
-		1847,           // doomednum
-		S_MAR64TREE,   // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		150*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SOLID|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_LIFESHROOM
-		1826,           // doomednum
-		S_LIFESHROOM,   // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_LIFESHROOMD,  // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_LIFESHROOM_INVISIBLE
-		1841,           // doomednum
-		S_LIFESHROOM_INVISIBLE, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_LIFESHROOM_INVISIBLE_TOUCH,  // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		-3072,          // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL|MF_NOGRAVITY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_POISONSHROOM
-		2303,           // doomednum
-		S_POISONSHROOM, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_POISONSHROOMD,// deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_NUKESHROOM
-		1829,           // doomednum
-		S_NUKESHROOM,   // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NUKESHROOMD,  // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_FORCESHROOM
-		1828,           // doomednum
-		S_FORCESHROOM,  // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_FORCESHROOMD, // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_ATTRACTSHROOM
-		1827,           // doomednum
-		S_ATTRACTSHROOM,// spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_ATTRACTSHROOMD, // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_ELEMENTALSHROOM
-		1831,           // doomednum
-		S_ELEMENTALSHROOM, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_ELEMENTALSHROOMD, // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_CLOUDSHROOM
-		1830,           // doomednum
-		S_CLOUDSHROOM,  // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_CLOUDSHROOMD, // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_STARMAN
-		1825,           // doomednum
-		S_STARMAN,      // spawnstate
-		1000,           // spawnhealth
-		S_STARMAN1,     // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_STARMAND,     // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_SPEEDWINGS
-		2304,           // doomednum
-		S_SPEEDWINGS,   // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_SPEEDWINGSD,  // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario3,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SPECIAL, 	// flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_POWERUPAWARD
-		-1,           // doomednum
-		S_POWERUPAWARD, // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_mario4,     // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		24*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_SLIDEME|MF_NOGRAVITY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_AXIS
-		1700,           // doomednum
-		S_INVISIBLE,    // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		10*FRACUNIT,    // speed
-		256*FRACUNIT,   // radius
-		1*FRACUNIT,     // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_AXISTRANSFER
-		1701,           // doomednum
-		S_INVISIBLE,    // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		10,             // speed
-		16*FRACUNIT,    // radius
-		1,              // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP,    // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_AXISTRANSFERLINE
-		1702,           // doomednum
-		S_INVISIBLE,    // spawnstate
-		1000,           // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		8,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		10,             // speed
-		32*FRACUNIT,    // radius
-		1,              // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP,    // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_NIGHTSDRONE
-		1703,           // doomednum
-		S_INVISIBLE,  // spawnstate
-		120,            // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		255,            // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		16*FRACUNIT,    // radius
-		80*FRACUNIT,    // height
-		1,              // display offset
-		1000,           // mass
-		0,              // damage
-		sfx_ideya,      // activesound
-		MF_NOGRAVITY|MF_NOCLIP|MF_SPECIAL, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_NIGHTSDRONE_MAN
-		-1,           // doomednum
-		S_INVISIBLE,  // spawnstate
-		120,            // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		255,            // painchance
-		sfx_None,       // painsound
-		S_NIGHTSDRONE_MAN1, // meleestate
+		S_NIGHTSDRONE_MAN1, // meleestate
 		S_NULL,         // missilestate
 		S_NULL,         // deathstate
 		S_NULL,         // xdeathstate
@@ -22795,141 +21782,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_MARIOBRICKDEBRIS
-		-1,             // doomednum
-		S_MARIOBRICKDEBRIS,    // spawnstate
-		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		35,             // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		6,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_marioc,     // activesound
-		MF_NOCLIPHEIGHT|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_MARIOBRICKDEBRISS
-		-1,             // doomednum
-		S_MARIOBRICKDEBRISS,    // spawnstate
-		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		35,             // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		6,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_marioc,     // activesound
-		MF_NOCLIPHEIGHT|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_MARIOBRICKDEBRISB
-		-1,             // doomednum
-		S_MARIOBRICKDEBRISB,    // spawnstate
-		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		35,             // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		6,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_marioc,     // activesound
-		MF_NOCLIPHEIGHT|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_MARIOBRICKDEBRISC
-		-1,             // doomednum
-		S_MARIOBRICKDEBRISC,    // spawnstate
-		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		35,             // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		6,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_marioc,     // activesound
-		MF_NOCLIPHEIGHT|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
-	{           // MT_MARIOBRICKDEBRISM
-		-1,             // doomednum
-		S_MARIOBRICKDEBRISM,    // spawnstate
-		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		35,             // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		0,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		6,              // speed
-		16*FRACUNIT,    // radius
-		48*FRACUNIT,    // height
-		0,              // display offset
-		100,            // mass
-		0,              // damage
-		sfx_marioc,     // activesound
-		MF_NOCLIPHEIGHT|MF_SCENERY, // flags
-		S_NULL          // raisestate
-	},
-
 	{           // MT_NAMECHECK
 		-1,             // doomednum
 		S_NAMECHECK,    // spawnstate
@@ -23045,15 +21897,15 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Moss",      {0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f}, SKINCOLOR_BEIGE,     13, V_GREENMAP,  true}, // SKINCOLOR_MOSS
 	{"Azure",     {0x90, 0x90, 0x91, 0x91, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf}, SKINCOLOR_PINK,      5,  V_AZUREMAP,  true}, // SKINCOLOR_AZURE
 	{"Eggplant",  {   4,   8,    11,   11,   16,  195,  195,  195,  196,  186,  187,  187,  254,  254,   30,   31}, SKINCOLOR_ROSEBUSH,  5,  V_PURPLEMAP, true}, // SKINCOLOR_EGGPLANT
-	{"Lavender",  {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_GOLD,      4,  V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER
+	{"Lavender",  {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_HEADLIGHT, 8,  V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER
 
 	// Viv's vivid colours (toast 21/07/17)
 	// Tweaks & additions (Lach, Chrispy, sphere, Alice, MotorRoach & Saneko 26/10/22)
 	{"Ruby",       {0xb0, 0xb0, 0xc9, 0xca, 0xcc, 0x26, 0x27, 0x28, 0x29, 0x2a, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfd}, SKINCOLOR_EMERALD,    10, V_REDMAP,     true}, // SKINCOLOR_RUBY
 	{"Cherry",     { 202,  203,  204,  205,  206,   40,   41,   42,   43,   44,  186,  187,   28,   29,   30,   31}, SKINCOLOR_MIDNIGHT,   10, V_REDMAP,     true}, // SKINCOLOR_CHERRY
 	{"Salmon",     {0xd0, 0xd0, 0xd1, 0xd2, 0x20, 0x21, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e}, SKINCOLOR_FOREST,     6,  V_REDMAP,     true}, // SKINCOLOR_SALMON
-	{"Pepper",     { 210,   32,   33,   34,   35,   35,   36,   37,   38,   39,   41,   43,   45,   45,   46,   47}, SKINCOLOR_MASTER,     8,  V_REDMAP,     true}, // SKINCOLOR_PEPPER
-	{"Red",        {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, SKINCOLOR_GREEN,      10, V_REDMAP,     true}, // SKINCOLOR_RED
+	{"Pepper",     { 210,   32,   33,   34,   35,   35,   36,   37,   38,   39,   41,   43,   45,   45,   46,   47}, SKINCOLOR_GREEN,      10, V_REDMAP,     true}, // SKINCOLOR_PEPPER
+	{"Red",        {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, SKINCOLOR_MASTER,     8,  V_REDMAP,     true}, // SKINCOLOR_RED
 	{"Crimson",    {0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x1f}, SKINCOLOR_ICY,        10, V_REDMAP,     true}, // SKINCOLOR_CRIMSON
 	{"Flame",      {0x31, 0x32, 0x33, 0x36, 0x22, 0x22, 0x25, 0x25, 0x25, 0xcd, 0xcf, 0xcf, 0xc5, 0xc5, 0xc7, 0xc7}, SKINCOLOR_PURPLE,     8,  V_REDMAP,     true}, // SKINCOLOR_FLAME
 	{"Garnet",     {   0,   83,   50,   53,   34,   35,   37,   38,   39,   40,   42,   44,   45,   46,   47,   47}, SKINCOLOR_AQUAMARINE, 6,  V_REDMAP,     true}, // SKINCOLOR_GARNET
@@ -23068,7 +21920,7 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Rust",       {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3f, 0x2c, 0x2d, 0x47, 0x2e, 0x2f, 0x2f}, SKINCOLOR_YOGURT,     8,  V_ORANGEMAP,  true}, // SKINCOLOR_RUST
 	{"Tangerine",  {  81,   83,   64,   64,   51,   52,   53,   54,   56,   58,   60,   61,   63,   45,   46,   47}, SKINCOLOR_OCEAN,      12, V_ORANGEMAP,  true}, // SKINCOLOR_TANGERINE
 	{"Topaz",      {   0,   81,   83,   73,   74,   74,   65,   52,   53,   54,   56,   58,   60,   42,   43,   45}, SKINCOLOR_MOONSTONE,  10, V_YELLOWMAP,  true}, // SKINCOLOR_TOPAZ
-	{"Gold",       {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_LAVENDER,   10, V_YELLOWMAP,  true}, // SKINCOLOR_GOLD
+	{"Gold",       {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_MAUVE,      8,  V_YELLOWMAP,  true}, // SKINCOLOR_GOLD
 	{"Sandy",      {0x53, 0x40, 0x41, 0x42, 0x43, 0xe6, 0xe9, 0xe9, 0xea, 0xec, 0xec, 0xc6, 0xc6, 0xc7, 0xc7, 0xfe}, SKINCOLOR_SKY,        8,  V_YELLOWMAP,  true}, // SKINCOLOR_SANDY
 	{"Goldenrod",  {   0,   80,   81,   81,   83,   73,   73,   64,   65,   66,   67,   68,   69,   62,   44,   45}, SKINCOLOR_MAJESTY,    8,  V_YELLOWMAP,  true}, // SKINCOLOR_GOLDENROD
 	{"Yellow",     {0x52, 0x53, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0xed}, SKINCOLOR_CORNFLOWER, 8,  V_YELLOWMAP,  true}, // SKINCOLOR_YELLOW
@@ -23078,19 +21930,19 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Lime",       {0x50, 0x51, 0x52, 0x53, 0x48, 0xbc, 0xbd, 0xbe, 0xbe, 0xbf, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_MAGENTA,    9,  V_PERIDOTMAP, true}, // SKINCOLOR_LIME
 	{"Peridot",    {0x58, 0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0x5e, 0x5e, 0x5f, 0x5f, 0x77, 0x77}, SKINCOLOR_COBALT,     2,  V_PERIDOTMAP, true}, // SKINCOLOR_PERIDOT
 	{"Apple",      {0x49, 0x49, 0xbc, 0xbd, 0xbe, 0xbe, 0xbe, 0x67, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6d}, SKINCOLOR_RASPBERRY,  13, V_PERIDOTMAP, true}, // SKINCOLOR_APPLE
-	{"Headlight",  {   0,   80,   81,   82,   73,   84,   64,   65,   91,   91,  124,  125,  126,  137,  138,  139}, SKINCOLOR_MAUVE,      8,  V_YELLOWMAP,  true}, // SKINCOLOR_HEADLIGHT
+	{"Headlight",  {   0,   80,   81,   82,   73,   84,   64,   65,   91,   91,  124,  125,  126,  137,  138,  139}, SKINCOLOR_LAVENDER,   10, V_YELLOWMAP,  true}, // SKINCOLOR_HEADLIGHT
 	{"Chartreuse", {  80,   82,   72,   73,  188,  188,  113,  114,  114,  125,  126,  137,  138,  139,  253,  254}, SKINCOLOR_NOBLE,      9,  V_PERIDOTMAP, true}, // SKINCOLOR_CHARTREUSE
-	{"Green",      {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_RED,        6,  V_GREENMAP,   true}, // SKINCOLOR_GREEN
+	{"Green",      {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_PEPPER,     8,  V_GREENMAP,   true}, // SKINCOLOR_GREEN
 	{"Forest",     {0x65, 0x66, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f}, SKINCOLOR_SALMON,     9,  V_GREENMAP,   true}, // SKINCOLOR_FOREST
 	{"Shamrock",   {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, SKINCOLOR_SIBERITE,   10, V_GREENMAP,   true}, // SKINCOLOR_SHAMROCK
-	{"Jade",       { 128,  120,  121,  122,  122,  113,  114,  114,  115,  116,  117,  118,  119,  110,  111,   30}, SKINCOLOR_TAFFY,      10, V_GREENMAP,   true}, // SKINCOLOR_JADE
+	{"Jade",       { 128,  120,  121,  122,  122,  113,  114,  114,  115,  116,  117,  118,  119,  110,  111,   30}, SKINCOLOR_ROSY,       7,  V_GREENMAP,   true}, // SKINCOLOR_JADE
 	{"Mint",       {0x00, 0x00, 0x58, 0x58, 0x59, 0x62, 0x62, 0x62, 0x64, 0x67, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a}, SKINCOLOR_VIOLET,     5,  V_GREENMAP,   true}, // SKINCOLOR_MINT
-	{"Master",     {   0,   80,   88,   96,  112,  113,   99,  100,  124,  125,  126,  117,  107,  118,  119,  111}, SKINCOLOR_PEPPER,     8,  V_GREENMAP,   true}, // SKINCOLOR_MASTER
+	{"Master",     {   0,   80,   88,   96,  112,  113,   99,  100,  124,  125,  126,  117,  107,  118,  119,  111}, SKINCOLOR_RED,        6,  V_GREENMAP,   true}, // SKINCOLOR_MASTER
 	{"Emerald",    {  80,   96,  112,  113,  114,  114,  125,  125,  126,  126,  137,  137,  138,  138,  139,  139}, SKINCOLOR_RUBY,       9,  V_GREENMAP,   true}, // SKINCOLOR_EMERALD
 	{"Seafoam",    {0x01, 0x58, 0x59, 0x5a, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a, 0x8b, 0xfd, 0xfd}, SKINCOLOR_PLUM,       6,  V_AQUAMAP,    true}, // SKINCOLOR_SEAFOAM
 	{"Island",     {  96,   97,  113,  113,  114,  124,  142,  136,  136,  150,  151,  153,  168,  168,  169,  169}, SKINCOLOR_GALAXY,     7,  V_AQUAMAP,    true}, // SKINCOLOR_ISLAND
 	{"Bottle",     {   0,    1,    3,    4,    5,  140,  141,  141,  124,  125,  126,  127,  118,  119,  111,  111}, SKINCOLOR_LATTE,      14, V_AQUAMAP,    true}, // SKINCOLOR_BOTTLE
-	{"Aqua",       {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_ROSY,       7,  V_AQUAMAP,    true}, // SKINCOLOR_AQUA
+	{"Aqua",       {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_TAFFY,      10, V_AQUAMAP,    true}, // SKINCOLOR_AQUA
 	{"Teal",       {0x78, 0x78, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0x8a}, SKINCOLOR_PEACHY,     7,  V_SKYMAP,     true}, // SKINCOLOR_TEAL
 	{"Ocean",      { 120,  121,  122,  122,  123,  141,  142,  142,  136,  137,  138,  138,  139,  139,  253,  253}, SKINCOLOR_TANGERINE,  4,  V_AQUAMAP,    true}, // SKINCOLOR_OCEAN
 	{"Wave",       {0x00, 0x78, 0x78, 0x79, 0x8d, 0x87, 0x88, 0x89, 0x89, 0xae, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfd}, SKINCOLOR_QUAIL,      5,  V_SKYMAP,     true}, // SKINCOLOR_WAVE
@@ -23124,12 +21976,12 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Violet",     {0xd0, 0xd1, 0xd2, 0xca, 0xcc, 0xb8, 0xb9, 0xb9, 0xba, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfe, 0xfe}, SKINCOLOR_MINT,       6,  V_MAGENTAMAP, true}, // SKINCOLOR_VIOLET
 	{"Royal",      { 208,  209,  192,  192,  192,  193,  193,  194,  194,  172,  173,  174,  175,  175,  139,  139}, SKINCOLOR_FANCY,      9,  V_PURPLEMAP,  true}, // SKINCOLOR_ROYAL
 	{"Lilac",      {0x00, 0xd0, 0xd1, 0xd2, 0xd3, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xfe, 0x1f}, SKINCOLOR_VAPOR,      4,  V_ROSYMAP,    true}, // SKINCOLOR_LILAC
-	{"Mauve",      { 176,  177,  178,  192,  193,  194,  195,  195,  196,  185,  185,  186,  186,  187,  187,  253}, SKINCOLOR_HEADLIGHT,  8,  V_PURPLEMAP,  true}, // SKINCOLOR_MAUVE
+	{"Mauve",      { 176,  177,  178,  192,  193,  194,  195,  195,  196,  185,  185,  186,  186,  187,  187,  253}, SKINCOLOR_GOLD,       4,  V_PURPLEMAP,  true}, // SKINCOLOR_MAUVE
 	{"Eventide",   {  51,   52,   53,   33,   34,  204,  183,  183,  184,  184,  166,  167,  168,  169,  253,  254}, SKINCOLOR_DAYBREAK,   13, V_MAGENTAMAP, true}, // SKINCOLOR_EVENTIDE
 	{"Plum",       {0xc8, 0xd3, 0xd5, 0xd6, 0xd7, 0xce, 0xcf, 0xb9, 0xb9, 0xba, 0xba, 0xa9, 0xa9, 0xa9, 0xfd, 0xfe}, SKINCOLOR_MINT,       7,  V_ROSYMAP,    true}, // SKINCOLOR_PLUM
 	{"Raspberry",  {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, SKINCOLOR_APPLE,      13, V_ROSYMAP,    true}, // SKINCOLOR_RASPBERRY
-	{"Taffy",      {   1,  176,  176,  177,  178,  179,  202,  203,  204,  204,  205,  206,  207,   44,   45,   46}, SKINCOLOR_JADE,       8,  V_ROSYMAP,    true}, // SKINCOLOR_TAFFY
-	{"Rosy",       {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_AQUA,       1,  V_ROSYMAP,    true}, // SKINCOLOR_ROSY
+	{"Taffy",      {   1,  176,  176,  177,  178,  179,  202,  203,  204,  204,  205,  206,  207,   44,   45,   46}, SKINCOLOR_AQUA,       1,  V_ROSYMAP,    true}, // SKINCOLOR_TAFFY
+	{"Rosy",       {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_JADE,       8,  V_ROSYMAP,    true}, // SKINCOLOR_ROSY
 	{"Fancy",      {   0,  208,   49,  210,  210,  202,  202,  203,  204,  204,  205,  206,  207,  207,  186,  186}, SKINCOLOR_ROYAL,      9,  V_ROSYMAP,    true}, // SKINCOLOR_FANCY
 	{"Sangria",    { 210,   32,   33,   34,   34,  215,  215,  207,  207,  185,  186,  186,  186,  169,  169,  253}, SKINCOLOR_TURQUOISE,  12, V_ROSYMAP,    true}, // SKINCOLOR_SANGRIA
 	{"Volcanic",   {  54,   36,   42,   44,   45,   46,   46,   47,   28,  253,  253,  254,  254,   30,   31,   31}, SKINCOLOR_BRONZE,     9,  V_REDMAP,     true}, // SKINCOLOR_VOLCANIC
diff --git a/src/info.h b/src/info.h
index bf83068877c850457f2f50bd16fa7aee7cbfb3be..94b0aeb48111178e2262a1f1144c7ff623fb3a43 100644
--- a/src/info.h
+++ b/src/info.h
@@ -947,15 +947,6 @@ typedef enum sprite
 	SPR_SSWY, // Yellow Side Spring
 	SPR_SSWR, // Red Side Spring
 	SPR_SSWB, // Blue Side Spring
-	SPR_MPRY, // Yellow trampoline
-	SPR_MPRR, // Red trampoline
-	SPR_MPRB, // Blue trampoline
-	SPR_MSWY, // Yellow horizontal trampoline
-	SPR_MSWR, // Red horizontal trampoline
-	SPR_MSWB, // Blue horizontal trampoline
-	SPR_MDIY, // Yellow diagonal trampoline
-	SPR_MDIR, // Red diagonal trampoline
-	SPR_MDIB, // Blue diagonal trampoline
 	SPR_BSTY, // Yellow Booster
 	SPR_BSTR, // Red Booster
 
@@ -1014,7 +1005,6 @@ typedef enum sprite
 	SPR_BGOM,
 	SPR_FFWR,
 	SPR_FBLL,
-	SPR_MKOP,
 	SPR_SHLL,
 	SPR_PUMA,
 	SPR_HAMM,
@@ -1024,29 +1014,6 @@ typedef enum sprite
 	SPR_MUS1,
 	SPR_MUS2,
 	SPR_TOAD,
-	SPR_MARS,
-	SPR_MRFL,
-	SPR_MAUH,
-	SPR_MBSA,
-	SPR_MBSB,
-	SPR_MBSC,
-	SPR_MFRE,
-	SPR_MFYE,
-	SPR_MFBE,
-	SPR_MFWD,
-	SPR_MUS3,
-
-	// Mario powerups
-	SPR_MSIV, // invincibility
-	SPR_MS1P, // 1-up
-	SPR_MSAT, // attract
-	SPR_MSFO, // force
-	SPR_MSAR, // nuke
-	SPR_MSWW, // whirlwind
-	SPR_MSEL, // elemental
-	SPR_MSSP, // speed shoes
-	SPR_MEGH, // poison
-	SPR_UPPB, // particle pickup
 
 	// NiGHTS Stuff
 	SPR_NDRN, // NiGHTS drone
@@ -1108,11 +1075,6 @@ typedef enum sprite
 	SPR_BRIR, // CEZ3 colored bricks
 	SPR_BRIB,
 	SPR_BRIY,
-	SPR_MBRI,
-	SPR_MBRS,
-	SPR_MBRB,
-	SPR_MBRC,
-	SPR_MTRI,
 
 	// Gravity Well Objects
 	SPR_GWLG,
@@ -1194,6 +1156,18 @@ typedef enum playersprite
 	SPR2_TALB,
 	SPR2_TALC,
 
+	// Misc slots
+	SPR2_MSC0,
+	SPR2_MSC1,
+	SPR2_MSC2,
+	SPR2_MSC3,
+	SPR2_MSC4,
+	SPR2_MSC5,
+	SPR2_MSC6,
+	SPR2_MSC7,
+	SPR2_MSC8,
+	SPR2_MSC9,
+
 	SPR2_CNT1, // continue disappointment
 	SPR2_CNT2, // continue lift
 	SPR2_CNT3, // continue spin
@@ -1941,11 +1915,11 @@ typedef enum state
 	S_FANG_FIRE1,
 	S_FANG_FIRE2,
 	S_FANG_FIRE3,
-	S_FANG_FIRE4,
 	S_FANG_FIREREPEAT,
 	S_FANG_LOBSHOT0,
 	S_FANG_LOBSHOT1,
 	S_FANG_LOBSHOT2,
+	S_FANG_LOBSHOT3,
 	S_FANG_WAIT1,
 	S_FANG_WAIT2,
 	S_FANG_WALLHIT,
@@ -1967,6 +1941,7 @@ typedef enum state
 	S_FANG_PINCHLOBSHOT2,
 	S_FANG_PINCHLOBSHOT3,
 	S_FANG_PINCHLOBSHOT4,
+	S_FANG_PINCHLOBSHOT5,
 	S_FANG_DIE1,
 	S_FANG_DIE2,
 	S_FANG_DIE3,
@@ -3116,11 +3091,9 @@ typedef enum state
 	// FHZ
 	S_FHZICE1,
 	S_FHZICE2,
-	S_ROSY_IDLE1,
-	S_ROSY_IDLE2,
-	S_ROSY_IDLE3,
-	S_ROSY_IDLE4,
+	S_ROSY_IDLE,
 	S_ROSY_JUMP,
+	S_ROSY_FALL,
 	S_ROSY_WALK,
 	S_ROSY_HUG,
 	S_ROSY_PAIN,
@@ -3780,69 +3753,6 @@ typedef enum state
 	S_BHORIZ7,
 	S_BHORIZ8,
 
-	// Yellow Trampoline
-	S_YELLOWTRAMPOLINE,
-	S_YELLOWTRAMPOLINE2,
-	S_YELLOWTRAMPOLINE3,
-	S_YELLOWTRAMPOLINE4,
-	S_YELLOWTRAMPOLINE5,
-
-	// Red Trampoline
-	S_REDTRAMPOLINE,
-	S_REDTRAMPOLINE2,
-	S_REDTRAMPOLINE3,
-	S_REDTRAMPOLINE4,
-	S_REDTRAMPOLINE5,
-
-	// Blue Trampoline
-	S_BLUETRAMPOLINE,
-	S_BLUETRAMPOLINE2,
-	S_BLUETRAMPOLINE3,
-	S_BLUETRAMPOLINE4,
-	S_BLUETRAMPOLINE5,
-
-	// Horizontal Yellow Trampoline
-	S_HORIZYELLOWTRAMPOLINE,
-	S_HORIZYELLOWTRAMPOLINE2,
-	S_HORIZYELLOWTRAMPOLINE3,
-	S_HORIZYELLOWTRAMPOLINE4,
-	S_HORIZYELLOWTRAMPOLINE5,
-
-	// Horizontal Red Trampoline
-	S_HORIZREDTRAMPOLINE,
-	S_HORIZREDTRAMPOLINE2,
-	S_HORIZREDTRAMPOLINE3,
-	S_HORIZREDTRAMPOLINE4,
-	S_HORIZREDTRAMPOLINE5,
-
-	// Horizontal Blue Trampoline
-	S_HORIZBLUETRAMPOLINE,
-	S_HORIZBLUETRAMPOLINE2,
-	S_HORIZBLUETRAMPOLINE3,
-	S_HORIZBLUETRAMPOLINE4,
-	S_HORIZBLUETRAMPOLINE5,
-
-	// Diagonal Yellow Trampoline
-	S_DIAGYELLOWTRAMPOLINE,
-	S_DIAGYELLOWTRAMPOLINE2,
-	S_DIAGYELLOWTRAMPOLINE3,
-	S_DIAGYELLOWTRAMPOLINE4,
-	S_DIAGYELLOWTRAMPOLINE5,
-
-	// Diagonal Red Trampoline
-	S_DIAGREDTRAMPOLINE,
-	S_DIAGREDTRAMPOLINE2,
-	S_DIAGREDTRAMPOLINE3,
-	S_DIAGREDTRAMPOLINE4,
-	S_DIAGREDTRAMPOLINE5,
-
-	// Diagonal Blue Trampoline
-	S_DIAGBLUETRAMPOLINE,
-	S_DIAGBLUETRAMPOLINE2,
-	S_DIAGBLUETRAMPOLINE3,
-	S_DIAGBLUETRAMPOLINE4,
-	S_DIAGBLUETRAMPOLINE5,
-
 	// Booster
 	S_BOOSTERSOUND,
 	S_YELLOWBOOSTERROLLER,
@@ -4115,28 +4025,37 @@ typedef enum state
 
 	S_RINGEXPLODE,
 
-	// Mario-specific stuff
-	S_COIN,
+	S_COIN1,
+	S_COIN2,
+	S_COIN3,
 	S_COINSPARKLE1,
 	S_COINSPARKLE2,
+	S_COINSPARKLE3,
+	S_COINSPARKLE4,
 	S_GOOMBA1,
 	S_GOOMBA1B,
 	S_GOOMBA2,
 	S_GOOMBA3,
 	S_GOOMBA4,
 	S_GOOMBA5,
+	S_GOOMBA6,
+	S_GOOMBA7,
+	S_GOOMBA8,
+	S_GOOMBA9,
 	S_GOOMBA_DEAD,
-	S_GOOMBA_DEAD2,
-	S_GOOMBA_DEAD3,
 	S_BLUEGOOMBA1,
 	S_BLUEGOOMBA1B,
 	S_BLUEGOOMBA2,
 	S_BLUEGOOMBA3,
 	S_BLUEGOOMBA4,
 	S_BLUEGOOMBA5,
+	S_BLUEGOOMBA6,
+	S_BLUEGOOMBA7,
+	S_BLUEGOOMBA8,
+	S_BLUEGOOMBA9,
 	S_BLUEGOOMBA_DEAD,
-	S_BLUEGOOMBA_DEAD2,
-	S_BLUEGOOMBA_DEAD3,
+
+	// Mario-specific stuff
 	S_FIREFLOWER1,
 	S_FIREFLOWER2,
 	S_FIREFLOWER3,
@@ -4144,13 +4063,6 @@ typedef enum state
 	S_FIREBALL,
 	S_FIREBALLTRAIL1,
 	S_FIREBALLTRAIL2,
-	S_GREENKOOPASPAWN,
-	S_GREENKOOPA1,
-	S_GREENKOOPA2,
-	S_GREENKOOPA3,
-	S_GREENKOOPA4,
-	S_GREENKOOPADEATH1,
-	S_GREENKOOPADEATH2,
 	S_SHELL,
 	S_PUMA_START1,
 	S_PUMA_START2,
@@ -4176,68 +4088,7 @@ typedef enum state
 	S_MARIOBUSH1,
 	S_MARIOBUSH2,
 	S_TOAD,
-	S_PTZSHROOM,
-	S_PTZFLAG1,
-	S_PTZFLAG2,
-	S_PTZFLAG3,
-	S_PTZFLAG4,
-	S_PTZFLAG5,
-	S_MARIOBUSH,
-	S_BSBSHROOM,
-	S_BLBSHROOM,
-	S_BNWSHROOM,
-	S_REDMFLOWER,
-	S_BLUEMFLOWER,
-	S_YELLOWMFLOWER,
-	S_WHITEDANDELION,
-	S_MAR64TREE,
-
-	// Power up mushrooms
-	S_LIFESHROOM,
-	S_LIFESHROOM2,
-	S_LIFESHROOMD,
-	S_LIFESHROOM_INVISIBLE,
-	S_LIFESHROOM_INVISIBLE_TOUCH,
-
-	S_POISONSHROOM,
-	S_POISONSHROOM2,
-	S_POISONSHROOMD,
-
-	S_NUKESHROOM,
-	S_NUKESHROOM2,
-	S_NUKESHROOMD,
-
-	S_FORCESHROOM,
-	S_FORCESHROOM2,
-	S_FORCESHROOMD,
-
-	S_ATTRACTSHROOM,
-	S_ATTRACTSHROOM2,
-	S_ATTRACTSHROOMD,
-
-	S_ELEMENTALSHROOM,
-	S_ELEMENTALSHROOM2,
-	S_ELEMENTALSHROOMD,
-
-	S_CLOUDSHROOM,
-	S_CLOUDSHROOM2,
-	S_CLOUDSHROOMD,
-
-	S_STARMAN,
-	S_STARMAN1,
-	S_STARMAN2,
-	S_STARMAN3,
-	S_STARMAND,
-
-	S_SPEEDWINGS,
-	S_SPEEDWINGSD,
-	
-	S_PARTICLEPICKUP1,
-	S_PARTICLEPICKUP2,
-	S_1000SCOREAWARD,
-	S_POWERUPAWARD,
-	S_POWERUPAWARD1,
-	S_POWERUPAWARD2,
+
 
 	// Nights-specific stuff
 	S_NIGHTSDRONE_MAN1,
@@ -4540,11 +4391,6 @@ typedef enum state
 	S_REDBRICKDEBRIS, // for CEZ3
 	S_BLUEBRICKDEBRIS, // for CEZ3
 	S_YELLOWBRICKDEBRIS, // for CEZ3
-	S_MARIOBRICKDEBRIS,
-	S_MARIOBRICKDEBRISS,
-	S_MARIOBRICKDEBRISB,
-	S_MARIOBRICKDEBRISC,
-	S_MARIOBRICKDEBRISM,
 
 	S_NAMECHECK,
 
@@ -4748,16 +4594,6 @@ typedef enum mobj_type
 	MT_REDHORIZ,
 	MT_BLUEHORIZ,
 
-	MT_YELLOWTRAMPOLINE,
-	MT_REDTRAMPOLINE,
-	MT_BLUETRAMPOLINE,
-	MT_HORIZYELLOWTRAMPOLINE,
-	MT_HORIZREDTRAMPOLINE,
-	MT_HORIZBLUETRAMPOLINE,
-	MT_DIAGYELLOWTRAMPOLINE,
-	MT_DIAGREDTRAMPOLINE,
-	MT_DIAGBLUETRAMPOLINE,
-
 	MT_BOOSTERSEG,
 	MT_BOOSTERROLLER,
 	MT_YELLOWBOOSTER,
@@ -5258,7 +5094,6 @@ typedef enum mobj_type
 	MT_FIREFLOWER,
 	MT_FIREBALL,
 	MT_FIREBALLTRAIL,
-	MT_GREENKOOPA,
 	MT_SHELL,
 	MT_PUMA,
 	MT_PUMATRAIL,
@@ -5269,30 +5104,6 @@ typedef enum mobj_type
 	MT_MARIOBUSH1,
 	MT_MARIOBUSH2,
 	MT_TOAD,
-	MT_PTZSHROOM,
-	MT_PTZFLAG,
-	MT_BSBSHROOM,
-	MT_BLBSHROOM,
-	MT_BNWSHROOM,
-	MT_MARIOBUSH,
-	MT_REDMFLOWER,
-	MT_BLUEMFLOWER,
-	MT_YELLOWMFLOWER,
-	MT_WHITEDANDELION,
-	MT_MAR64TREE,
-
-	// Power up mushrooms
-	MT_LIFESHROOM,
-	MT_LIFESHROOM_INVISIBLE,
-	MT_POISONSHROOM,
-	MT_NUKESHROOM,
-	MT_FORCESHROOM,
-	MT_ATTRACTSHROOM,
-	MT_ELEMENTALSHROOM,
-	MT_CLOUDSHROOM,
-	MT_STARMAN,
-	MT_SPEEDWINGS,
-	MT_POWERUPAWARD,
 
 	// NiGHTS Stuff
 	MT_AXIS,
@@ -5390,11 +5201,6 @@ typedef enum mobj_type
 	MT_REDBRICKDEBRIS, // for CEZ3
 	MT_BLUEBRICKDEBRIS, // for CEZ3
 	MT_YELLOWBRICKDEBRIS, // for CEZ3
-	MT_MARIOBRICKDEBRIS,
-	MT_MARIOBRICKDEBRISS,
-	MT_MARIOBRICKDEBRISB,
-	MT_MARIOBRICKDEBRISC,
-	MT_MARIOBRICKDEBRISM,
 
 	MT_NAMECHECK,
 	MT_RAY, // General purpose mobj
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 0d828df85ede18d44a1d7ad2a7d4afcc68786dbe..ecd1ee55e648019fb883917ca361cc45ba8847b2 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -1987,7 +1987,7 @@ static int lib_pLineIsBlocking(lua_State *L)
 		return LUA_ErrInvalid(L, "mobj_t");
 	if (!line)
 		return LUA_ErrInvalid(L, "line_t");
-	
+
 	// P_LineOpening in P_LineIsBlocking sets these variables.
 	// We want to keep their old values after so that whatever
 	// map collision code uses them doesn't get messed up.
@@ -2000,9 +2000,9 @@ static int lib_pLineIsBlocking(lua_State *L)
 	pslope_t *oldopenbottomslope = openbottomslope;
 	ffloor_t *oldopenfloorrover = openfloorrover;
 	ffloor_t *oldopenceilingrover = openceilingrover;
-	
+
 	lua_pushboolean(L, P_LineIsBlocking(mo, line));
-	
+
 	opentop = oldopentop;
 	openbottom = oldopenbottom;
 	openrange = oldopenrange;
@@ -2012,7 +2012,7 @@ static int lib_pLineIsBlocking(lua_State *L)
 	openbottomslope = oldopenbottomslope;
 	openfloorrover = oldopenfloorrover;
 	openceilingrover = oldopenceilingrover;
-	
+
 	return 1;
 }
 
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index 0e8860804a4922f579405937de71eeb1395254a4..6650e60e6f353c3250644757c06d87ad1c1c7001 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -1,7 +1,7 @@
 // SONIC ROBO BLAST 2
 //-----------------------------------------------------------------------------
 // Copyright (C) 2014-2016 by John "JTE" Muniz.
-// Copyright (C) 2014-2024 by Sonic Team Junior.
+// Copyright (C) 2014-2025 by Sonic Team Junior.
 //
 // This program is free software distributed under the
 // terms of the GNU General Public License, version 2.
@@ -368,7 +368,10 @@ static int lib_numSkinsSprites(lua_State *L)
 static int lib_getSkinSpriteCompat(lua_State *L)
 {
 	spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESCOMPAT);
-	playersprite_t i = luaL_checkinteger(L, 2);
+	INT32 i = luaL_checkinteger(L, 2) & (SPR2F_MASK | SPR2F_SUPER);
+
+	if (i & SPR2F_SUPER)
+		i = (i & ~SPR2F_SUPER) + NUMPLAYERSPRITES;
 
 	if (i < 0 || i >= NUMPLAYERSPRITES*2)
 		return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 4be071bb20254f062bfbcb87dbf625abac6ea4ec..21ecc3312f2c5fa82f865600518d2863589ca986 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -1110,9 +1110,9 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
 	mt->pitch = mt->roll = 0;
 
 	// Ignore offsets
-	if (mt->type == MT_EMBLEM)
+	if (mt->type == mobjinfo[MT_EMBLEM].doomednum)
 		mt->args[1] = 1;
-	else
+	else if (!(mt->type == mobjinfo[MT_METALSONIC_RACE].doomednum || mt->type == mobjinfo[MT_ROSY].doomednum))
 		mt->args[0] = 1;
 
 	return mt;
diff --git a/src/m_cond.c b/src/m_cond.c
index 418b2ff2b1384af7a2231921ec02b100ac71e318..9706f76c83e06c2537bf1d57051ed80f0b3f0f84 100644
--- a/src/m_cond.c
+++ b/src/m_cond.c
@@ -475,7 +475,7 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
 		// that's better than making dedicated server's lives hell.
 		return false;
 	}
-	
+
 	if (cv_debug || devparm)
 		return false; // Unlock every level when in devmode.
 
diff --git a/src/m_menu.c b/src/m_menu.c
index d92f56ffaf795b4a06d07ad78e06de409d634f9d..37d191a0df84158e31d0d782d6f4b2d6b819eadc 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -140,7 +140,6 @@ static char *char_notes = NULL;
 
 boolean menuactive = false;
 boolean fromlevelselect = false;
-tic_t shieldprompt_timer = 0; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove
 
 typedef enum
 {
@@ -1072,9 +1071,8 @@ 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 Ability",   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_HEADER, NULL, "Camera", NULL, 0},
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
 	{IT_CALL | IT_STRING2, NULL, "Look Up",        M_ChangeControl, GC_LOOKUP      },
@@ -1123,15 +1121,13 @@ static menuitem_t OP_ChangeControlsMenu[] =
 
 static menuitem_t OP_Joystick1Menu[] =
 {
-	{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_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_CVAR,  NULL, "Fire Axis"         , &cv_fireaxis         , 90},
 	{IT_STRING | IT_CVAR,  NULL, "Fire Normal Axis"  , &cv_firenaxis        ,100},
 
@@ -1143,15 +1139,13 @@ static menuitem_t OP_Joystick1Menu[] =
 
 static menuitem_t OP_Joystick2Menu[] =
 {
-	{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_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_CVAR,  NULL, "Fire Axis"         , &cv_fireaxis2        , 90},
 	{IT_STRING | IT_CVAR,  NULL, "Fire Normal Axis"  , &cv_firenaxis2       ,100},
 
@@ -3162,7 +3156,6 @@ static void Command_Manual_f(void)
 	if (modeattacking)
 		return;
 	M_StartControlPanel();
-	if (shieldprompt_timer) return; // TODO: 2.3: Delete this line
 	currentMenu = &MISC_HelpDef;
 	itemOn = 0;
 }
@@ -3342,7 +3335,6 @@ boolean M_Responder(event_t *ev)
 				if (modeattacking)
 					return true;
 				M_StartControlPanel();
-				if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line
 				M_Options(0);
 				// Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically.
 				//OP_SoundOptionsDef.lastOn = 0;
@@ -3353,7 +3345,6 @@ boolean M_Responder(event_t *ev)
 				if (modeattacking)
 					return true;
 				M_StartControlPanel();
-				if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line
 				M_Options(0);
 				M_VideoModeMenu(0);
 				return true;
@@ -3365,7 +3356,6 @@ boolean M_Responder(event_t *ev)
 				if (modeattacking)
 					return true;
 				M_StartControlPanel();
-				if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line
 				M_Options(0);
 				M_SetupNextMenu(&OP_MainDef);
 				return true;
@@ -3643,230 +3633,6 @@ void M_Drawer(void)
 	}
 }
 
-// Handle the "Do you want to assign Shield Ability now?" pop-up for old configs // TODO: 2.3: Remove this line...
-static UINT8 shieldprompt_currentchoice = 0; // ...and this line...
-
-static void M_ShieldPromptUseDefaults(void) // ...and this function
-{
-	// With a default config from v2.2.10 to v2.2.13, the B button will be set to Custom 1,
-	// and Controls per Key defaults to "One", so it will override the default Shield button.
-	// A default config from v2.2.0 to v2.2.9 has Next Weapon on B, so it suffers from this too.
-
-	// So for "Use default Shield Ability buttons", we should update old configs to mitigate gamepad conflicts
-	// (even with "Several" Controls per Key!), and show a message with the default bindings
-
-	for (setupcontrols = gamecontrol; true; setupcontrols = gamecontrolbis) // Do stuff for both P1 and P2
-	{
-		INT32 JOY1 = (setupcontrols == gamecontrol) ? KEY_JOY1 : KEY_2JOY1; // Is this for P1 or for P2?
-
-		if ((setupcontrols[GC_CUSTOM1][0] == JOY1+1 || setupcontrols[GC_CUSTOM1][1] == JOY1+1)
-		&&  (setupcontrols[GC_CUSTOM2][0] == JOY1+3 || setupcontrols[GC_CUSTOM2][1] == JOY1+3)
-		&&  (setupcontrols[GC_CUSTOM3][0] == JOY1+8 || setupcontrols[GC_CUSTOM3][1] == JOY1+8))
-		{
-			// If the player has v2.2.13's default gamepad Custom 1/2/3 buttons,
-			// shuffle Custom 1/2/3 around to make room for Shield Ability on B
-			UINT8 shield_slot  = (setupcontrols[GC_SHIELD ][0] == KEY_NULL  ) ? 0 : 1;
-			UINT8 custom1_slot = (setupcontrols[GC_CUSTOM1][0] == JOY1+1) ? 0 : 1;
-			UINT8 custom2_slot = (setupcontrols[GC_CUSTOM2][0] == JOY1+3) ? 0 : 1;
-			UINT8 custom3_slot = (setupcontrols[GC_CUSTOM3][0] == JOY1+8) ? 0 : 1;
-
-			setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B
-			setupcontrols[GC_CUSTOM1][custom1_slot] = JOY1+3; // Move Custom 1 from B to Y
-			setupcontrols[GC_CUSTOM2][custom2_slot] = JOY1+8; // Move Custom 2 from Y to LS
-			setupcontrols[GC_CUSTOM3][custom3_slot] = KEY_NULL; // Unassign Custom 3 from LS...
-			// (The alternative would be to check and update the ENTIRE gamepad layout.
-			// That'd be nice, but it would mess with people that are used to the old defaults.)
-		}
-		else if ((setupcontrols[GC_WEAPONNEXT][0] == JOY1+1 || setupcontrols[GC_WEAPONNEXT][1] == JOY1+1)
-		&&       (setupcontrols[GC_WEAPONPREV][0] == JOY1+2 || setupcontrols[GC_WEAPONPREV][1] == JOY1+2))
-		{
-			// Or if the user has a default config from v2.2.0 to v2.2.9,
-			// the B button will be Next Weapon, and X will be Previous Weapon.
-			// It's "safe" to discard one of them, you just have to press X multiple times to select in the other direction
-			UINT8 shield_slot  = (setupcontrols[GC_SHIELD    ][0] == KEY_NULL  ) ? 0 : 1;
-			UINT8 nweapon_slot = (setupcontrols[GC_WEAPONNEXT][0] == JOY1+1) ? 0 : 1;
-			UINT8 pweapon_slot = (setupcontrols[GC_WEAPONPREV][0] == JOY1+2) ? 0 : 1;
-
-			setupcontrols[GC_SHIELD    ][shield_slot ] = JOY1+1; // Assign Shield Ability to B
-			setupcontrols[GC_WEAPONNEXT][nweapon_slot] = JOY1+3; // Move Next Weapon from B to X
-			setupcontrols[GC_WEAPONPREV][pweapon_slot] = KEY_NULL; // Unassign Previous Weapon from X
-		}
-
-		if (setupcontrols == gamecontrolbis) // If we've already updated both players, break out
-			break;
-	}
-
-
-	// Now, show a message about the default Shield Ability bindings
-	if ((gamecontrol[GC_SHIELD][0] == KEY_LALT && gamecontrol[GC_SHIELD][1] == KEY_JOY1+1)
-	||  (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 && gamecontrol[GC_SHIELD][1] == KEY_LALT))
-	{
-		// Left Alt and the B button are both assigned
-		M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard,\nand the \x85""B button\x80"" on gamepads."
-		"\n\nYou can always reassign it\nin the Options menu later."
-		"\n\n\nPress 'Enter' to continue\n"),
-			NULL, MM_NOTHING);
-		MessageDef.x = 43; // Change the pop-up message's background position/width
-		MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 27;
-	}
-	else if (gamecontrol[GC_SHIELD][0] == KEY_LALT || gamecontrol[GC_SHIELD][1] == KEY_LALT)
-	{
-		// Left Alt is assigned, but the B button isn't.
-		M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard.\nThe \x85""B button\x80"" on gamepads was taken."
-		"\n\nYou can always reassign it\nin the Options menu later."
-		"\n\n\nPress 'Enter' to continue\n"),
-			NULL, MM_NOTHING);
-		MessageDef.x = 24; // Change the pop-up message's background position/width
-		MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32;
-	}
-	else if (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 || gamecontrol[GC_SHIELD][1] == KEY_JOY1+1)
-	{
-		// The B button is assigned, but Left Alt isn't
-		M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x85""B button\x80"" on gamepads.\nThe \x82""Left Alt\x80"" key on keyboard was taken."
-		"\n\nYou can always reassign it\nin the Options menu later."
-		"\n\n\nPress 'Enter' to continue\n"),
-			NULL, MM_NOTHING);
-		MessageDef.x = 8; // Change the pop-up message's background position/width
-		MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 36;
-	}
-	else if (gamecontrol[GC_SHIELD][0] == KEY_NULL && gamecontrol[GC_SHIELD][1] == KEY_NULL)
-	{
-		// Neither Left Alt nor the B button are assigned
-		M_StartMessage(M_GetText("Shield Ability is unassigned!\nThe \x82""Left Alt\x80"" key on keyboard and\nthe \x85""B button\x80"" on gamepads were taken."
-		"\n\nYou should assign Shield Ability\nin the Options menu later."
-		"\n\n\nPress 'Enter' to continue\n"),
-			NULL, MM_NOTHING);
-		MessageDef.x = 19; // Change the pop-up message's background position/width
-		MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 33;
-	}
-	else
-	{
-		// Neither Left Alt nor the B button are assigned... but something else is???
-		// (This can technically happen if you edit your config or use setcontrol in the console before opening the menu)
-		char keystr[16+16+2+7+1]; // Two 16-char keys + two colour codes + "' and '" + null
-
-		if (gamecontrol[GC_SHIELD][0] != KEY_NULL && gamecontrol[GC_SHIELD][1] != KEY_NULL)
-			STRBUFCPY(keystr, va("%s\x80""' and '\x82""%s",
-				G_KeyNumToName(gamecontrol[GC_SHIELD][0]),
-				G_KeyNumToName(gamecontrol[GC_SHIELD][1])));
-		else if (gamecontrol[GC_SHIELD][0] != KEY_NULL)
-			STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][0]));
-		else //if (gamecontrol[GC_SHIELD][1] != KEY_NULL)
-			STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][1]));
-
-		M_StartMessage(va("Shield Ability is assigned to\n'\x82""%s\x80""'."
-		"\n\nYou can always reassign it\nin the Options menu later."
-		"\n\n\nPress 'Enter' to continue\n",
-			keystr), NULL, MM_NOTHING);
-		MessageDef.x = 23; // Change the pop-up message's background position/width
-		MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32;
-	}
-}
-
-static void M_HandleShieldPromptMenu(INT32 choice) // TODO: 2.3: Remove
-{
-	switch (choice)
-	{
-		case KEY_ESCAPE:
-			if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident!
-				break;
-
-			S_StartSound(NULL, sfx_menu1);
-			noFurtherInput = true;
-			shieldprompt_timer = 0;
-			M_ShieldPromptUseDefaults();
-			break;
-
-		case KEY_ENTER:
-			if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident!
-				break;
-
-			S_StartSound(NULL, sfx_menu1);
-			noFurtherInput = true;
-			shieldprompt_timer = 0;
-
-			if (shieldprompt_currentchoice == 0)
-			{
-				OP_ChangeControlsDef.lastOn = 8; // Highlight Shield Ability in the controls menu
-				M_Setup1PControlsMenu(0); // Set up P1's controls menu and call M_SetupNextMenu
-			}
-			else if (shieldprompt_currentchoice == 1) // Copy the Spin buttons to the Shield buttons
-			{
-				CV_SetValue(&cv_controlperkey, 2); // Make sure that Controls per Key is "Several"
-
-				gamecontrol   [GC_SHIELD][0] = gamecontrol   [GC_SPIN][0];
-				gamecontrol   [GC_SHIELD][1] = gamecontrol   [GC_SPIN][1];
-				gamecontrolbis[GC_SHIELD][0] = gamecontrolbis[GC_SPIN][0];
-				gamecontrolbis[GC_SHIELD][1] = gamecontrolbis[GC_SPIN][1];
-				CV_SetValue(&cv_shieldaxis,  cv_spinaxis.value);
-				CV_SetValue(&cv_shieldaxis2, cv_spinaxis2.value);
-
-				M_StartMessage(M_GetText("Spin and Shield Ability are now\nthe same button."
-				"\n\nYou can always reassign them\nin the Options menu later."
-				"\n\n\nPress 'Enter' to continue\n"),
-					NULL, MM_NOTHING);
-				MessageDef.x = 36; // Change the pop-up message's background position/width
-				MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 29;
-			}
-			else
-				M_ShieldPromptUseDefaults();
-			break;
-
-		case KEY_UPARROW:
-			S_StartSound(NULL, sfx_menu1);
-			shieldprompt_currentchoice = (shieldprompt_currentchoice+2)%3;
-			break;
-
-		case KEY_DOWNARROW:
-			S_StartSound(NULL, sfx_menu1);
-			shieldprompt_currentchoice = (shieldprompt_currentchoice+1)%3;
-			break;
-	}
-
-	MessageDef.prevMenu = &MainDef;
-}
-
-static void M_DrawShieldPromptMenu(void) // TODO: 2.3: Remove
-{
-	INT16 cursorx = (BASEVIDWIDTH/2) - 24;
-
-	V_DrawFill(10-3, 68-3, 300+6, 40+6, 159);
-	// V_DrawCenteredString doesn't centre newlines, so we have to draw each line separately
-	V_DrawCenteredString(BASEVIDWIDTH/2, 68, V_ALLOWLOWERCASE, "Welcome back! Since you last played,");
-	V_DrawCenteredString(BASEVIDWIDTH/2, 76, V_ALLOWLOWERCASE, "Spin has been split into separate");
-	V_DrawCenteredString(BASEVIDWIDTH/2, 84, V_ALLOWLOWERCASE, "\"Spin\" and \"Shield Ability\" controls.");
-
-	V_DrawCenteredString(BASEVIDWIDTH/2, 98, V_ALLOWLOWERCASE, "Do you want to assign Shield Ability now?");
-
-
-	V_DrawCenteredString(BASEVIDWIDTH/2, 164,
-		(shieldprompt_currentchoice == 0) ? V_YELLOWMAP : 0, "Open Control Setup");
-	V_DrawCenteredString(BASEVIDWIDTH/2, 172,
-		(shieldprompt_currentchoice == 1) ? V_YELLOWMAP : 0, "Keep the old behaviour");
-	V_DrawCenteredString(BASEVIDWIDTH/2, 180,
-		(shieldprompt_currentchoice == 2) ? V_YELLOWMAP : 0, "Use default Shield Ability buttons");
-
-	switch (shieldprompt_currentchoice)
-	{
-		case 0:  cursorx -= V_StringWidth("Open Control Setup",                 0)/2; break;
-		case 1:  cursorx -= V_StringWidth("Keep the old behaviour",             0)/2; break;
-		default: cursorx -= V_StringWidth("Use default Shield Ability buttons", 0)/2; break;
-	}
-	V_DrawScaledPatch(cursorx, 164 + (shieldprompt_currentchoice*8), 0, W_CachePatchName("M_CURSOR", PU_PATCH));
-}
-
-static menuitem_t OP_ShieldPromptMenu[] = {{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleShieldPromptMenu, 0}}; // TODO: 2.3: Remove
-
-menu_t OP_ShieldPromptDef = { // TODO: 2.3: Remove
-	MN_SPECIAL,
-	NULL,
-	1,
-	&MainDef,
-	OP_ShieldPromptMenu,
-	M_DrawShieldPromptMenu,
-	0, 0, 0, NULL
-};
-
 //
 // M_StartControlPanel
 //
@@ -3898,15 +3664,6 @@ void M_StartControlPanel(void)
 		currentMenu = &MainDef;
 		itemOn = singleplr;
 		M_UpdateItemOn();
-
-		if (shieldprompt_timer) // For old configs, show a pop-up about the new Shield button // TODO: 2.3: Remove
-		{
-			S_StartSound(NULL, sfx_strpst);
-			noFurtherInput = true;
-			shieldprompt_timer = I_GetTime() + TICRATE; // Don't mash past the pop-up by accident!
-
-			M_SetupNextMenu(&OP_ShieldPromptDef);
-		}
 	}
 	else if (modeattacking)
 	{
@@ -3917,12 +3674,16 @@ void M_StartControlPanel(void)
 	}
 	else if (!(netgame || multiplayer)) // Single Player
 	{
-		// Devmode unlocks Pandora's Box in the pause menu
-		boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) || cv_debug || devparm) && !marathonmode);
+		// Devmode unlocks Pandora's Box and Level Select in the pause menu
+		boolean isforbidden = (marathonmode || ultimatemode);
+		boolean isdebug = ((cv_debug || devparm) && !isforbidden);
+		boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !isforbidden) || isdebug);
+		boolean lselect = ((maplistoption != 0 && !isforbidden) || isdebug);
 
-		if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff.
+		if (gamestate != GS_LEVEL) // intermission, so gray out stuff.
 		{
 			SPauseMenu[spause_pandora].status = (pandora) ? (IT_GRAYEDOUT) : (IT_DISABLED);
+			SPauseMenu[spause_levelselect].status = (lselect) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 			SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
 		}
 		else
@@ -3932,6 +3693,11 @@ void M_StartControlPanel(void)
 				++numlives;
 
 			SPauseMenu[spause_pandora].status = (pandora) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
+			SPauseMenu[spause_levelselect].status = (lselect) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
+			if (ultimatemode)
+			{
+				SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
+			}
 
 			// The list of things that can disable retrying is (was?) a little too complex
 			// for me to want to use the short if statement syntax
@@ -3941,13 +3707,6 @@ void M_StartControlPanel(void)
 				SPauseMenu[spause_retry].status = (IT_STRING | IT_CALL);
 		}
 
-		// We can always use level select though. :33
-		// Guarantee it if we have either it unlocked or devmode is enabled
-		if ((maplistoption != 0 || M_SecretUnlocked(SECRET_LEVELSELECT, serverGamedata) || cv_debug || devparm) && !marathonmode)
-			SPauseMenu[spause_levelselect].status = (IT_STRING | IT_CALL);
-		else
-			SPauseMenu[spause_levelselect].status = (IT_DISABLED);
-
 		// And emblem hints.
 		SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 
@@ -7788,13 +7547,9 @@ static void M_PauseLevelSelect(INT32 choice)
 	SP_PauseLevelSelectDef.prevMenu = currentMenu;
 	levellistmode = LLM_LEVELSELECT;
 
-	// maplistoption is only specified if not set already
-	// and we have the level select unlocked so that it
+	// maplistoption is NOT specified, so that this
 	// transfers the level select list from the menu
 	// used to enter the game to the pause menu.
-	if (maplistoption == 0 && M_SecretUnlocked(SECRET_LEVELSELECT, serverGamedata))
-		maplistoption = 1;
-
 	if (!M_PrepareLevelPlatter(-1, true))
 	{
 		M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
@@ -11373,7 +11128,7 @@ static void M_Refresh(INT32 choice)
 
 	// note: this is the one case where 0 is a valid room number
 	// because it corresponds to "All"
-	CL_UpdateServerList(!(ms_RoomId < 0), ms_RoomId);
+	CL_UpdateServerList(cv_masterserver_room_id.value >= 0, cv_masterserver_room_id.value);
 
 	// first page of servers
 	serverlistpage = 0;
@@ -11459,7 +11214,7 @@ static void M_DrawConnectMenu(void)
 		numPages = 1;
 
 	// Room name
-	if (ms_RoomId < 0)
+	if (cv_masterserver_room_id.value < 0)
 		V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey,
 		                         V_YELLOWMAP, (itemOn == mp_connect_room) ? "<Select to change>" : "<Unlisted Mode>");
 	else
@@ -11687,7 +11442,7 @@ static void M_ConnectMenu(INT32 choice)
 
 	// first page of servers
 	serverlistpage = 0;
-	if (ms_RoomId < 0)
+	if (cv_masterserver_room_id.value < 0)
 	{
 		M_RoomMenu(0); // Select a room instead of staring at an empty list
 		// This prevents us from returning to the modified game alert.
@@ -11783,7 +11538,7 @@ static void M_ChooseRoom(INT32 choice)
 #endif
 
 	if (choice == 0)
-		CV_SetValue(&cv_masterserver_room_id, 0);
+		CV_SetValue(&cv_masterserver_room_id, -1);
 	else
 	{
 		CV_SetValue(&cv_masterserver_room_id, roomIds[choice-1]);
@@ -11855,7 +11610,7 @@ static void M_DrawServerMenu(void)
 	if (currentMenu == &MP_ServerDef)
 	{
 		M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true, false);
-		if (ms_RoomId < 0)
+		if (cv_masterserver_room_id.value < 0)
 			V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
 			                         V_YELLOWMAP, (itemOn == mp_server_room) ? "<Select to change>" : "<Unlisted Mode>");
 		else
@@ -11951,7 +11706,7 @@ static void M_ServerOptions(INT32 choice)
 static void M_StartServerMenu(INT32 choice)
 {
 	(void)choice;
-	ms_RoomId = -1;
+	CV_SetValue(&cv_masterserver_room_id, -1);
 	levellistmode = LLM_CREATESERVER;
 	Newgametype_OnChange();
 	M_SetupNextMenu(&MP_ServerDef);
@@ -13568,23 +13323,23 @@ static void M_Setup1PControlsMenu(INT32 choice)
 	currentMenu->lastOn = itemOn;
 
 	// Unhide the nine non-P2 controls and their headers
-	//OP_ChangeControlsMenu[19+0].status = IT_HEADER;
-	//OP_ChangeControlsMenu[19+1].status = IT_SPACE;
+	//OP_ChangeControlsMenu[18+0].status = IT_HEADER;
+	//OP_ChangeControlsMenu[18+1].status = IT_SPACE;
 	// ...
-	OP_ChangeControlsMenu[19+2].status = IT_CALL|IT_STRING2;
-	OP_ChangeControlsMenu[19+3].status = IT_CALL|IT_STRING2;
-	OP_ChangeControlsMenu[19+4].status = IT_CALL|IT_STRING2;
-	OP_ChangeControlsMenu[19+5].status = IT_CALL|IT_STRING2;
-	OP_ChangeControlsMenu[19+6].status = IT_CALL|IT_STRING2;
-	//OP_ChangeControlsMenu[19+7].status = IT_CALL|IT_STRING2;
-	//OP_ChangeControlsMenu[19+8].status = IT_CALL|IT_STRING2;
-	OP_ChangeControlsMenu[19+9].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[18+2].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[18+3].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[18+4].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[18+5].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[18+6].status = IT_CALL|IT_STRING2;
+	//OP_ChangeControlsMenu[18+7].status = IT_CALL|IT_STRING2;
+	//OP_ChangeControlsMenu[18+8].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[18+9].status = IT_CALL|IT_STRING2;
 	// ...
-	OP_ChangeControlsMenu[29+0].status = IT_HEADER;
-	OP_ChangeControlsMenu[29+1].status = IT_SPACE;
+	OP_ChangeControlsMenu[28+0].status = IT_HEADER;
+	OP_ChangeControlsMenu[28+1].status = IT_SPACE;
 	// ...
-	OP_ChangeControlsMenu[29+2].status = IT_CALL|IT_STRING2;
-	OP_ChangeControlsMenu[29+3].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[28+2].status = IT_CALL|IT_STRING2;
+	OP_ChangeControlsMenu[28+3].status = IT_CALL|IT_STRING2;
 
 	OP_ChangeControlsDef.prevMenu = &OP_P1ControlsDef;
 	OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level
@@ -13600,23 +13355,23 @@ static void M_Setup2PControlsMenu(INT32 choice)
 	currentMenu->lastOn = itemOn;
 
 	// Hide the nine non-P2 controls and their headers
-	//OP_ChangeControlsMenu[19+0].status = IT_GRAYEDOUT2;
-	//OP_ChangeControlsMenu[19+1].status = IT_GRAYEDOUT2;
+	//OP_ChangeControlsMenu[18+0].status = IT_GRAYEDOUT2;
+	//OP_ChangeControlsMenu[18+1].status = IT_GRAYEDOUT2;
 	// ...
-	OP_ChangeControlsMenu[19+2].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[19+3].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[19+4].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[19+5].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[19+6].status = IT_GRAYEDOUT2;
-	//OP_ChangeControlsMenu[19+7].status = IT_GRAYEDOUT2;
-	//OP_ChangeControlsMenu[19+8].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[19+9].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[18+2].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[18+3].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[18+4].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[18+5].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[18+6].status = IT_GRAYEDOUT2;
+	//OP_ChangeControlsMenu[18+7].status = IT_GRAYEDOUT2;
+	//OP_ChangeControlsMenu[18+8].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[18+9].status = IT_GRAYEDOUT2;
 	// ...
-	OP_ChangeControlsMenu[29+0].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[29+1].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[28+0].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[28+1].status = IT_GRAYEDOUT2;
 	// ...
-	OP_ChangeControlsMenu[29+2].status = IT_GRAYEDOUT2;
-	OP_ChangeControlsMenu[29+3].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[28+2].status = IT_GRAYEDOUT2;
+	OP_ChangeControlsMenu[28+3].status = IT_GRAYEDOUT2;
 
 	OP_ChangeControlsDef.prevMenu = &OP_P2ControlsDef;
 	OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level
diff --git a/src/m_menu.h b/src/m_menu.h
index cfe811d0be536b82ec3aeec7f0ab920a55a3d6c1..dc8bef8b136e1d819e7680f5a7bca1e6cf8b94c1 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -3,7 +3,7 @@
 // Copyright (C) 1993-1996 by id Software, Inc.
 // Copyright (C) 1998-2000 by DooM Legacy Team.
 // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
-// Copyright (C) 1999-2024 by Sonic Team Junior.
+// Copyright (C) 1999-2025 by Sonic Team Junior.
 //
 // This program is free software distributed under the
 // terms of the GNU General Public License, version 2.
@@ -143,7 +143,7 @@ typedef enum
 
 typedef struct
 {
-	char bgname[8]; // name for background gfx lump; lays over titlemap if this is set
+	char bgname[8+1]; // name for background gfx lump; lays over titlemap if this is set
 	SINT8 fadestrength;  // darken background when displaying this menu, strength 0-31 or -1 for undefined
 	INT32 bgcolor; // fill color, overrides bg name. -1 means follow bg name rules.
 	INT32 titlescrollxspeed; // background gfx scroll per menu; inherits global setting
@@ -153,13 +153,13 @@ typedef struct
 	SINT8 hidetitlepics; // hide title gfx per menu; -1 means undefined, inherits global setting
 	ttmode_enum ttmode; // title wing animation mode; default TTMODE_OLD
 	UINT8 ttscale; // scale of title wing gfx (FRACUNIT / ttscale); -1 means undefined, inherits global setting
-	char ttname[9]; // lump name of title wing gfx. If name length is <= 6, engine will attempt to load numbered frames (TTNAMExx)
+	char ttname[8+1]; // lump name of title wing gfx. If name length is <= 6, engine will attempt to load numbered frames (TTNAMExx)
 	INT16 ttx; // X position of title wing
 	INT16 tty; // Y position of title wing
 	INT16 ttloop; // # frame to loop; -1 means dont loop
 	UINT16 tttics; // # of tics per frame
 
-	char musname[7]; ///< Music track to play. "" for no music.
+	char musname[6+1]; ///< 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.
 	boolean muslooping; ///< Loop the music
 	boolean musstop; ///< Don't play any music
@@ -176,7 +176,6 @@ typedef struct
 extern menupres_t menupres[NUMMENUTYPES];
 extern UINT32 prevMenuId;
 extern UINT32 activeMenuId;
-extern tic_t shieldprompt_timer; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove
 
 void M_InitMenuPresTables(void);
 UINT8 M_GetYoungestChildMenu(void);
@@ -370,8 +369,8 @@ extern menu_t OP_JoystickSetDef;
 typedef struct
 {
 	boolean used;
-	char notes[441];
-	char picname[8];
+	char notes[440+1];
+	char picname[8+1];
 	char skinname[SKINNAMESIZE*2+2]; // skin&skin\0
 	patch_t *charpic;
 	UINT8 prev;
diff --git a/src/m_misc.c b/src/m_misc.c
index dda3ffc86dc70de55ac3d3ce5df48cc3d797299d..24616e9db42e2b27bab8c4d359e5d92b3945f6d7 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -560,11 +560,6 @@ void M_FirstLoadConfig(void)
 	COM_BufInsertText(va("exec \"%s\"\n", configfile));
 	// no COM_BufExecute() needed; that does it right away
 
-	// For configs loaded at startup only, check for pre-Shield-button configs // TODO: 2.3: Remove
-	if (GETMAJOREXECVERSION(cv_execversion.value) < 55 // Pre-v2.2.14 configs
-	&& cv_execversion.value != 25) // Make sure that the config exists, too
-		shieldprompt_timer = 1;
-
 	// don't filter anymore vars and don't let this convsvar be changed
 	COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION));
 	CV_ToggleExecVersion(false);
diff --git a/src/m_random.c b/src/m_random.c
index 536fbfbbd1077abf6ae400bd4d8773a7574e4b08..a063e88f47ccc40f10ffa09d441016d3bd20c13b 100644
--- a/src/m_random.c
+++ b/src/m_random.c
@@ -193,9 +193,9 @@ INT32 M_RandomKey(INT32 a)
   */
 INT32 M_RandomRange(INT32 a, INT32 b)
 {
-  	if (b < a)
+	if (b < a)
 	{
-    	INT32 temp;
+		INT32 temp;
 
 		temp = a;
 		a = b;
diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c
index 067458852e69b1bf1e37d8cd5b6b0de10cc95f27..6702e2591254349a9bd3dde6d08b7fa86ef7fb29 100644
--- a/src/netcode/d_clisrv.c
+++ b/src/netcode/d_clisrv.c
@@ -663,7 +663,7 @@ void D_QuitNetGame(void)
 			if (netnodes[i].ingame)
 				HSendPacket(i, true, 0, 0);
 #ifdef MASTERSERVER
-		if (serverrunning && ms_RoomId > 0)
+		if (serverrunning && cv_masterserver_room_id.value > 0)
 			UnregisterServer();
 #endif
 	}
@@ -797,7 +797,7 @@ void SV_SpawnServer(void)
 		{
 			I_NetOpenSocket();
 #ifdef MASTERSERVER
-			if (ms_RoomId > 0)
+			if (cv_masterserver_room_id.value > 0)
 				RegisterServer();
 #endif
 		}
diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c
index 7bdf229fd2698ceeda18bba2f16da6ba2c36c174..94170fa0df401064f5c1a2f9569cfceb0b0c490e 100644
--- a/src/netcode/d_netcmd.c
+++ b/src/netcode/d_netcmd.c
@@ -824,8 +824,6 @@ 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);
diff --git a/src/netcode/http-mserv.c b/src/netcode/http-mserv.c
index 4a080498455234f234655f505e4bf0df956dd9a6..8ce20af956008d2e522a08dc0aa98756174252d8 100644
--- a/src/netcode/http-mserv.c
+++ b/src/netcode/http-mserv.c
@@ -426,7 +426,7 @@ HMS_register (void)
 
 	char *title;
 
-	hms = HMS_connect(PROTO_V4, "rooms/%d/register", ms_RoomId);
+	hms = HMS_connect(PROTO_V4, "rooms/%d/register", cv_masterserver_room_id.value);
 
 	if (! hms)
 		return 0;
@@ -462,7 +462,7 @@ HMS_register (void)
 	if (!hms_allow_ipv6)
 		return ok;
 
-	hms = HMS_connect(PROTO_V6, "rooms/%d/register", ms_RoomId);
+	hms = HMS_connect(PROTO_V6, "rooms/%d/register", cv_masterserver_room_id.value);
 
 	if (! hms)
 		return 0;
diff --git a/src/netcode/mserv.c b/src/netcode/mserv.c
index fba36a3babddc507dd9d3c7601682ac50baa7a45..f17db4b6e32e59a08a7ac5c9c3a44e867c0ffff2 100644
--- a/src/netcode/mserv.c
+++ b/src/netcode/mserv.c
@@ -67,9 +67,10 @@ consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://ds.ms.srb2.org/M
 consvar_t cv_servername = CVAR_INIT_WITH_CALLBACKS ("servername", "SRB2 server", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT|CV_ALLOWLUA, NULL, Update_parameters, ServerName_CanChange);
 
 consvar_t cv_masterserver_update_rate = CVAR_INIT ("masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters);
-consvar_t cv_masterserver_room_id = CVAR_INIT ("masterserver_room_id", "0", CV_CALL, CV_Unsigned, RoomId_OnChange);
+CV_PossibleValue_t cv_masterserver_room_values[] = {{-1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
+consvar_t cv_masterserver_room_id = CVAR_INIT ("masterserver_room_id", "-1", CV_CALL, cv_masterserver_room_values, RoomId_OnChange);
 
-INT16 ms_RoomId = 0;
+static INT16 ms_RoomId = -1;
 
 #if defined (MASTERSERVER) && defined (HAVE_THREADS)
 int           ms_QueryId;
@@ -449,7 +450,7 @@ void UnregisterServer(void)
 static boolean
 Online (void)
 {
-	return ( serverrunning && ms_RoomId > 0 );
+	return ( serverrunning && cv_masterserver_room_id.value > 0 );
 }
 
 static inline void SendPingToMasterServer(void)
diff --git a/src/netcode/mserv.h b/src/netcode/mserv.h
index 419c11a89409d7491249d159f669285c344fdee5..ed3c9b27b8f6d9f52b1c8cc4e2640b5501653dff 100644
--- a/src/netcode/mserv.h
+++ b/src/netcode/mserv.h
@@ -71,11 +71,6 @@ extern consvar_t cv_masterserver_timeout;
 extern consvar_t cv_masterserver_debug;
 extern consvar_t cv_masterserver_token;
 
-// < 0 to not connect (usually -1) (offline mode)
-// == 0 to show all rooms, not a valid hosting room
-// anything else is whatever room the MS assigns to that number (online mode)
-extern INT16 ms_RoomId;
-
 #ifdef HAVE_THREADS
 extern int           ms_QueryId;
 extern I_mutex       ms_QueryId_mutex;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index e99a2dd4a8dd43db549752bf7744973033c8d7db..7091af5429e834c098ba7d81ace6961cc238e37f 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -3922,7 +3922,7 @@ static void P_DoBoss5Death(mobj_t *mo)
 				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,
@@ -7837,14 +7837,13 @@ void A_BuzzFly(mobj_t *actor)
 
 // Function: A_GuardChase
 //
-// Description: Modified A_Chase for Egg Guard and Koopa Troopas
+// Description: Modified A_Chase for Egg Guard
 //
-// var1 = shield (0) or no shield (1)
+// var1 = unused
 // var2 = unused
 //
 void A_GuardChase(mobj_t *actor)
 {
-	INT32 locvar1 = var1;
 	INT32 delta;
 
 	if (LUA_CallAction(A_GUARDCHASE, actor))
@@ -7853,11 +7852,11 @@ void A_GuardChase(mobj_t *actor)
 	if (actor->reactiontime)
 		actor->reactiontime--;
 
-	if (actor->threshold != 42 || locvar1 == 1) // In formation...
+	if (actor->threshold != 42) // In formation...
 	{
 		fixed_t speed;
 
-		if ((!actor->tracer || !actor->tracer->health) && locvar1 == 0)
+		if (!actor->tracer || !actor->tracer->health)
 		{
 			P_SetTarget(&actor->tracer, NULL);
 			actor->threshold = 42;
@@ -7946,7 +7945,7 @@ void A_GuardChase(mobj_t *actor)
 	// Now that we've moved, its time for our shield to move!
 	// Otherwise it'll never act as a proper overlay.
 	if (actor->tracer && actor->tracer->state
-	&& actor->tracer->state->action.acp1 && locvar1 == 0)
+	&& actor->tracer->state->action.acp1)
 	{
 		var1 = actor->tracer->state->var1, var2 = actor->tracer->state->var2;
 		actor->tracer->state->action.acp1(actor->tracer);
@@ -8333,7 +8332,7 @@ void A_Shockwave(mobj_t *actor)
 		ang += interval;
 		sprev = shock;
 	}
-	
+
 	S_StartSound(actor, shock->info->seesound);
 }
 
diff --git a/src/p_inter.c b/src/p_inter.c
index 0e63fea1b9500cb8b9d22642bfb9f0d9c7fd2b20..27e612154dc87c1b88fec2e42e890af0d27c382e 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -538,14 +538,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1) && (!(player->powers[pw_strong] & STR_HEAVY)))
 			{
 				fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce
-				
+
 				if (elementalpierce == 2) // Reset bubblewrap, part 1
 					P_DoBubbleBounce(player);
 				toucher->momz = setmomz;
 				if (elementalpierce == 2) // Reset bubblewrap, part 2
 				{
 					boolean underwater = toucher->eflags & MFE_UNDERWATER;
-							
+
 					if (underwater)
 						toucher->momz /= 2;
 					toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height!
@@ -2572,7 +2572,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			if (!(target->flags2 & MF2_DONTRESPAWN))
 			{
 				if (!(netgame || multiplayer))
-					target->fuse = atoi(cv_itemrespawntime.defaultvalue)*TICRATE + 2; 
+					target->fuse = atoi(cv_itemrespawntime.defaultvalue)*TICRATE + 2;
 				else if (cv_itemrespawn.value)
 					target->fuse = cv_itemrespawntime.value*TICRATE + 2;
 			}
diff --git a/src/p_local.h b/src/p_local.h
index de519b211b8d664ddba9305f6a6c5a2eb03ed159..85a31cf8982114068b0da41c7a59971d011929ba 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -289,7 +289,6 @@ void P_RecalcPrecipInSector(sector_t *sector);
 void P_PrecipitationEffects(void);
 
 void P_RemoveMobj(mobj_t *th);
-boolean P_MobjWasRemoved(mobj_t *th);
 void P_RemoveSavegameMobj(mobj_t *th);
 boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
 void P_RunShields(void);
@@ -301,6 +300,12 @@ boolean P_CheckSkyHit(mobj_t *mo, line_t *line);
 void P_PushableThinker(mobj_t *mobj);
 void P_SceneryThinker(mobj_t *mobj);
 
+// This does not need to be added to Lua.
+// To test it in Lua, check mobj.valid
+FUNCINLINE static ATTRINLINE boolean P_MobjWasRemoved(mobj_t *mobj)
+{
+	return mobj == NULL || mobj->thinker.function.acp1 != (actionf_p1)P_MobjThinker;
+}
 
 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);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 56a98deee551970e115bc3486bb31d57b3b1b9f4..8e5c5506445545c862ab2cbdfdce6d14e12afb19 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -323,8 +323,10 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 		mobj->state = st;
 		mobj->tics = st->tics;
 
-		// Adjust the player's animation speed to match their velocity.
-		if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE))
+		// Adjust the player's animation speed
+		if (mobj->state-states == S_PLAY_WAIT && (player->charflags & SF_FASTWAIT))
+			mobj->tics = 5;
+		else if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE))
 			mobj->tics = 2;
 		else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST))
 		{
@@ -6639,12 +6641,12 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
 	if (scale < 1) {
 		P_SetScale(thing, thing->target->scale, true);
 		thing->old_scale = thing->target->old_scale;
-		
+
 		thing->flags2 |= (MF2_DONTDRAW|MF2_JUSTATTACKED); //Hide and indicate we're hidden
 	} else {
 		P_SetScale(thing, scale, true);
 		thing->old_scale = FixedMul(thing->target->old_scale, thing->target->player->shieldscale);
-		
+
 		//Only unhide if we were hidden by the above code
 		if (thing->flags2 & MF2_JUSTATTACKED)
 			thing->flags2 &= ~(MF2_DONTDRAW|MF2_JUSTATTACKED);
@@ -6773,6 +6775,12 @@ void P_RunOverlays(void)
 		else
 			zoffs = 0;
 
+		// hide the overlay as well if we're part of a hidden shield
+		if ((mo->target->flags2 & (MF2_JUSTATTACKED|MF2_DONTDRAW)) == (MF2_JUSTATTACKED|MF2_DONTDRAW))
+			mo->flags2 |= (MF2_DONTDRAW|MF2_JUSTATTACKED);
+		else if (mo->flags2 & MF2_JUSTATTACKED)
+			mo->flags2 &= ~(MF2_DONTDRAW|MF2_JUSTATTACKED);
+
 		P_UnsetThingPosition(mo);
 		mo->x = mo->target->x;
 		mo->y = mo->target->y;
@@ -7301,7 +7309,7 @@ static void P_RosySceneryThink(mobj_t *mobj)
 		player = &players[i];
 	}
 
-	if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN)
+	if (stat == S_ROSY_JUMP || stat == S_ROSY_FALL || stat == S_ROSY_PAIN)
 	{
 		if (P_IsObjectOnGround(mobj))
 		{
@@ -7312,16 +7320,16 @@ static void P_RosySceneryThink(mobj_t *mobj)
 				stat = S_ROSY_WALK;
 			P_SetMobjState(mobj, stat);
 		}
-		else if (P_MobjFlip(mobj)*mobj->momz < 0)
-			mobj->frame = mobj->state->frame + mobj->state->var1;
+		else if (P_MobjFlip(mobj)*mobj->momz < 0 && stat == S_ROSY_JUMP)
+			P_SetMobjState(mobj, S_ROSY_FALL);
 	}
 
 	if (!player)
 	{
-		if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP)
+		if (stat != S_ROSY_IDLE && stat != S_ROSY_JUMP && stat != S_ROSY_FALL)
 		{
 			mobj->momx = mobj->momy = 0;
-			P_SetMobjState(mobj, S_ROSY_IDLE1);
+			P_SetMobjState(mobj, S_ROSY_IDLE);
 		}
 	}
 	else
@@ -7335,13 +7343,11 @@ static void P_RosySceneryThink(mobj_t *mobj)
 
 		switch (stat)
 		{
-		case S_ROSY_IDLE1:
-		case S_ROSY_IDLE2:
-		case S_ROSY_IDLE3:
-		case S_ROSY_IDLE4:
+		case S_ROSY_IDLE:
 			dojump = true;
 			break;
 		case S_ROSY_JUMP:
+		case S_ROSY_FALL:
 		case S_ROSY_PAIN:
 			// handled above
 			break;
@@ -7367,8 +7373,7 @@ static void P_RosySceneryThink(mobj_t *mobj)
 				max = pdist;
 				if ((--mobj->extravalue1) <= 0)
 				{
-					if (++mobj->frame > mobj->state->frame + mobj->state->var1)
-						mobj->frame = mobj->state->frame;
+					P_SetMobjState(mobj, S_ROSY_WALK);
 					if (mom > 12*mobj->scale)
 						mobj->extravalue1 = 2;
 					else if (mom > 6*mobj->scale)
@@ -10603,6 +10608,19 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
 	}
 }
 
+static INT32 P_SetupNPC(mobj_t *mobj, const char *name)
+{
+	INT32 skinnum = R_SkinAvailable(name);
+
+	if (skinnum != -1)
+	{
+		mobj->skin = skins[skinnum];
+		mobj->color = skins[skinnum]->prefcolor;
+	}
+
+	return skinnum;
+}
+
 //
 // P_SpawnMobj
 //
@@ -10956,17 +10974,14 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				nummaprings++;
 			break;
 		case MT_METALSONIC_RACE:
-			mobj->skin = skins[5];
-			/* FALLTHRU */
 		case MT_METALSONIC_BATTLE:
-			mobj->color = skins[5]->prefcolor;
-			sc = 5;
+			sc = P_SetupNPC(mobj, "metalsonic");
 			break;
 		case MT_FANG:
-			sc = 4;
+			sc = P_SetupNPC(mobj, "fang");
 			break;
 		case MT_ROSY:
-			sc = 3;
+			sc = P_SetupNPC(mobj, "amy");
 			break;
 		case MT_CORK:
 			mobj->flags2 |= MF2_SUPERFIRE;
@@ -10996,13 +11011,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				mcsolid->angle = mobj->angle + ANGLE_90;
 			}
 			break;
-		case MT_TORCHFLOWER:
-			{
-				mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME);
-				if (!P_MobjWasRemoved(fire))
-					P_SetTarget(&mobj->target, fire);
-				break;
-			}
 		case MT_PYREFLY:
 			mobj->extravalue1 = (FixedHypot(mobj->x, mobj->y)/FRACUNIT) % 360;
 			mobj->extravalue2 = 0;
@@ -11274,15 +11282,6 @@ void P_RemoveMobj(mobj_t *mobj)
 #endif
 }
 
-// This does not need to be added to Lua.
-// To test it in Lua, check mobj.valid
-boolean P_MobjWasRemoved(mobj_t *mobj)
-{
-	if (mobj && mobj->thinker.function.acp1 == (actionf_p1)P_MobjThinker)
-		return false;
-	return true;
-}
-
 void P_RemovePrecipMobj(precipmobj_t *mobj)
 {
 	// unlink from sector and block lists
@@ -12995,6 +12994,13 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 			}
 		}
 		break;
+	case MT_TORCHFLOWER:
+		{
+			mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME);
+			if (!P_MobjWasRemoved(fire))
+				P_SetTarget(&mobj->target, fire);
+			break;
+		}
 	case MT_CANDLE:
 	case MT_CANDLEPRICKET:
 		if (mthing->args[0])
diff --git a/src/p_setup.c b/src/p_setup.c
index 04d4b77283789962bb392309c4ce091851a2f73a..c2b8f2db2e367cc23fcdb704f23fe572360eea81 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -5866,10 +5866,6 @@ static void P_ConvertBinaryLinedefTypes(void)
 			lines[i].args[0] = tag;
 			lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB);
 			break;
-		case 465: // Bounce Player (purely for backwards compatibility with new Pipe Towers)
-			lines[i].args[0] = (FixedHypot(lines[i].dx, lines[i].dy) / 8) >> FRACBITS;
-			lines[i].special = 430;
-			break;
 		case 466: //Set level failure state
 			lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB);
 			break;
diff --git a/src/p_slopes.c b/src/p_slopes.c
index 7f070e2a1793b4d02a44fefa374f4a887a8da4a1..7390329369b4b5dfbb9b084e4396234f99b1fb57 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -181,7 +181,7 @@ void T_DynamicSlopeLine (dynlineplanethink_t* th)
 {
 	pslope_t* slope = th->slope;
 	line_t* srcline = th->sourceline;
-	
+
 	fixed_t zdelta, oldoz = slope->o.z;
 
 	switch(th->type) {
diff --git a/src/p_spec.c b/src/p_spec.c
index e402180fedd857156d4183bd3d982d457e94f7c4..93809cbb4b68118e4fc4032186c5e772435daba2 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -2406,7 +2406,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					z = line->args[4] << FRACBITS;
 
 					P_SetOrigin(mo, mo->x + x, mo->y + y, mo->z + z);
-					
+
 					if (mo->player)
 					{
 						if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3
@@ -2702,18 +2702,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 				EV_DoCrush(line->args[0], line, crushBothOnce);
 			break;
 
-		case 430: // Bounce Player
-			if (mo && mo->player)
-			{
-				P_SetObjectMomZ(mo, line->args[0]*FRACUNIT, false);
-				S_StartSound(NULL, sfx_s3k8a);
-				mo->player->pflags |= PF_JUMPED;
-				if (skins[mo->player->skin]->flags & SF_NOJUMPSPIN)
-					P_SetMobjState(mo, S_PLAY_SPRING);
-				else
-					P_SetMobjState(mo, S_PLAY_JUMP);
-			}
-			break;
 		case 432: // Enable/Disable 2D Mode
 			if (mo && mo->player)
 			{
diff --git a/src/p_user.c b/src/p_user.c
index 6063544bc7e50979b34be6c66e1c2b1f6452d245..b961576a8e314bea2922a598edeb69f7e10682b6 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -669,7 +669,7 @@ static void P_DeNightserizePlayer(player_t *player)
 	player->powers[pw_carry] = CR_NIGHTSFALL;
 
 	player->powers[pw_underwater] = 0;
-	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_SHIELDDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
+	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
 	player->secondjump = 0;
 	player->homing = 0;
 	player->climbing = 0;
@@ -802,7 +802,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 	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->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
 	player->homing = 0;
 	player->mo->fuse = 0;
 	player->speed = 0;
@@ -978,7 +978,7 @@ boolean P_PlayerInPain(player_t *player)
 {
 	if (P_MobjWasRemoved(player->mo))
 		return false;
-		
+
 	// no silly, sliding isn't pain
 	if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing])
 		return true;
@@ -1362,6 +1362,8 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 	if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
 		P_PlayJingle(player, JT_SUPER);
 
+	S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
+
 	player->mo->momx = player->mo->momy = player->mo->momz = player->cmomx = player->cmomy = player->rmomx = player->rmomy = 0;
 
 	// Transformation animation
@@ -1378,11 +1380,8 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 		player->powers[pw_sneakers] = 0;
 	}
 
-	if (G_CoopGametype())
-		S_StartSound(player->mo, sfx_supert); //only hear it near yourself in co-op
-	else
+	if (!G_CoopGametype())
 	{
-		S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
 		HU_SetCEchoFlags(0);
 		HU_SetCEchoDuration(5);
 		HU_DoCEcho(va("%s\\is now super.\\\\\\\\", player_names[player-players]));
@@ -1417,7 +1416,7 @@ void P_DoSuperDetransformation(player_t *player)
 	if (!G_CoopGametype())
 		player->powers[pw_flashing] = flashingtics-1;
 
-	if (player->mo->sprite2 & SPR2F_SUPER)
+	if (player->mo->sprite2 & FF_SPR2SUPER)
 		P_SetMobjState(player->mo, player->mo->state-states);
 
 	// Inform the netgame that the champion has fallen in the heat of battle.
@@ -4211,7 +4210,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
 	if (player->pflags & PF_ATTACKDOWN || player->climbing || (G_TagGametype() && !(player->pflags & PF_TAGIT)))
 		return;
 
-	// Fire a fireball if we have the Fire Flower powerup!
 	if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->weapondelay))
 	{
 		player->pflags |= PF_ATTACKDOWN;
@@ -4223,7 +4221,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
 		return;
 	}
 
-	// No ringslinging outside of ringslinger!
 	if (!G_RingSlingerGametype() || player->weapondelay)
 		return;
 
@@ -4402,7 +4399,34 @@ static void P_DoSuperStuff(player_t *player)
 		// If you're super and not Sonic, de-superize!
 		if (!(ALL7EMERALDS(emeralds) && player->charflags & SF_SUPER))
 		{
-			P_DoSuperDetransformation(player);
+			player->powers[pw_super] = 0;
+			P_SetMobjState(player->mo, S_PLAY_STND);
+			if (P_IsLocalPlayer(player))
+			{
+				music_stack_noposition = true; // HACK: Do not reposition next music
+				music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music
+			}
+			P_RestoreMusic(player);
+			P_SpawnShieldOrb(player);
+
+			// Restore color
+			if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
+			{
+				player->mo->color = SKINCOLOR_WHITE;
+				G_GhostAddColor(GHC_FIREFLOWER);
+			}
+			else
+			{
+				player->mo->color = P_GetPlayerColor(player);
+				G_GhostAddColor(GHC_NORMAL);
+			}
+
+			if (!G_CoopGametype())
+			{
+				HU_SetCEchoFlags(0);
+				HU_SetCEchoDuration(5);
+				HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players]));
+			}
 			return;
 		}
 
@@ -4429,31 +4453,28 @@ static void P_DoSuperStuff(player_t *player)
 
 		// Ran out of rings while super!
 		if (player->rings <= 0 || player->exiting)
+		{
 			P_DoSuperDetransformation(player);
+		}
 	}
 }
 
 //
 // P_SuperReady
 //
-// Returns true if player is ready to transform or detransform
+// Returns true if player is ready to turn super, duh
 //
 boolean P_SuperReady(player_t *player)
 {
-	if (player->mo
-	&& (player->rings >= 50)
-	&& ALL7EMERALDS(emeralds)
+	if (!player->powers[pw_super]
+	&& !player->powers[pw_invulnerability]
+	&& !player->powers[pw_tailsfly]
 	&& (player->charflags & SF_SUPER)
 	&& (player->pflags & PF_JUMPED)
-	&& !player->powers[pw_super]
-	&& !player->powers[pw_invulnerability]
 	&& !(player->powers[pw_shield] & SH_NOSTACK)
-	&& !player->powers[pw_tailsfly]
-	&& !player->powers[pw_carry]
-	&& !P_PlayerInPain(player)
-	&& !player->climbing
-	&& !(player->pflags & (PF_JUMPSTASIS|PF_THOKKED|PF_STARTDASH|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY))
-	&& !(maptol & TOL_NIGHTS))
+	&& !(maptol & TOL_NIGHTS)
+	&& ALL7EMERALDS(emeralds)
+	&& (player->rings >= 50))
 		return true;
 
 	return false;
@@ -5158,7 +5179,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
 {
 	mobj_t *lockonshield = NULL;
 
-	if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SHIELDDOWN)
+	if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN)
 		&& ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted
 	{
 		if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT && !(player->charflags & SF_NOSHIELDABILITY))
@@ -5188,7 +5209,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
 				}
 			}
 		}
-		if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SHIELD && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) // Shield button effects
+		if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SPIN && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) // Spin button effects
 		{
 			// Force stop
 			if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
@@ -5277,7 +5298,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, boolean spinshieldhack)
+static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 {
 	mobj_t *lockonthok = NULL, *visual = NULL;
 
@@ -5310,12 +5331,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd, boolean spinshieldhac
 			;
 		else if (P_PlayerShieldThink(player, cmd, lockonthok, visual))
 			;
-		else if (cmd->buttons & BT_SPIN)
+		else if ((cmd->buttons & BT_SPIN))
 		{
-			if (spinshieldhack && !(player->pflags & PF_SPINDOWN) && P_SuperReady(player))
+			if (!(player->pflags & PF_SPINDOWN) && P_SuperReady(player))
 			{
-				// If you're using two-button play, can turn Super and aren't already,
-				// and you don't have a shield, then turn Super!
+				// If you can turn super and aren't already,
+				// and you don't have a shield, do it!
 				P_DoSuperTransformation(player, false);
 			}
 			else if (!LUA_HookPlayer(player, HOOK(JumpSpinSpecial)))
@@ -5418,6 +5439,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd, boolean spinshieldhac
 		}
 		else if (player->pflags & PF_SLIDING || ((gametyperules & GTR_TEAMFLAGS) && player->gotflag) || player->pflags & PF_SHIELDABILITY)
 			;
+		/*else if (P_SuperReady(player))
+		{
+			// If you can turn super and aren't already,
+			// and you don't have a shield, do it!
+			P_DoSuperTransformation(player, false);
+		}*/
 		else if (player->pflags & PF_JUMPED)
 		{
 			if (!LUA_HookPlayer(player, HOOK(AbilitySpecial)))
@@ -8070,7 +8097,6 @@ 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;
 
@@ -8692,13 +8718,10 @@ 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, spinshieldhack);
+	P_DoJumpStuff(player, cmd);
 
 	// If you're not spinning, you'd better not be spindashing!
 	if (!(player->pflags & PF_SPINNING) && player->powers[pw_carry] != CR_NIGHTSMODE)
@@ -8786,21 +8809,10 @@ void P_MovePlayer(player_t *player)
 			P_PlayerFlagBurst(player, true);
 	}
 
-	// Check for fire and shield buttons
+	// check for fire
 	if (!player->exiting)
-	{
 		P_DoFiring(player, cmd);
 
-		// Shield button behavior
-		// Check P_PlayerShieldThink for actual shields!
-		if ((cmd->buttons & BT_SHIELD) && !(player->pflags & PF_SHIELDDOWN) && !spinshieldhack)
-		{
-			// Transform into super if we can!
-			if (P_SuperReady(player))
-				P_DoSuperTransformation(player, false);
-		}
-	}
-
 	{
 		boolean atspinheight = false;
 		fixed_t oldheight = player->mo->height;
@@ -11540,6 +11552,9 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 		return;
 	}
 
+	if (player->skidtime) // Rotate during metal sonic's new skid animation
+		angle += ANGLE_90;
+
 	if (underwater) // No fume underwater; spawn bubbles instead!
 	{
 		fume->movedir	+= FixedAngle(FixedDiv(2 * player->speed, 3 * mo->scale));
@@ -12056,7 +12071,7 @@ void P_PlayerThink(player_t *player)
 				ticmiss++;
 
 			P_DoRopeHang(player);
-			P_DoJumpStuff(player, &player->cmd, false); // P_DoRopeHang would set PF_SPINDOWN, so no spinshieldhack here
+			P_DoJumpStuff(player, &player->cmd);
 		}
 		else //if (player->powers[pw_carry] == CR_ZOOMTUBE)
 		{
@@ -12330,12 +12345,6 @@ 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)
diff --git a/src/r_bbox.c b/src/r_bbox.c
index 8ccad2bb58186098810f299405fc0f4d23fa9b5a..93fa2dca28c4a1f923c69ff4f44958c7e583310c 100644
--- a/src/r_bbox.c
+++ b/src/r_bbox.c
@@ -275,7 +275,7 @@ boolean R_ThingBoundingBoxVisible(mobj_t *thing)
 	switch (thing->type)
 	{
 		default:
-			// First person / awayviewmobj -- rendering a bbox 
+			// First person / awayviewmobj -- rendering a bbox
 			// too close to the viewpoint causes anomalies
 			// and these are exactly on the viewpoint!
 			if (thing != r_viewmobj)
diff --git a/src/r_main.c b/src/r_main.c
index ee05876da1395f4375515457e552b36cffcfd486..46bac9dc76a1886cb3ddc60167772312721b6a53 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1095,7 +1095,7 @@ void R_SetupFrame(player_t *player)
 	camera_t *thiscam;
 	boolean chasecam = R_ViewpointHasChasecam(player);
 	boolean ispaused = paused || P_AutoPause();
-	
+
 	if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
 		thiscam = &camera2;
 	else
@@ -1375,7 +1375,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
 		chasecam = true; // force chasecam on
 	else if (player->spectator) // no spectator chasecam
 		chasecam = false; // force chasecam off
-		
+
 	if (chasecam && !thiscam->chase)
 	{
 		P_ResetCamera(player, thiscam);
@@ -1386,7 +1386,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
 		P_ResetCamera(player, thiscam);
 		thiscam->chase = false;
 	}
-	
+
 	if (isplayer2)
 	{
 		R_SetViewContext(VIEWCONTEXT_PLAYER2);
diff --git a/src/r_textures.c b/src/r_textures.c
index bd22a2df13443e7596b303704eecae93281ab418..4c52f75ebe169607d8f367bf07c03bc7f2eb70af 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -1110,7 +1110,7 @@ static lumpnum_t W_GetTexPatchLumpNum(const char *name)
 
 	lumpnum_t lump = LUMPERROR;
 	INT32 lump_type_it;
-	
+
 
 	for (lump_type_it = 0; lump_type_it < USE__MAX; lump_type_it++)
 	{
@@ -1716,7 +1716,7 @@ const char *R_CheckTextureNameForNum(INT32 num)
 {
 	if (num > 0 && num < numtextures)
 		return textures[num]->name;
-	
+
 	return "-";
 }
 
diff --git a/src/r_things.c b/src/r_things.c
index 50855e2fc6630b370657f2093b08fda305a4a780..2c0529e47a572b8fcd5b7966fcb7652e13a6b03b 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -968,7 +968,9 @@ UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 trans
 	if (color != SKINCOLOR_NONE)
 	{
 		// New colormap stuff for skins Tails 06-07-2002
-		if (mobj->colorized)
+		if ((mobj->state-states == S_METALSONIC_DASH || mobj->state-states == S_METALSONIC_BOUNCE) && (((leveltime/2) & 1))) // Metal boss doing attack
+			skinnum = TC_DASHMODE;
+		else if (mobj->colorized)
 			skinnum = TC_RAINBOW;
 		else if (mobj->player && mobj->player->dashmode >= DASHMODE_THRESHOLD
 			&& (mobj->player->charflags & SF_DASHMODE)
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index 99425108e69b3761fd03de7790d02232e44bb898..8950846ee4f43cf794bd6d2505bbf039e6c71d2f 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -14,8 +14,13 @@ target_sources(SRB2SDL2 PRIVATE
 
 # 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)
+if (NOT SRB2_CONFIG_FORCE_NO_MS_BITFIELDS)
+	if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+		check_cxx_compiler_flag("-mno-ms-bitfields" HAS_NO_MS_BITFIELDS)
+		if(HAS_NO_MS_BITFIELDS)
+			target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+		endif()
+	endif()
 endif()
 
 # Yes we know we use insecure CRT functions...
diff --git a/src/sounds.c b/src/sounds.c
index 75bccb396492e52f3920177ac44387b5e624d2da..19b69dd2825748ae97493172a2571d970a1b4dec 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -284,8 +284,6 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"mario8", false,  48, SF_X4AWAYSOUND,     -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"},
   {"mario9",  true, 120, 0,                  -1, NULL, 0, -1, -1, LUMPERROR, "Emerging power-up"},
   {"marioa",  true, 192, 0,                  -1, NULL, 0, -1, -1, LUMPERROR, "One-up"},
-  {"mariob",  true, 127, 0,                  -1, NULL, 0, -1, -1, LUMPERROR, "Spring"},
-  {"marioc",  true, 127, 0,                  -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"},
   {"thwomp",  true, 127, SF_X4AWAYSOUND,     -1, NULL, 0, -1, -1, LUMPERROR, "Thwomp"},
 
   // Black Eggman
diff --git a/src/sounds.h b/src/sounds.h
index a01d192e60ca6df0e8a0b6ca208ee97f84f8aba2..bf934276858a301a542492abd560f730a4f1077d 100644
--- a/src/sounds.h
+++ b/src/sounds.h
@@ -332,8 +332,6 @@ typedef enum
 	sfx_mario8,
 	sfx_mario9,
 	sfx_marioa,
-	sfx_mariob,
-	sfx_marioc,
 	sfx_thwomp,
 
 	// Black Eggman
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 391d038a4a129b5334bdfb566edf29f76e253ead..4fdacd51ada1871c4a711f91749e0d9b39872796 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1176,10 +1176,8 @@ static void ST_drawInput(void)
 	V_DrawFill(x+16+(xoffs), y+(yoffs)-offs, 10, 10, col);\
 	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(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");
+	drawbutt( 4,-3, BT_JUMP, 'J');
+	drawbutt(15,-3, BT_SPIN, 'S');
 
 	V_DrawFill(x+16+4, y+8, 21, 10, hudinfo[HUD_INPUT].f|20); // sundial backing
 	if (stplyr->mo)
@@ -2822,7 +2820,7 @@ static void ST_overlayDrawer(void)
 		}
 		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 && LUA_HudEnabled(hud_powerups))
 		ST_drawPowerupHUD(); // same as it ever was...
diff --git a/src/string.c b/src/string.c
index c5d95b224fffd63b43d0682ae0a05408844271d6..79573283e10bee24ef70a394899c6f5585f67521 100644
--- a/src/string.c
+++ b/src/string.c
@@ -83,7 +83,7 @@ char *xstrtok(char *line, const char *delims)
 		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
@@ -91,4 +91,3 @@ char *xstrtok(char *line, const char *delims)
 
 	return p;
 }
-
diff --git a/src/v_video.c b/src/v_video.c
index 42a4aaa009bc32584d553f1182ec31badebf0a42..39a1001d199952077fc783875b4d104c819a8fcd 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1137,7 +1137,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
 	}
 #endif
 
-	
+
 
 	if (splitscreen && (c & V_PERPLAYER))
 	{
@@ -1953,7 +1953,7 @@ char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *
 	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	slen = strlen(string);
-	
+
 	if (w == 0)
 		w = BASEVIDWIDTH;
 	w -= x;
@@ -2131,7 +2131,7 @@ void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t
 				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);
@@ -2422,7 +2422,7 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 			if (wline < w) wline = w;
 			w = 0;
 			continue;
-		}	
+		}
 		if (string[i] & 0x80)
 			continue;
 
@@ -2455,7 +2455,7 @@ INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font)
 			{
 				result += (option & V_RETURN8) ? 8 : font.linespacing;
 				h = 0;
-			}	
+			}
 			continue;
 		}
 
diff --git a/src/version.h b/src/version.h
index 21204e01619cf9d177a56800ac81eeb6afa95a8c..8e69194cd20b98debe50bc67afb264a0bb2aec9b 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
-#define SRB2VERSION "2.2.14"/* this must be the first line, for cmake !! */
+#define SRB2VERSION "2.2.15"/* this must be the first line, for cmake !! */
 
 // The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/members/?key=ms_admin ).
 // DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
@@ -9,7 +9,7 @@
 // it's only for detection of the version the player is using so the MS can alert them of an update.
 // Only set it higher, not lower, obviously.
 // Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1".
-#define MODVERSION 55
+#define MODVERSION 56
 
 // Define this as a prerelease version suffix (pre#, RC#)
 //#define BETAVERSION "pre4"
diff --git a/src/y_inter.c b/src/y_inter.c
index e9905f1de870d3dd49aeba817a12451ce1ffdbd3..d7e644567eb14030e1bbb569434e1db460d8b56c 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -581,7 +581,7 @@ void Y_IntermissionDrawer(void)
 			if (LUA_HudEnabled(hud_intermissiontitletext))
 			{
 				const char *ringtext = "\x82" "50 rings, no shield";
-				const char *tut1text = "\x82" "press " "\x80" "shield";
+				const char *tut1text = "\x82" "press " "\x80" "spin";
 				const char *tut2text = "\x82" "mid-" "\x80" "jump";
 				ttheight = 8;
 				V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
@@ -1648,7 +1648,7 @@ static void Y_CalculateMatchWinners(void)
 				data.match.scores[data.match.numplayers] = players[i].score;
 				data.match.color[data.match.numplayers] = &players[i].skincolor;
 				if (data.match.ctfteam[data.match.numplayers] == 1) // red team
-					data.match.color[data.match.numplayers] = &skincolor_redteam; 
+					data.match.color[data.match.numplayers] = &skincolor_redteam;
 
 				if (data.match.ctfteam[data.match.numplayers] == 2) // blue team
 					data.match.color[data.match.numplayers] = &skincolor_blueteam;
@@ -2074,7 +2074,7 @@ static void Y_AwardCoopBonuses(void)
 				(bonuses_list[bonusnum][j])(&players[i], &localbonuses[j]);
 			else
 				Y_SetNullBonus(&players[i], &localbonuses[j]);
-			
+
 			players[i].score += localbonuses[j].points;
 			if (players[i].score > MAXSCORE)
 				players[i].score = MAXSCORE;
diff --git a/thirdparty/curl.cmake b/thirdparty/curl.cmake
index 5c3aa26e35882d64ca8a6cf99517d28e9fc56dcc..7b6c3a299f951139fe18e0c25d18074d0deae300 100644
--- a/thirdparty/curl.cmake
+++ b/thirdparty/curl.cmake
@@ -55,4 +55,3 @@ else()
 endif()
 
 FetchContent_MakeAvailable(curl)
-
diff --git a/thirdparty/sdl2-mixer-ext.cmake b/thirdparty/sdl2-mixer-ext.cmake
index a52b11584ae747630ed4c44af6282fb8cc9dea75..1998a7bd9217c2bdfd9da5f1b5de544e48cd6c5d 100644
--- a/thirdparty/sdl2-mixer-ext.cmake
+++ b/thirdparty/sdl2-mixer-ext.cmake
@@ -36,4 +36,3 @@ FetchContent_Declare(
 )
 
 FetchContent_MakeAvailable(SDL2_mixer_ext)
-
diff --git a/thirdparty/zlib.cmake b/thirdparty/zlib.cmake
index 257609f775ae9f7c325665198f0e8804a5cb6030..50c567dda9e664632c709fc374276c401ee59203 100644
--- a/thirdparty/zlib.cmake
+++ b/thirdparty/zlib.cmake
@@ -33,4 +33,3 @@ FetchContent_MakeAvailable(ZLIB)
 add_library(ZLIB::ZLIB ALIAS zlibstatic)
 
 set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib" "${zlib_BINARY_DIR}" CACHE PATH "" FORCE)
-