diff --git a/.gitignore b/.gitignore
index 4ba05f7ca698b968eec6391857fa5ec68e1b422e..a3d823fa2182edef86c35ee2810560e5d8f7408e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,4 @@ Win32_LIB_ASM_Release
 /CMakeUserPresets.json
 /out
 /objs/VC10
+/thirdparty/vcpkg-overlays
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b21ce1b00313089705addb772b455a8308d21795..29f5ef5fff9f1bc4afb83006c65f54088762e6dc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,848 +1,19 @@
-variables:
-  GIT_STRATEGY: clone
-  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
-
-default:
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:stable
-
-  cache:
-    - key: ccache-$CI_PROJECT_PATH_SLUG-$CI_JOB_NAME_SLUG
-      fallback_keys:
-        - cache-$CI_PROJECT_PATH_SLUG-$CI_DEFAULT_BRANCH
-        - cache-$CI_PROJECT_PATH_SLUG-default
-      paths:
-        - ccache
-        - ccache_statslog
-
-    - key: apt-$CI_JOB_IMAGE
-      paths:
-        - apt-cache
-      unprotect: true
-
-    - key: apk-$CI_JOB_IMAGE
-      paths:
-        - apk-cache
-      unprotect: true
-
-  before_script:
-    - - |
-         # debconf
-         echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
-      - export DEBIAN_FRONTEND="noninteractive"
-      - export DEBIAN_PRIORITY="low"
-      - export DEBCONF_NONINTERACTIVE_SEEN="true"
-      - |
-          # debconf
-          echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
-    - - |
-          # dpkg_aa
-          echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
-      - dpkg --add-architecture i386
-      - dpkg --add-architecture amd64
-      - dpkg --add-architecture arm64
-      - |
-          # dpkg_aa
-          echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
-    - - |
-          # apt_conf
-          echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
-      - export APT_CACHE_DIR=`pwd`/apt-cache
-      - mkdir --parents --verbose $APT_CACHE_DIR/partial/
-      - touch /etc/apt/apt.conf.d/99build
-      - |
-          # apt.conf
-          echo Adding options to apt.conf':'
-      - |
-          # APT::Install-Recommends
-          echo APT::Install-Recommends "false"\;       | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # quit
-          echo quiet "1"\;                             | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # APT::Get::Assume-Yes
-          echo APT::Get::Assume-Yes "true"\;           | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # Dir::Cache::Archives
-          echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # apt_conf
-          echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
-    - - |
-          # apt_update
-          echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
-      - apt-get update
-      - |
-          # apt_update
-          echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
-
-    - - |
-          # apt_pre
-          echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
-      - apt-get install apt-utils
-      - |
-          # apt_pre
-          echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
-
-    - - |
-          # apt_upgrade
-          echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
-      - apt-get upgrade
-      - |
-          # apt_update
-          echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
+include:
+  - '.gitlab/ci/templates/*.yml'
+  - '.gitlab/ci/jobs/*.yml'
 
-    - - |
-          # apt_common
-          echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apt-get install make git ccache nasm cmake ca-certificates
-      - |
-          # apt_common
-          echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
+workflow:
+  auto_cancel:
+    on_new_commit: interruptible
 
-    - - |
-          # ccache_config
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
-      - mkdir --parents --verbose ~/.ccache/
-      - touch ~/.ccache/ccache.conf
-      - |
-          # cache.conf
-          echo Adding ccache configution option
-      - |
-          # base_dir
-          echo base_dir = $PWD                  | tee --append ~/.ccache/ccache.conf
-      - |
-          # cache_dir
-          echo cache_dir = $PWD/ccache          | tee --append ~/.ccache/ccache.conf
-      - |
-          # compiler_check
-          echo compiler_check = content         | tee --append ~/.ccache/ccache.conf
-      - |
-          # stats_log
-          echo stats_log = $PWD/ccache_statslog | tee --append ~/.ccache/ccache.conf
-      - |
-          # max_size
-          echo max_size = 50M                   | tee --append ~/.ccache/ccache.conf
-      - |
-          # ccache_config
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
-
-    - - |
-          # cache_reset
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
-      - ccache --zero-stats
-      - ccache --show-stats
-      - |
-          # ccache_reset
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME_SLUG"
-
-  after_script:
-    - - |
-           # apt_clean
-           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
-      - apt-get autoclean
-      - |
-          # apt_clean
-          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
-
-    - - |
-          # ccache_stats
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
-      - ccache --show-stats
-      - ccache --show-log-stats || true
-      - |
-          # ccahe_stats
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
+variables:
+  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
+  GIT_DEPTH: 20
 
 stages:
   - build
 
-Debian testing GCC:
-  stage: build
-
-  when: manual
-
-  image: debian:testing-slim
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "testing-gcc"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
-
-  variables:
-    CC: gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Windows x86:
-  stage: build
-
-  when: on_success
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Win32"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
-
-  variables:
-    PREFIX: i686-w64-mingw32
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-mingw-w64-i686-win32
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:amd64:
-  stage: build
-
-  when: on_success
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian amd64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
-
-  variables:
-    CC: x86_64-linux-gnu-gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-    OBJCOPY: x86_64-linux-gnu-objcopy
-    OBJDUMP: x86_64-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian oldstable:amd64:
-  extends: Debian stable:amd64
-
-  when: manual
-
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old amd64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:i386:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian i386"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
-
-  variables:
-    CC: i686-linux-gnu-gcc
-    OBJCOPY: i686-linux-gnu-objcopy
-    OBJDUMP: i686-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:arm64:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
-
-  variables:
-    CC: aarch64-linux-gnu-gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-    OBJCOPY: aarch64-linux-gnu-objcopy
-    OBJDUMP: aarch64-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian oldstable:arm64:
-  extends: Debian stable:arm64
-
-  when: manual
-
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-batocera:arm64:
-  extends: Debian stable:arm64
-
-  when: manual
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Windows x64:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Win64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
-
-  variables:
-    PREFIX: x86_64-w64-mingw32
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-mingw-w64-x86-64-win32
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable Clang:
-  stage: build
-
-  when: on_success
-
-  allow_failure: false
-
-  artifacts:
-    paths:
-      - "build.clang/bin/"
-      - "build.clang/src/config.h"
-    expose_as: "clang"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    CC: clang
-    CXX: clang
-    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
-    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install clang
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # cmake
-          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.clang -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_USE_LIBGME:BOOL=OFF -G "Unix Makefiles"
-      - |
-          # cmake
-          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.clang --keep-going || make --directory=build.clang --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian testing Clang:
-  extends: Debian stable Clang
-
-  when: manual
-
-  allow_failure: true
-
-  image: debian:testing-slim
-
-  artifacts:
-    paths:
-      - "build.clang/bin/"
-      - "build.clang/src/config.h"
-    expose_as: "testing-clang"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
-
-  variables:
-    CC: clang
-    CXX: clang
-    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
-    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-Alpine 3 GCC:
-  stage: build
-
-  when: on_success
-
-  image: alpine:3
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Apline-3"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
-
-  before_script:
-    - - |
-          # apk_cache
-          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
-      - export APK_CACHE_DIR=`pwd`/apk-cache
-      - mkdir --parents --verbose $APK_CACHE_DIR/
-      - ln -sf /etc/apk/cache $APK_CACHE_DIR
-      - |
-          # apk_cache
-          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
-
-    - - |
-          # apk_update
-          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
-      - apk update
-      - |
-          # apk_update
-          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
-
-    - - |
-          # apk_upgrade
-          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
-      - apk upgrade
-      - |
-          # apk_update
-          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
-
-    - - |
-          # apk_common
-          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apk add make git ccache nasm
-      - |
-          # apk_common
-          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
-
-    - - |
-          # ccache_config
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
-      - mkdir --parents --verbose ~/.ccache/
-      - touch ~/.ccache/ccache.conf
-      - |
-          # cache.conf
-          echo Adding ccache configution option
-      - |
-          # base_dir
-          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
-      - |
-          # cache_dir
-          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
-      - |
-          # compiler_check
-          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
-      - |
-          # stats_log
-          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
-      - |
-          # max_size
-          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
-      - |
-          # ccache_config
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
-
-    - - |
-          # cache_reset
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
-      - ccache --zero-stats
-      - ccache --show-stats
-      - |
-          # ccache_reset
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
-
-  script:
-    - - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
-      - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
-
-    - - |
-          # apk_development
-          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
-      - |
-          # apk_development
-          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-  after_script:
-    - - |
-           # apk_clean
-           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
-      - apk cache clean
-      - |
-          # apk_clean
-          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
-
-    - - |
-          # ccache_stats
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
-      - ccache --show-stats --verbose
-      - ccache --show-log-stats --verbose
-      - |
-          # ccahe_stats
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
-
-Alpine 3 GCC Dedicated:
-  extends: Alpine 3 GCC
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Apline-3-Dedicated"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
-
-  script:
-    - - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
-      - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
-
-    - - |
-          # apk_development
-          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev libpng-dev curl-dev
-      - |
-          # apk_development
-          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-osxcross x86_64:
-  stage: build
-
-  artifacts:
-    paths:
-      - "build.osxcross/bin/"
-      - "build.osxcross/src/config.h"
-    expose_as: "Mac x86_64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    OSXCROSS_HOST: x86_64-apple-darwin21.4
-    LD: x86_64-apple-darwin21.4-ld
-
-  script:
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
-      - osxcross-macports install curl libopenmpt libsdl2_mixer
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-osxcross arm64:
-  stage: build
-
-  when: manual
-
-  allow_failure: true
-
+default:
+  interruptible: true
   artifacts:
-    paths:
-      - "build.osxcross/bin/"
-      - "build.osxcross/src/config.h"
-    expose_as: "Mac arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    OSXCROSS_HOST: arm64-apple-darwin21.4
-    LD: arm64-apple-darwin21.4-ld
-
-  script:
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
-      - osxcross-macports install --arm64 curl libopenmpt libsdl2_mixer
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+    expire_in: 1 day
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml b/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
new file mode 100644
index 0000000000000000000000000000000000000000..242ddd0eaa3f0e45504fa0fe258e08c63e0845df
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
@@ -0,0 +1,34 @@
+Alpine 3 GCC Dedicated:
+  extends: Alpine 3 GCC
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3-Dedicated"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add musl-dev libpng-dev curl-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/alpine-3-gcc.yml b/.gitlab/ci/jobs/alpine-3-gcc.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3b12e40167a568e3ced2abc7a09ed0045e0cc99
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc.yml
@@ -0,0 +1,135 @@
+Alpine 3 GCC:
+  stage: build
+
+  when: manual
+
+  image: alpine:3
+
+  allow_failure: true
+
+  cache:
+    - key: apk-$CI_JOB_IMAGE
+      paths:
+        - apk-cache
+      unprotect: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
+
+  before_script:
+    - - |
+          # apk_cache
+          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
+      - export APK_CACHE_DIR=`pwd`/apk-cache
+      - mkdir --parents --verbose $APK_CACHE_DIR/
+      - ln -sf /etc/apk/cache $APK_CACHE_DIR
+      - |
+          # apk_cache
+          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
+
+    - - |
+          # apk_update
+          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
+      - apk update
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
+
+    - - |
+          # apk_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apk upgrade
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
+
+    - - |
+          # apk_common
+          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apk add make git ccache nasm
+      - |
+          # apk_common
+          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+  after_script:
+    - - |
+           # apk_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
+      - apk cache clean
+      - |
+          # apk_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats --verbose
+      - ccache --show-log-stats --verbose
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/.gitlab/ci/jobs/batocera-arm64.yml b/.gitlab/ci/jobs/batocera-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3e43aa8753a0a1500abdc52e9f594863bd4b3691
--- /dev/null
+++ b/.gitlab/ci/jobs/batocera-arm64.yml
@@ -0,0 +1,38 @@
+batocera:arm64:
+  extends: Debian stable:arm64
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-amd64.yml b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3929ecdcd10f8f448072d2c859de6a7dd31d94c7
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
@@ -0,0 +1,40 @@
+Debian oldstable:amd64:
+  extends: Debian stable:amd64
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old amd64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-arm64.yml b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b18d538cd0824041650f3f8a5361b7b07c85f206
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
@@ -0,0 +1,40 @@
+Debian oldstable:arm64:
+  extends: Debian stable:arm64
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-amd64.yml b/.gitlab/ci/jobs/debian-stable-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4a757afe0d519f268bb4541cda49ba03a3181600
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-amd64.yml
@@ -0,0 +1,45 @@
+Debian stable:amd64:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian amd64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
+
+  variables:
+    CC: x86_64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: x86_64-linux-gnu-objcopy
+    OBJDUMP: x86_64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
+
+  when: on_success
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-arm64.yml b/.gitlab/ci/jobs/debian-stable-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..879391affebe7586e019e7bb7f8d77a0599983e2
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-arm64.yml
@@ -0,0 +1,45 @@
+Debian stable:arm64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
+
+  variables:
+    CC: aarch64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: aarch64-linux-gnu-objcopy
+    OBJDUMP: aarch64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-clang-amd64.yml b/.gitlab/ci/jobs/debian-stable-clang-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4686c1849196d3be6cbee936c1ad910c0f93627c
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-clang-amd64.yml
@@ -0,0 +1,55 @@
+Debian stable Clang:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  allow_failure: false
+
+  artifacts:
+    paths:
+      - "build.clang/bin/"
+      - "build.clang/src/config.h"
+    expose_as: "clang"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    CC: clang
+    CXX: clang
+    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
+    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install clang
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.clang -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_USE_LIBGME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.clang --keep-going || make --directory=build.clang --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-i386.yml b/.gitlab/ci/jobs/debian-stable-i386.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cd6206e55e9a497d7065d3ea652c1ed3c6bd8d23
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-i386.yml
@@ -0,0 +1,44 @@
+Debian stable:i386:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian i386"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
+
+  variables:
+    CC: i686-linux-gnu-gcc
+    OBJCOPY: i686-linux-gnu-objcopy
+    OBJDUMP: i686-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-testing-clang-amd64.yml b/.gitlab/ci/jobs/debian-testing-clang-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dc790b397f2187b47a75c05bcf3e5973d5a175e1
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-clang-amd64.yml
@@ -0,0 +1,22 @@
+Debian testing Clang:
+  extends: Debian stable Clang
+
+  when: manual
+
+  allow_failure: true
+
+  image: debian:testing-slim
+
+  artifacts:
+    paths:
+      - "build.clang/bin/"
+      - "build.clang/src/config.h"
+    expose_as: "testing-clang"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
+
+  variables:
+    CC: clang
+    CXX: clang
+    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
+    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
+    LDFLAGS: -Wl,-fuse-ld=gold
diff --git a/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..10799b3053e45a3d98fcfa1f63281e36ebadae9d
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
@@ -0,0 +1,46 @@
+Debian testing GCC:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  image: debian:testing-slim
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "testing-gcc"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
+
+  variables:
+    CC: gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-arm64.yml b/.gitlab/ci/jobs/macos-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3928413610a048460dfe05d0dfc8f92e9da76848
--- /dev/null
+++ b/.gitlab/ci/jobs/macos-arm64.yml
@@ -0,0 +1,44 @@
+osxcross arm64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "build.osxcross/bin/"
+      - "build.osxcross/src/config.h"
+    expose_as: "Mac arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    OSXCROSS_HOST: arm64-apple-darwin21.4
+    LD: arm64-apple-darwin21.4-ld
+
+  script:
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
+      - osxcross-macports install --arm64 curl libopenmpt libsdl2_mixer
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-x86_64.yml b/.gitlab/ci/jobs/macos-x86_64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..818028e49a43624f3e29a357d7d7614ef4dd5118
--- /dev/null
+++ b/.gitlab/ci/jobs/macos-x86_64.yml
@@ -0,0 +1,40 @@
+osxcross x86_64:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "build.osxcross/bin/"
+      - "build.osxcross/src/config.h"
+    expose_as: "Mac x86_64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    OSXCROSS_HOST: x86_64-apple-darwin21.4
+    LD: x86_64-apple-darwin21.4-ld
+
+  script:
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
+      - osxcross-macports install curl libopenmpt libsdl2_mixer
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x64.yml b/.gitlab/ci/jobs/windows-x64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..da8d960bd1330229a2265ed9b015a487f1040e75
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x64.yml
@@ -0,0 +1,35 @@
+Windows x64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
+
+  variables:
+    PREFIX: x86_64-w64-mingw32
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-x86-64-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x86.yml b/.gitlab/ci/jobs/windows-x86.yml
new file mode 100644
index 0000000000000000000000000000000000000000..311c767bbd9cd31d1063a248f68c0a6793dd47d5
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x86.yml
@@ -0,0 +1,35 @@
+Windows x86:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win32"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
+
+  variables:
+    PREFIX: i686-w64-mingw32
+    CC: /usr/bin/i686-w64-mingw32-gcc-posix
+    CXX: /usr/bin/i686-w64-mingw32-g++-posix
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-i686-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/templates/srb2ci.yml b/.gitlab/ci/templates/srb2ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3716d9df921407cb29081af301a5b6a3d92db459
--- /dev/null
+++ b/.gitlab/ci/templates/srb2ci.yml
@@ -0,0 +1,145 @@
+.srb2ci:
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:stable
+
+  cache:
+    - key: ccache-$CI_JOB_NAME_SLUG-$CI_COMMIT_REF_SLUG
+      fallback_keys:
+        - ccache-$CI_JOB_NAME_SLUG-$CI_DEFAULT_BRANCH
+        - ccache-$CI_JOB_NAME_SLUG-master
+      paths:
+        - build/ccache
+        - build/ccache_statslog
+
+    - key: apt-$CI_JOB_IMAGE
+      paths:
+        - build/apt-cache
+      unprotect: true
+
+  before_script:
+    - - |
+         # debconf
+         echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
+      - export DEBIAN_FRONTEND="noninteractive"
+      - export DEBIAN_PRIORITY="low"
+      - export DEBCONF_NONINTERACTIVE_SEEN="true"
+      - |
+          # debconf
+          echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
+    - - |
+          # dpkg_aa
+          echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
+      - dpkg --add-architecture i386
+      - dpkg --add-architecture amd64
+      - dpkg --add-architecture arm64
+      - |
+          # dpkg_aa
+          echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
+    - - |
+          # apt_conf
+          echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
+      - export APT_CACHE_DIR=$CI_PROJECT_DIR/build/apt-cache
+      - mkdir --parents --verbose $APT_CACHE_DIR/partial/
+      - touch /etc/apt/apt.conf.d/99build
+      - |
+          # apt.conf
+          echo Adding options to apt.conf':'
+      - |
+          # APT::Install-Recommends
+          echo APT::Install-Recommends "false"\;       | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # quit
+          echo quiet "1"\;                             | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # APT::Get::Assume-Yes
+          echo APT::Get::Assume-Yes "true"\;           | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # Dir::Cache::Archives
+          echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # apt_conf
+          echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
+    - - |
+          # apt_update
+          echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
+      - apt-get update
+      - |
+          # apt_update
+          echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
+
+    - - |
+          # apt_pre
+          echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
+      - apt-get install apt-utils
+      - |
+          # apt_pre
+          echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
+
+    - - |
+          # apt_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apt-get upgrade
+      - |
+          # apt_update
+          echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
+
+    - - |
+          # apt_common
+          echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apt-get install make git ccache nasm cmake ca-certificates
+      - |
+          # apt_common
+          echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $CI_PROJECT_DIR                        | tee --append ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $CI_PROJECT_DIR/build/ccache          | tee --append ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content                          | tee --append ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $CI_PROJECT_DIR/build/ccache_statslog | tee --append ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 300M                                   | tee --append ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  after_script:
+    - - |
+           # apt_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
+      - apt-get autoclean
+      - |
+          # apt_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats
+      - ccache --show-log-stats || true
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 358e62cc4d5bb72631cbcbe50f7b512a1e97da2a..3b08a9facc348aad76f77b55a5700b8929859333 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,6 @@ endif()
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
 include(CMakeDependentOption)
-include(cmake/CPM.cmake)
 
 file(STRINGS src/version.h SRB2_VERSION)
 string(REGEX MATCH "[0-9]+\\.[0-9.]+" SRB2_VERSION ${SRB2_VERSION})
@@ -46,28 +45,23 @@ SET(CPACK_OUTPUT_FILE_PREFIX package)
 include(CPack)
 
 # Options
-
-if("${CMAKE_SYSTEM_NAME}" MATCHES Linux)
-	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
+if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
+	if(DEFINED VCPKG_TARGET_TRIPLET)
+		set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
+	else()
+		set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF)
+	endif()
 else()
-	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF)
+	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
 endif()
 
 # Clang tidy options will be ignored if CMAKE_<LANG>_CLANG_TIDY are set.
 option(SRB2_CONFIG_ENABLE_CLANG_TIDY_C "Enable default clang-tidy check configuration for C" OFF)
 option(SRB2_CONFIG_ENABLE_CLANG_TIDY_CXX "Enable default clang-tidy check configuration for C++" OFF)
 option(
-	SRB2_CONFIG_SYSTEM_LIBRARIES
-	"Link dependencies using CMake's find_package and do not use internal builds"
-	${SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT}
-)
-option(SRB2_CONFIG_ENABLE_TESTS "Build the test suite" ON)
-# This option isn't recommended for distribution builds and probably won't work (yet).
-cmake_dependent_option(
-	SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES
-	"Use dynamic libraries when compiling internal dependencies"
-	OFF "NOT SRB2_CONFIG_SYSTEM_LIBRARIES"
-	OFF
+	SRB2_CONFIG_STATIC_STDLIB
+	"Link static version of standard library. All dependencies must also be static"
+	ON
 )
 option(SRB2_CONFIG_HWRENDER "Enable hardware render (OpenGL) support" ON)
 option(SRB2_CONFIG_USE_GME "Enable GME playback support" OFF)
@@ -82,63 +76,27 @@ option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF)
 option(SRB2_CONFIG_PROFILEMODE "Compile for profiling (GCC only)." OFF)
 set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.")
 
-if(SRB2_CONFIG_ENABLE_TESTS)
-	# https://github.com/catchorg/Catch2
-	CPMAddPackage(
-		NAME Catch2
-		VERSION 3.4.0
-		GITHUB_REPOSITORY catchorg/Catch2
-		OPTIONS
-			"CATCH_INSTALL_DOCS OFF"
-	)
-	list(APPEND CMAKE_MODULE_PATH "${Catch2_SOURCE_DIR}/extras")
-	include(CTest)
-	include(Catch)
-	add_executable(srb2tests)
-	# To add tests, use target_sources to add individual test files to the target in subdirs.
-	target_link_libraries(srb2tests PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
-	target_compile_features(srb2tests PRIVATE c_std_11 cxx_std_17)
-	catch_discover_tests(srb2tests)
-endif()
+# Dependencies
+add_subdirectory(thirdparty)
 
-# Enable CCache
-# (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options)
-if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows)
-	option(USE_CCACHE "Enable ccache support" OFF)
-
-	if(USE_CCACHE)
-		find_program(CCACHE_TOOL_PATH ccache)
-		if(CCACHE_TOOL_PATH)
-			set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
-			set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
-		else()
-			message(WARNING "USE_CCACHE was set but ccache is not found (set CCACHE_TOOL_PATH)")
-		endif()
-	endif()
+if(SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
+	set(SRB2_INTERNAL_LIBRARY_TYPE SHARED)
+	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES OFF)
 else()
-	CPMAddPackage(
-		NAME Ccache.cmake
-		GITHUB_REPOSITORY TheLartians/Ccache.cmake
-		VERSION 1.2
-	)
+	set(SRB2_INTERNAL_LIBRARY_TYPE STATIC)
+	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES ON)
 endif()
 
-# Dependencies
-add_subdirectory(thirdparty)
 
-if("${SRB2_CONFIG_SYSTEM_LIBRARIES}")
-	find_package(ZLIB REQUIRED)
-	find_package(PNG REQUIRED)
-	find_package(SDL2 REQUIRED)
-	find_package(SDL2_mixer REQUIRED)
-	find_package(CURL REQUIRED)
-	find_package(OPENMPT REQUIRED)
-
-	# libgme defaults to "Nuked" YM2612 emulator, which is
-	# very SLOW. The system library probably uses the
-	# default so just always build it.
-	#find_package(GME REQUIRED)
+find_package(ZLIB REQUIRED)
+find_package(PNG REQUIRED)
+find_package(CURL REQUIRED)
+find_package(libopenmpt QUIET)
+if("${SRB2_CONFIG_USE_GME}")
+	find_package(libgme QUIET)
 endif()
+find_package(miniupnpc QUIET)
+
 
 if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
 	message(FATAL_ERROR "In-source builds will bring you a world of pain. Please make a separate directory to invoke CMake from.")
diff --git a/CMakePresets.json b/CMakePresets.json
index effea7260656c6235c75b07669edea01eeb682b7..8cb95d797f7f4c3ae708effa15e0d38112175937 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -2,26 +2,263 @@
 	"version": 3,
 	"configurePresets": [
 		{
-			"name": "default",
-			"description": "Build using default generator",
-			"binaryDir": "build",
+			"name": "__debug",
+			"hidden": true,
 			"cacheVariables": {
+				"SRB2_CONFIG_DEV_BUILD": "ON",
+				"CMAKE_BUILD_TYPE": "Debug"
+			}
+		},
+		{
+			"name": "__develop",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_C_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"SRB2_CONFIG_DEV_BUILD": "ON",
 				"CMAKE_BUILD_TYPE": "RelWithDebInfo"
 			}
 		},
 		{
-			"name": "debug",
-			"description": "Build for development (no optimizations)",
-			"inherits": "default",
+			"name": "__release",
+			"hidden": true,
 			"cacheVariables": {
-				"CMAKE_BUILD_TYPE": "Debug"
+				"CMAKE_C_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"SRB2_CONFIG_DEV_BUILD": "OFF",
+				"CMAKE_BUILD_TYPE": "RelWithDebInfo"
+			}
+		},
+		{
+			"name": "__testers",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_C_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "-DNDEBUG",
+				"SRB2_CONFIG_DEV_BUILD": "ON",
+				"CMAKE_BUILD_TYPE": "RelWithDebInfo",
+				"SRB2_CONFIG_TESTERS": "ON"
+			}
+		},
+		{
+			"name": "__ninja",
+			"hidden": true,
+			"generator": "Ninja",
+			"cacheVariables": {
+				"CMAKE_COLOR_DIAGNOSTICS": "ON"
+			}
+		},
+		{
+			"name": "__vcpkg-toolchain",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
+			}
+		},
+		{
+			"name": "__compiler-mingw-w64-i686",
+			"hidden": true,
+			"cacheVariables": {
+				"CMAKE_C_COMPILER": "i686-w64-mingw32-gcc",
+				"CMAKE_CXX_COMPILER": "i686-w64-mingw32-g++"
+			}
+		},
+		{
+			"name": "__mingw-dynamic",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_TARGET_TRIPLET": "x86-mingw-dynamic"
 			}
+		},
+		{
+			"name": "__mingw-static",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_HOST_TRIPLET": "x86-mingw-static",
+				"VCPKG_TARGET_TRIPLET": "x86-mingw-static"
+			}
+		},
+		{
+			"name": "__osx_x64",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_TARGET_TRIPLET": "x64-osx"
+			}
+		},
+		{
+			"name": "__osx_arm64",
+			"hidden": true,
+			"cacheVariables": {
+				"VCPKG_TARGET_TRIPLET": "arm64-osx"
+			}
+		},
+
+		{
+			"name": "ninja-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja"]
+		},
+		{
+			"name": "ninja-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja"]
+		},
+		{
+			"name": "ninja-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja"]
+		},
+		{
+			"name": "ninja-testers",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__testers", "__ninja"]
+		},
+
+		{
+			"name": "ninja-vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja", "__vcpkg-toolchain"]
+		},
+		{
+			"name": "ninja-vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja", "__vcpkg-toolchain"]
+		},
+		{
+			"name": "ninja-vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja", "__vcpkg-toolchain"]
+		},
+		{
+			"name": "ninja-vcpkg-testers",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__testers", "__ninja", "__vcpkg-toolchain"]
+		},
+
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-testers",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__testers", "__compiler-mingw-w64-i686", "__ninja", "__vcpkg-toolchain", "__mingw-static"]
+		},
+
+		{
+			"name": "ninja-x64_osx_vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja", "__vcpkg-toolchain", "__osx_x64"]
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja", "__vcpkg-toolchain", "__osx_x64"]
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja", "__vcpkg-toolchain", "__osx_x64"]
+		},
+
+		{
+			"name": "ninja-arm64_osx_vcpkg-debug",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__debug", "__ninja", "__vcpkg-toolchain", "__osx_arm64"]
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-develop",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__develop", "__ninja", "__vcpkg-toolchain", "__osx_arm64"]
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-release",
+			"hidden": false,
+			"binaryDir": "build/${presetName}",
+			"inherits": ["__release", "__ninja", "__vcpkg-toolchain", "__osx_arm64"]
 		}
 	],
+
 	"buildPresets": [
 		{
-			"name": "default",
-			"configurePreset": "default"
+			"name": "ninja-debug",
+			"configurePreset": "ninja-debug"
+		},
+		{
+			"name": "ninja-develop",
+			"configurePreset": "ninja-develop"
+		},
+		{
+			"name": "ninja-release",
+			"configurePreset": "ninja-release"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-debug",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-debug"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-develop",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-develop"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-release",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-release"
+		},
+		{
+			"name": "ninja-x86_mingw_static_vcpkg-testers",
+			"configurePreset": "ninja-x86_mingw_static_vcpkg-testers"
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-debug",
+			"configurePreset": "ninja-x64_osx_vcpkg-debug"
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-develop",
+			"configurePreset": "ninja-x64_osx_vcpkg-develop"
+		},
+		{
+			"name": "ninja-x64_osx_vcpkg-release",
+			"configurePreset": "ninja-x64_osx_vcpkg-release"
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-debug",
+			"configurePreset": "ninja-arm64_osx_vcpkg-debug"
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-develop",
+			"configurePreset": "ninja-arm64_osx_vcpkg-develop"
+		},
+		{
+			"name": "ninja-arm64_osx_vcpkg-release",
+			"configurePreset": "ninja-arm64_osx_vcpkg-release"
 		}
 	]
-}
+}
\ No newline at end of file
diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake
deleted file mode 100644
index fba27d2fef3d2bf2edb50ea41687157dc0730c20..0000000000000000000000000000000000000000
--- a/cmake/CPM.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-set(CPM_DOWNLOAD_VERSION 0.38.7)
-
-if(CPM_SOURCE_CACHE)
-  set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
-elseif(DEFINED ENV{CPM_SOURCE_CACHE})
-  set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
-else()
-  set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
-endif()
-
-# Expand relative path. This is important if the provided path contains a tilde (~)
-get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
-if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
-  message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
-  file(DOWNLOAD
-       https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
-       ${CPM_DOWNLOAD_LOCATION}
-  )
-endif()
-
-include(${CPM_DOWNLOAD_LOCATION})
diff --git a/cmake/Modules/FindGME.cmake b/cmake/Modules/FindGME.cmake
deleted file mode 100644
index 3af0a94be604f44cf0eda200f3d90a129ea77809..0000000000000000000000000000000000000000
--- a/cmake/Modules/FindGME.cmake
+++ /dev/null
@@ -1,33 +0,0 @@
-include(LibFindMacros)
-
-libfind_pkg_check_modules(GME_PKGCONF GME)
-
-find_path(GME_INCLUDE_DIR
-	NAMES gme.h
-	PATHS
-		${GME_PKGCONF_INCLUDE_DIRS}
-		"/usr/include/gme"
-		"/usr/local/include/gme"
-)
-
-find_library(GME_LIBRARY
-	NAMES gme
-	PATHS
-		${GME_PKGCONF_LIBRARY_DIRS}
-		"/usr/lib"
-		"/usr/local/lib"
-)
-
-set(GME_PROCESS_INCLUDES GME_INCLUDE_DIR)
-set(GME_PROCESS_LIBS GME_LIBRARY)
-libfind_process(GME)
-
-if(GME_FOUND AND NOT TARGET gme)
-	add_library(gme UNKNOWN IMPORTED)
-	set_target_properties(
-		gme
-		PROPERTIES
-		IMPORTED_LOCATION "${GME_LIBRARY}"
-		INTERFACE_INCLUDE_DIRECTORIES "${GME_INCLUDE_DIR}"
-	)
-endif()
diff --git a/cmake/Modules/FindOPENMPT.cmake b/cmake/Modules/FindOPENMPT.cmake
deleted file mode 100644
index 7e5b2d5a3966be22d22afdb815934cf20fe0e4d7..0000000000000000000000000000000000000000
--- a/cmake/Modules/FindOPENMPT.cmake
+++ /dev/null
@@ -1,33 +0,0 @@
-include(LibFindMacros)
-
-libfind_pkg_check_modules(OPENMPT_PKGCONF OPENMPT)
-
-find_path(OPENMPT_INCLUDE_DIR
-	NAMES libopenmpt.h
-	PATHS
-		${OPENMPT_PKGCONF_INCLUDE_DIRS}
-		"/usr/include/libopenmpt"
-		"/usr/local/include/libopenmpt"
-)
-
-find_library(OPENMPT_LIBRARY
-	NAMES openmpt
-	PATHS
-		${OPENMPT_PKGCONF_LIBRARY_DIRS}
-		"/usr/lib"
-		"/usr/local/lib"
-)
-
-set(OPENMPT_PROCESS_INCLUDES OPENMPT_INCLUDE_DIR)
-set(OPENMPT_PROCESS_LIBS OPENMPT_LIBRARY)
-libfind_process(OPENMPT)
-
-if(OPENMPT_FOUND AND NOT TARGET openmpt)
-	add_library(openmpt UNKNOWN IMPORTED)
-	set_target_properties(
-		openmpt
-		PROPERTIES
-		IMPORTED_LOCATION "${OPENMPT_LIBRARY}"
-		INTERFACE_INCLUDE_DIRECTORIES "${OPENMPT_INCLUDE_DIR}"
-	)
-endif()
diff --git a/cmake/Modules/Findlibgme.cmake b/cmake/Modules/Findlibgme.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6b693a7fd14234eb89c24798ea340b6a39030d33
--- /dev/null
+++ b/cmake/Modules/Findlibgme.cmake
@@ -0,0 +1,38 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(libgme_PKGCONF gme libgme)
+
+find_path(libgme_INCLUDE_DIR
+	NAMES gme.h
+	PATHS
+		${libgme_PKGCONF_INCLUDE_DIRS}
+		"/usr/include"
+		"/usr/local/include"
+	PATH_SUFFIXES
+		gme
+)
+
+find_library(libgme_LIBRARY
+	NAMES gme
+	PATHS
+		${libgme_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(libgme
+    REQUIRED_VARS libgme_LIBRARY libgme_INCLUDE_DIR)
+
+if(libgme_FOUND AND NOT TARGET gme)
+	add_library(gme UNKNOWN IMPORTED)
+	set_target_properties(
+		gme
+		PROPERTIES
+		IMPORTED_LOCATION "${libgme_LIBRARY}"
+		INTERFACE_INCLUDE_DIRECTORIES "${libgme_INCLUDE_DIR}"
+	)
+	add_library(gme::gme ALIAS gme)
+endif()
+
+mark_as_advanced(libgme_LIBRARY libgme_INCLUDE_DIR)
diff --git a/cmake/Modules/Findlibopenmpt.cmake b/cmake/Modules/Findlibopenmpt.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..d7de22134831c1e0edc8b3b6e62ed42abd69287f
--- /dev/null
+++ b/cmake/Modules/Findlibopenmpt.cmake
@@ -0,0 +1,37 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(libopenmpt_PKGCONF openmpt)
+
+find_path(libopenmpt_INCLUDE_DIR
+	NAMES libopenmpt.h
+	PATHS
+		${libopenmpt_PKGCONF_INCLUDE_DIRS}
+		"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/libopenmpt"
+		"/usr/include/libopenmpt"
+		"/usr/local/include/libopenmpt"
+)
+
+find_library(libopenmpt_LIBRARY
+	NAMES openmpt
+	PATHS
+		${libopenmpt_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(libopenmpt
+    REQUIRED_VARS libopenmpt_LIBRARY libopenmpt_INCLUDE_DIR)
+
+if(libopenmpt_FOUND AND NOT TARGET openmpt)
+	add_library(openmpt UNKNOWN IMPORTED)
+	set_target_properties(
+		openmpt
+		PROPERTIES
+		IMPORTED_LOCATION "${libopenmpt_LIBRARY}"
+		INTERFACE_INCLUDE_DIRECTORIES "${libopenmpt_INCLUDE_DIR}"
+	)
+	add_library(libopenmpt::libopenmpt ALIAS openmpt)
+endif()
+
+mark_as_advanced(libopenmpt_LIBRARY libopenmpt_INCLUDE_DIR)
diff --git a/cmake/Modules/Findminiupnpc.cmake b/cmake/Modules/Findminiupnpc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f4931ad832eb856583be1c12daaf4d9883847ed3
--- /dev/null
+++ b/cmake/Modules/Findminiupnpc.cmake
@@ -0,0 +1,39 @@
+include(LibFindMacros)
+
+libfind_pkg_check_modules(libminiupnpc_PKGCONF miniupnpc libminiupnpc)
+
+find_path(libminiupnpc_INCLUDE_DIR
+	NAMES miniupnpc.h
+	PATHS
+		${libminiupnpc_PKGCONF_INCLUDE_DIRS}
+		"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include"
+		"/usr/include"
+		"/usr/local/include"
+	PATH_SUFFIXES
+		miniupnpc
+)
+
+find_library(libminiupnpc_LIBRARY
+	NAMES miniupnpc
+	PATHS
+		${libminiupnpc_PKGCONF_LIBRARY_DIRS}
+		"/usr/lib"
+		"/usr/local/lib"
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(miniupnpc
+    REQUIRED_VARS libminiupnpc_LIBRARY libminiupnpc_INCLUDE_DIR)
+
+if(miniupnpc_FOUND AND NOT TARGET miniupnpc)
+	add_library(miniupnpc UNKNOWN IMPORTED)
+	set_target_properties(
+		miniupnpc
+		PROPERTIES
+		IMPORTED_LOCATION "${libminiupnpc_LIBRARY}"
+		INTERFACE_INCLUDE_DIRECTORIES "${libminiupnpc_INCLUDE_DIR}"
+	)
+	add_library(miniupnpc::miniupnpc ALIAS miniupnpc)
+endif()
+
+mark_as_advanced(libminiupnpc_LIBRARY libminiupnpc_INCLUDE_DIR)
diff --git a/cmake/PatchFile.cmake b/cmake/PatchFile.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f80da3434d764fdbc1eb1f0219c38204517ee19a
--- /dev/null
+++ b/cmake/PatchFile.cmake
@@ -0,0 +1,30 @@
+# use GNU Patch from any platform
+
+if(WIN32)
+  # prioritize Git Patch on Windows as other Patches may be very old and incompatible.
+  find_package(Git)
+  if(Git_FOUND)
+    get_filename_component(GIT_DIR ${GIT_EXECUTABLE} DIRECTORY)
+    get_filename_component(GIT_DIR ${GIT_DIR} DIRECTORY)
+  endif()
+endif()
+
+find_program(PATCH
+NAMES patch
+HINTS ${GIT_DIR}
+PATH_SUFFIXES usr/bin
+)
+
+if(NOT PATCH)
+  message(FATAL_ERROR "Did not find GNU Patch")
+endif()
+
+execute_process(COMMAND ${PATCH} ${in_file} --input=${patch_file} --output=${out_file} --ignore-whitespace
+TIMEOUT 15
+COMMAND_ECHO STDOUT
+RESULT_VARIABLE ret
+)
+
+if(NOT ret EQUAL 0)
+  message(FATAL_ERROR "Failed to apply patch ${patch_file} to ${in_file} with ${PATCH}")
+endif()
\ No newline at end of file
diff --git a/cmake/Toolchains/mingw-w64-i686.cmake b/cmake/Toolchains/mingw-w64-i686.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6b327291d79d905e7fd97e99196e8b0809fa8d06
--- /dev/null
+++ b/cmake/Toolchains/mingw-w64-i686.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(TOOLCHAIN_PREFIX i686-w64-mingw32)
+
+# cross compilers to use for C, C++ and Fortran
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
+set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
+set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
+
+# target environment on the build host system
+set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
+
+# modify default behavior of FIND_XXX() commands
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/cmake/Toolchains/mingw-w64-x86_64.cmake b/cmake/Toolchains/mingw-w64-x86_64.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..2f22e13d8a5dc80e869c5ca2f0089e5d9917ff7d
--- /dev/null
+++ b/cmake/Toolchains/mingw-w64-x86_64.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
+
+# cross compilers to use for C, C++ and Fortran
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
+set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
+set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
+
+# target environment on the build host system
+set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
+
+# modify default behavior of FIND_XXX() commands
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/doc/specs/udmf_srb2.txt b/doc/specs/udmf_srb2.txt
index c758d7e40f13d466afcfc689c679845fec71b906..d6d71a0d5f7217482422799a4e521714e604b204 100644
--- a/doc/specs/udmf_srb2.txt
+++ b/doc/specs/udmf_srb2.txt
@@ -126,7 +126,7 @@ Sonic Robo Blast 2 defines the following standardized fields:
       texturebottom = <string>; // Lower texture. Default = "-".
       texturemiddle = <string>; // Middle texture. Default = "-".
 
-      repeatcnt = <string>; // Number of middle texture repetitions. Default = 0
+      repeatcnt = <integer>; // Number of middle texture repetitions. Default = 0.
 
       sector = <integer>; // Sector index. No valid default.
 
@@ -228,6 +228,8 @@ Sonic Robo Blast 2 defines the following standardized fields:
       ropehang           = <bool>;     // Sector is a rope hang. Must be applied to a 3D floor.
       jumpflip           = <bool>;     // Sector flips the gravity of players who jump from it.
       gravityoverride    = <bool>;     // Reverse gravity effect is only applied when an object is in the sector.
+      nophysics_floor    = <bool>;     // Disables floor slope physics if created through a plane equation.
+      nophysics_ceiling  = <bool>;     // Disables ceiling slope physics if created through a plane equation.
 
       friction            = <float>;   // Sector's friction factor.
       gravity             = <float>;   // Sector's gravity. Default is 1.0.
diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg
index aee7a70e4e0a4b806d8c0a055d77f06fce476ea6..90c85cdea40827970a7b44222e9a2f6a5e2668f6 100644
--- a/extras/conf/udb/Includes/SRB222_common.cfg
+++ b/extras/conf/udb/Includes/SRB222_common.cfg
@@ -39,6 +39,7 @@ common
 	defaulttexturescale = 1.0f;
 	defaultflatscale = 1.0f;
 	scaledtextureoffsets = true;
+	scaledflatoffsets = true;
 
 	// Colormap/fade related options
 	maxcolormapalpha = 25;
diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index e297f473fd46d2848f3835765988bb913147e84f..fc505fb6025b02782d1a309b247f569a63dd96fd 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -7,13 +7,11 @@ udmf
 		0
 		{
 			title = "None";
-			prefix = "(0)";
 		}
 		
 		6
 		{
 			title = "Sector Set Portal";
-			prefix = "(6)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -52,7 +50,6 @@ udmf
 		7
 		{
 			title = "Sector Flat Alignment";
-			prefix = "(7)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -70,7 +67,6 @@ udmf
 		10
 		{
 			title = "Culling Plane";
-			prefix = "(10)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -91,20 +87,17 @@ udmf
 		40
 		{
 			title = "Visual Portal Between Tagged Linedefs";
-			prefix = "(40)";
 		}
 
 		41
 		{
 			title = "Horizon Effect";
 			id = "srb2_horizonline";
-			prefix = "(41)";
 		}
 
 		63
 		{
 			title = "Fake Floor/Ceiling Planes";
-			prefix = "(63)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -120,7 +113,6 @@ udmf
 		2
 		{
 			title = "Custom Exit";
-			prefix = "(2)";
 			arg0
 			{
 				title = "Next map";
@@ -144,7 +136,6 @@ udmf
 		3
 		{
 			title = "Zoom Tube Parameters";
-			prefix = "(3)";
 			arg0
 			{
 				title = "Speed";
@@ -166,7 +157,6 @@ udmf
 		4
 		{
 			title = "Speed Pad Parameters";
-			prefix = "(4)";
 			arg0
 			{
 				title = "Speed";
@@ -193,7 +183,6 @@ udmf
 		8
 		{
 			title = "Set Camera Collision Planes";
-			prefix = "(8)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -204,7 +193,6 @@ udmf
 		11
 		{
 			title = "Rope Hang Parameters";
-			prefix = "(11)";
 			arg0
 			{
 				title = "Speed";
@@ -226,7 +214,6 @@ udmf
 		14
 		{
 			title = "Bustable Block Parameters";
-			prefix = "(14)";
 			arg0
 			{
 				title = "Debris spacing";
@@ -252,13 +239,11 @@ udmf
 		15
 		{
 			title = "Fan Particle Generator Heights";
-			prefix = "(15)";
 		}
 
 		16
 		{
 			title = "Minecart Parameters";
-			prefix = "(16)";
 			arg0
 			{
 				title = "Order";
@@ -268,7 +253,6 @@ udmf
 		64
 		{
 			title = "Continuously Appearing/Disappearing FOF";
-			prefix = "(64)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -307,7 +291,6 @@ udmf
 		20
 		{
 			title = "PolyObject First Line";
-			prefix = "(20)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -348,7 +331,6 @@ udmf
 		30
 		{
 			title = "Waving PolyObject Flag";
-			prefix = "(30)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -369,7 +351,6 @@ udmf
 		31
 		{
 			title = "Move PolyObject by Front Sector Displacement";
-			prefix = "(31)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -385,7 +366,6 @@ udmf
 		32
 		{
 			title = "Rotate PolyObject by Front Sector Displacement";
-			prefix = "(32)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -421,7 +401,6 @@ udmf
 		52
 		{
 			title = "Continuously Falling Sector";
-			prefix = "(52)";
 			arg0
 			{
 				title = "Speed";
@@ -442,7 +421,6 @@ udmf
 		53
 		{
 			title = "Continuous Plane Mover (Slowdown)";
-			prefix = "(53)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -477,7 +455,6 @@ udmf
 		56
 		{
 			title = "Continuous Plane Mover (Constant)";
-			prefix = "(56)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -512,7 +489,6 @@ udmf
 		60
 		{
 			title = "Activate Moving Platform";
-			prefix = "(60)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -542,7 +518,6 @@ udmf
 		61
 		{
 			title = "Ceiling Crusher";
-			prefix = "(61)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -573,7 +548,6 @@ udmf
 		66
 		{
 			title = "Move Planes by Front Sector Displacement";
-			prefix = "(66)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -600,7 +574,6 @@ udmf
 		70
 		{
 			title = "Add Raise Thinker";
-			prefix = "(70)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -626,7 +599,6 @@ udmf
 		71
 		{
 			title = "Add Air Bobbing Thinker";
-			prefix = "(71)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -652,7 +624,6 @@ udmf
 		72
 		{
 			title = "Add Thwomp Thinker";
-			prefix = "(72)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -679,7 +650,6 @@ udmf
 		73
 		{
 			title = "Add Laser Thinker";
-			prefix = "(73)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -696,7 +666,6 @@ udmf
 		74
 		{
 			title = "Make FOF Bustable";
-			prefix = "(74)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -735,7 +704,6 @@ udmf
 		75
 		{
 			title = "Make FOF Quicksand";
-			prefix = "(75)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -755,7 +723,6 @@ udmf
 		76
 		{
 			title = "Make FOF Bouncy";
-			prefix = "(76)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -775,7 +742,6 @@ udmf
 		100
 		{
 			title = "Solid";
-			prefix = "(100)";
 			id = "srb2_fofsolid";
 			arg0
 			{
@@ -819,7 +785,6 @@ udmf
 		120
 		{
 			title = "Water";
-			prefix = "(120)";
 			id = "srb2_fofwater";
 			arg0
 			{
@@ -857,7 +822,6 @@ udmf
 		150
 		{
 			title = "Air Bobbing";
-			prefix = "(150)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -884,7 +848,6 @@ udmf
 		160
 		{
 			title = "Water Bobbing";
-			prefix = "(160)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -896,7 +859,6 @@ udmf
 		170
 		{
 			title = "Crumbling";
-			prefix = "(170)";
 			id = "srb2_fofcrumbling";
 			arg0
 			{
@@ -939,7 +901,6 @@ udmf
 		190
 		{
 			title = "Rising";
-			prefix = "(190)";
 			id = "srb2_fofsolid";
 			arg0
 			{
@@ -998,7 +959,6 @@ udmf
 		200
 		{
 			title = "Light Block";
-			prefix = "(200)";
 			id = "srb2_foflight";
 			arg0
 			{
@@ -1016,7 +976,6 @@ udmf
 		202
 		{
 			title = "Fog Block";
-			prefix = "(202)";
 			id = "srb2_foffog";
 			arg0
 			{
@@ -1028,7 +987,6 @@ udmf
 		220
 		{
 			title = "Intangible";
-			prefix = "(220)";
 			id = "srb2_fofintangible";
 			arg0
 			{
@@ -1066,7 +1024,6 @@ udmf
 		223
 		{
 			title = "Intangible, Invisible";
-			prefix = "(223)";
 			id = "srb2_fofintangibleinvisible";
 			arg0
 			{
@@ -1078,7 +1035,6 @@ udmf
 		250
 		{
 			title = "Mario Block";
-			prefix = "(250)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1100,7 +1056,6 @@ udmf
 		251
 		{
 			title = "Thwomp Block";
-			prefix = "(251)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1128,7 +1083,6 @@ udmf
 		254
 		{
 			title = "Bustable Block";
-			prefix = "(254)";
 			id = "srb2_fofbustable";
 			arg0
 			{
@@ -1181,7 +1135,6 @@ udmf
 		257
 		{
 			title = "Quicksand";
-			prefix = "(257)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1208,7 +1161,6 @@ udmf
 		258
 		{
 			title = "Laser";
-			prefix = "(258)";
 			id = "srb2_foflaser";
 			arg0
 			{
@@ -1242,7 +1194,6 @@ udmf
 		259
 		{
 			title = "Custom";
-			prefix = "(259)";
 			id = "srb2_fofcustom";
 			arg0
 			{
@@ -1307,7 +1258,6 @@ udmf
 		300
 		{
 			title = "Basic";
-			prefix = "(300)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1319,7 +1269,6 @@ udmf
 		303
 		{
 			title = "Ring Count";
-			prefix = "(303)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1347,7 +1296,6 @@ udmf
 		305
 		{
 			title = "Character Ability";
-			prefix = "(305)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1383,7 +1331,6 @@ udmf
 		308
 		{
 			title = "Gametype";
-			prefix = "(308)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1441,7 +1388,6 @@ udmf
 		309
 		{
 			title = "CTF Team";
-			prefix = "(309)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1459,7 +1405,6 @@ udmf
 		313
 		{
 			title = "No More Enemies";
-			prefix = "(313)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1470,7 +1415,6 @@ udmf
 		314
 		{
 			title = "Number of Pushables";
-			prefix = "(314)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1492,7 +1436,6 @@ udmf
 		317
 		{
 			title = "Condition Set Trigger";
-			prefix = "(317)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1508,7 +1451,6 @@ udmf
 		319
 		{
 			title = "Unlockable";
-			prefix = "(319)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1524,7 +1466,6 @@ udmf
 		321
 		{
 			title = "Trigger After X Calls";
-			prefix = "(321)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1550,7 +1491,6 @@ udmf
 		323
 		{
 			title = "NiGHTSerize";
-			prefix = "(323)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1617,7 +1557,6 @@ udmf
 		325
 		{
 			title = "De-NiGHTSerize";
-			prefix = "(325)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1680,7 +1619,6 @@ udmf
 		327
 		{
 			title = "NiGHTS Lap";
-			prefix = "(327)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1732,7 +1670,6 @@ udmf
 		329
 		{
 			title = "Ideya Capture Touch";
-			prefix = "(329)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1800,7 +1737,6 @@ udmf
 		331
 		{
 			title = "Player Skin";
-			prefix = "(331)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1823,7 +1759,6 @@ udmf
 		334
 		{
 			title = "Object Dye";
-			prefix = "(334)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1846,7 +1781,6 @@ udmf
 		337
 		{
 			title = "Emerald Check";
-			prefix = "(337)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1879,7 +1813,6 @@ udmf
 		340
 		{
 			title = "NiGHTS Mare";
-			prefix = "(340)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1901,7 +1834,6 @@ udmf
 		343
 		{
 			title = "Gravity Check";
-			prefix = "(343)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1924,7 +1856,6 @@ udmf
 		399
 		{
 			title = "Level Load";
-			prefix = "(399)";
 		}
 	}
 
@@ -1935,7 +1866,6 @@ udmf
 		400
 		{
 			title = "Set Tagged Sector's Heights/Textures";
-			prefix = "(400)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1958,7 +1888,6 @@ udmf
 		402
 		{
 			title = "Copy Light Level to Tagged Sectors";
-			prefix = "(402)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1980,7 +1909,6 @@ udmf
 		408
 		{
 			title = "Set Tagged Sector's Flats";
-			prefix = "(408)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1997,7 +1925,6 @@ udmf
 		409
 		{
 			title = "Change Tagged Sector's Tag";
-			prefix = "(409)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2025,7 +1952,6 @@ udmf
 		410
 		{
 			title = "Change Front Sector's Tag";
-			prefix = "(410)";
 			arg0
 			{
 				title = "Tag";
@@ -2048,7 +1974,6 @@ udmf
 		416
 		{
 			title = "Start Adjustable Flickering Light";
-			prefix = "(416)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2077,7 +2002,6 @@ udmf
 		417
 		{
 			title = "Start Adjustable Pulsating Light";
-			prefix = "(417)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2106,7 +2030,6 @@ udmf
 		418
 		{
 			title = "Start Adjustable Blinking Light";
-			prefix = "(418)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2143,7 +2066,6 @@ udmf
 		420
 		{
 			title = "Fade Light Level";
-			prefix = "(420)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2173,7 +2095,6 @@ udmf
 		421
 		{
 			title = "Stop Lighting Effect";
-			prefix = "(421)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2184,7 +2105,6 @@ udmf
 		435
 		{
 			title = "Change Plane Scroller Direction";
-			prefix = "(435)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2200,7 +2120,6 @@ udmf
 		467
 		{
 			title = "Set Tagged Sector's Light Level";
-			prefix = "(467)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2232,7 +2151,6 @@ udmf
 		469
 		{
 			title = "Change Tagged Sector's Gravity";
-			prefix = "(469)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2284,7 +2202,6 @@ udmf
 		403
 		{
 			title = "Move Tagged Sector's Planes";
-			prefix = "(403)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2317,7 +2234,6 @@ udmf
 		405
 		{
 			title = "Move Planes by Set Distance";
-			prefix = "(405)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2349,7 +2265,6 @@ udmf
 		411
 		{
 			title = "Stop Plane Movement";
-			prefix = "(411)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2360,7 +2275,6 @@ udmf
 		428
 		{
 			title = "Start Platform Movement";
-			prefix = "(428)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2394,7 +2308,6 @@ udmf
 		429
 		{
 			title = "Crush Planes Once";
-			prefix = "(429)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2426,7 +2339,6 @@ udmf
 		412
 		{
 			title = "Teleporter";
-			prefix = "(412)";
 			arg0
 			{
 				title = "Destination thing tag";
@@ -2461,7 +2373,6 @@ udmf
 		425
 		{
 			title = "Change Object State";
-			prefix = "(425)";
 			stringarg0
 			{
 				title = "State";
@@ -2472,7 +2383,6 @@ udmf
 		426
 		{
 			title = "Stop Object";
-			prefix = "(426)";
 			arg0
 			{
 				title = "Move to center?";
@@ -2484,7 +2394,6 @@ udmf
 		427
 		{
 			title = "Award Score";
-			prefix = "(427)";
 			arg0
 			{
 				title = "Score";
@@ -2494,7 +2403,6 @@ udmf
 		432
 		{
 			title = "Enable/Disable 2D Mode";
-			prefix = "(432)";
 			arg0
 			{
 				title = "Mode";
@@ -2510,7 +2418,6 @@ udmf
 		433
 		{
 			title = "Enable/Disable Gravity Flip";
-			prefix = "(433)";
 			arg0
 			{
 				title = "Set gravity";
@@ -2546,7 +2453,6 @@ udmf
 		434
 		{
 			title = "Award Power-Up";
-			prefix = "(434)";
 			stringarg0
 			{
 				title = "Power";
@@ -2562,7 +2468,6 @@ udmf
 		437
 		{
 			title = "Disable Player Control";
-			prefix = "(437)";
 			arg0
 			{
 				title = "Time";
@@ -2578,7 +2483,6 @@ udmf
 		438
 		{
 			title = "Change Object Size";
-			prefix = "(438)";
 			arg0
 			{
 				title = "Size (%)";
@@ -2589,7 +2493,6 @@ udmf
 		442
 		{
 			title = "Change Object Type State";
-			prefix = "(442)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2620,7 +2523,6 @@ udmf
 		457
 		{
 			title = "Track Object's Angle";
-			prefix = "(457)";
 			arg0
 			{
 				title = "Anchor tag";
@@ -2651,13 +2553,11 @@ udmf
 		458
 		{
 			title = "Stop Tracking Object's Angle";
-			prefix = "(458)";
 		}
 
 		460
 		{
 			title = "Award Rings";
-			prefix = "(460)";
 			arg0
 			{
 				title = "Rings";
@@ -2671,7 +2571,6 @@ udmf
 		461
 		{
 			title = "Spawn Object";
-			prefix = "(461)";
 			arg0
 			{
 				title = "X position";
@@ -2717,13 +2616,11 @@ udmf
 		462
 		{
 			title = "Stop Timer/Exit Stage in Record Attack";
-			prefix = "(462)";
 		}
 
 		463
 		{
 			title = "Dye Object";
-			prefix = "(463)";
 			stringarg0
 			{
 				title = "Skin color";
@@ -2734,7 +2631,6 @@ udmf
 		464
 		{
 			title = "Trigger Egg Capsule";
-			prefix = "(464)";
 			arg0
 			{
 				title = "Egg Capsule tag";
@@ -2751,7 +2647,6 @@ udmf
 		466
 		{
 			title = "Set Level Failure State";
-			prefix = "(466)";
 			arg0
 			{
 				title = "State";
@@ -2772,7 +2667,6 @@ udmf
 		413
 		{
 			title = "Change Music";
-			prefix = "(413)";
 			arg0
 			{
 				title = "Flags";
@@ -2823,7 +2717,6 @@ udmf
 		414
 		{
 			title = "Play Sound Effect";
-			prefix = "(414)";
 			arg0
 			{
 				title = "Source";
@@ -2863,7 +2756,6 @@ udmf
 		415
 		{
 			title = "Run Script";
-			prefix = "(415)";
 			stringarg0
 			{
 				title = "Lump name";
@@ -2874,7 +2766,6 @@ udmf
 		422
 		{
 			title = "Switch to Cut-Away View";
-			prefix = "(422)";
 			arg0
 			{
 				title = "Viewpoint tag";
@@ -2889,7 +2780,6 @@ udmf
 		423
 		{
 			title = "Change Sky";
-			prefix = "(423)";
 			arg0
 			{
 				title = "Sky number";
@@ -2905,7 +2795,6 @@ udmf
 		424
 		{
 			title = "Change Weather";
-			prefix = "(424)";
 			arg0
 			{
 				title = "Weather";
@@ -2932,7 +2821,6 @@ udmf
 		436
 		{
 			title = "Shatter FOF";
-			prefix = "(436)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2948,7 +2836,6 @@ udmf
 		439
 		{
 			title = "Change Tagged Linedef's Textures";
-			prefix = "(439)";
 			arg0
 			{
 				title = "Target linedef tag";
@@ -2977,13 +2864,11 @@ udmf
 		440
 		{
 			title = "Start Metal Sonic Race";
-			prefix = "(440)";
 		}
 
 		441
 		{
 			title = "Condition Set Trigger";
-			prefix = "(441)";
 			arg0
 			{
 				title = "Trigger number";
@@ -2993,7 +2878,6 @@ udmf
 		443
 		{
 			title = "Call Lua Function";
-			prefix = "(443)";
 			stringarg0
 			{
 				title = "Function name";
@@ -3004,7 +2888,6 @@ udmf
 		444
 		{
 			title = "Earthquake";
-			prefix = "(444)";
 			arg0
 			{
 				title = "Duration";
@@ -3018,7 +2901,6 @@ udmf
 		445
 		{
 			title = "Make FOF Disappear/Reappear";
-			prefix = "(445)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3044,7 +2926,6 @@ udmf
 		446
 		{
 			title = "Make FOF Crumble";
-			prefix = "(446)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3072,7 +2953,6 @@ udmf
 		447
 		{
 			title = "Change Tagged Sector's Colormap";
-			prefix = "(447)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3108,7 +2988,6 @@ udmf
 		448
 		{
 			title = "Change Skybox";
-			prefix = "(448)";
 			arg0
 			{
 				title = "Viewpoint thing tag";
@@ -3139,7 +3018,6 @@ udmf
 		449
 		{
 			title = "Enable Bosses with Parameter";
-			prefix = "(449)";
 			arg0
 			{
 				title = "Boss ID";
@@ -3159,7 +3037,6 @@ udmf
 		450
 		{
 			title = "Execute Linedef Executor (specific tag)";
-			prefix = "(450)";
 			arg0
 			{
 				title = "Trigger linedef tag";
@@ -3170,7 +3047,6 @@ udmf
 		451
 		{
 			title = "Execute Linedef Executor (random tag in range)";
-			prefix = "(451)";
 			arg0
 			{
 				title = "Start of tag range";
@@ -3186,7 +3062,6 @@ udmf
 		452
 		{
 			title = "Set FOF Translucency";
-			prefix = "(452)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3217,7 +3092,6 @@ udmf
 		453
 		{
 			title = "Fade FOF";
-			prefix = "(453)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3260,7 +3134,6 @@ udmf
 		454
 		{
 			title = "Stop Fading FOF";
-			prefix = "(454)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3282,7 +3155,6 @@ udmf
 		455
 		{
 			title = "Fade Tagged Sector's Colormap";
-			prefix = "(455)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3324,7 +3196,6 @@ udmf
 		456
 		{
 			title = "Stop Fading Tagged Sector's Colormap";
-			prefix = "(456)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3335,7 +3206,6 @@ udmf
 		459
 		{
 			title = "Control Text Prompt";
-			prefix = "(459)";
 			arg0
 			{
 				title = "Prompt number";
@@ -3371,7 +3241,6 @@ udmf
 		465
 		{
 			title = "Set Linedef Executor Delay";
-			prefix = "(465)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3392,7 +3261,6 @@ udmf
 		468
 		{
 			title = "Change Linedef Argument";
-			prefix = "(468)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3422,7 +3290,6 @@ udmf
 		480
 		{
 			title = "PolyObject Door Slide";
-			prefix = "(480)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3446,7 +3313,6 @@ udmf
 		481
 		{
 			title = "PolyObject Door Swing";
-			prefix = "(481)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3471,7 +3337,6 @@ udmf
 		482
 		{
 			title = "Move PolyObject";
-			prefix = "(482)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3497,7 +3362,6 @@ udmf
 		484
 		{
 			title = "Rotate PolyObject";
-			prefix = "(484)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3531,7 +3395,6 @@ udmf
 		488
 		{
 			title = "Move PolyObject by Waypoints";
-			prefix = "(488)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3573,7 +3436,6 @@ udmf
 		489
 		{
 			title = "Set PolyObject Visibility/Tangibility";
-			prefix = "(489)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3606,7 +3468,6 @@ udmf
 		491
 		{
 			title = "Set PolyObject Translucency";
-			prefix = "(491)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3628,7 +3489,6 @@ udmf
 		492
 		{
 			title = "Fade PolyObject Translucency";
-			prefix = "(492)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3666,7 +3526,6 @@ udmf
 		500
 		{
 			title = "Scroll Wall";
-			prefix = "(500)";
 			arg0
 			{
 				title = "Side";
@@ -3686,7 +3545,6 @@ udmf
 		502
 		{
 			title = "Scroll Tagged Walls";
-			prefix = "(502)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3717,7 +3575,6 @@ udmf
 		510
 		{
 			title = "Scroll Planes";
-			prefix = "(510)";
 			arg0
 			{
 				title = "Sector tag";
@@ -3755,7 +3612,6 @@ udmf
 		541
 		{
 			title = "Wind/Current";
-			prefix = "(541)";
 			arg0
 			{
 				title = "Sector tag";
@@ -3800,7 +3656,6 @@ udmf
 		600
 		{
 			title = "Copy Light Level to Tagged Sector's Planes";
-			prefix = "(600)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3817,7 +3672,6 @@ udmf
 		602
 		{
 			title = "Adjustable Pulsating Light";
-			prefix = "(602)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3846,7 +3700,6 @@ udmf
 		603
 		{
 			title = "Adjustable Flickering Light";
-			prefix = "(603)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3875,7 +3728,6 @@ udmf
 		604
 		{
 			title = "Adjustable Blinking Light";
-			prefix = "(604)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3912,7 +3764,6 @@ udmf
 		606
 		{
 			title = "Copy Colormap";
-			prefix = "(606)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3933,7 +3784,6 @@ udmf
 		700
 		{
 			title = "Create Sector-Based Slope";
-			prefix = "(700)";
 			id = "plane_align";
 			arg0
 			{
@@ -3963,7 +3813,6 @@ udmf
 		704
 		{
 			title = "Create Vertex-Based Slope";
-			prefix = "(704)";
 			id = "srb2_vertexslope";
 			arg0
 			{
@@ -4007,7 +3856,6 @@ udmf
 		720
 		{
 			title = "Copy Slope";
-			prefix = "(720)";
 			id = "plane_copy";
 			arg0
 			{
@@ -4046,7 +3894,6 @@ udmf
 		799
 		{
 			title = "Set Tagged Dynamic Slope Vertex to Front Sector Height";
-			prefix = "(799)";
 			arg0
 			{
 				title = "Apply height";
diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index 405d043c140995b4ed840528878cc6eda7c53346..37b01d7dd56eadaeb1eb3ae4759fb74efc79e61f 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -78,6 +78,8 @@ sectorflags
 	ropehang = "Rope Hang";
 	jumpflip = "Flip Gravity on Jump";
 	gravityoverride = "Make Reverse Gravity Temporary";
+	nophysics_floor = "Disable Floor Slope Physics";
+	nophysics_ceiling = "Disable Ceiling Slope Physics";
 	flipspecial_nofloor = "No Trigger on Floor Touch";
 	flipspecial_ceiling = "Trigger on Ceiling Touch";
 	triggerspecial_touch = "Trigger on Edge Touch";
@@ -114,6 +116,8 @@ sectorflagscategories
 	ropehang = "special";
 	jumpflip = "special";
 	gravityoverride = "special";
+	nophysics_floor = "special";
+	nophysics_ceiling = "special";
 	flipspecial_nofloor = "trigger";
 	flipspecial_ceiling = "trigger";
 	triggerspecial_touch = "trigger";
@@ -586,6 +590,12 @@ universalfields
 			type = 3;
 			default = false;
 		}
+
+		triggertag
+		{
+			type = 0;
+			default = 0;
+		}
 	}
 }
 
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index 990f8dca9f505b57f1797c49ed0d8ae003d18d5d..c028f9439c493d156e1ded87f7a116cc4b14d9d7 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -3938,6 +3938,7 @@ udmf
 			width = 30;
 			height = 32;
 			color = 17;
+			hangs = 1;
 			arg0
 			{
 				title = "Initial delay";
diff --git a/libs/miniupnpc/include/igd_desc_parse.h b/libs/miniupnpc/include/miniupnpc/igd_desc_parse.h
similarity index 100%
rename from libs/miniupnpc/include/igd_desc_parse.h
rename to libs/miniupnpc/include/miniupnpc/igd_desc_parse.h
diff --git a/libs/miniupnpc/include/miniupnpc.h b/libs/miniupnpc/include/miniupnpc/miniupnpc.h
similarity index 100%
rename from libs/miniupnpc/include/miniupnpc.h
rename to libs/miniupnpc/include/miniupnpc/miniupnpc.h
diff --git a/libs/miniupnpc/include/miniupnpc_declspec.h b/libs/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
similarity index 100%
rename from libs/miniupnpc/include/miniupnpc_declspec.h
rename to libs/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
diff --git a/libs/miniupnpc/include/miniupnpctypes.h b/libs/miniupnpc/include/miniupnpc/miniupnpctypes.h
similarity index 100%
rename from libs/miniupnpc/include/miniupnpctypes.h
rename to libs/miniupnpc/include/miniupnpc/miniupnpctypes.h
diff --git a/libs/miniupnpc/include/miniwget.h b/libs/miniupnpc/include/miniupnpc/miniwget.h
similarity index 100%
rename from libs/miniupnpc/include/miniwget.h
rename to libs/miniupnpc/include/miniupnpc/miniwget.h
diff --git a/libs/miniupnpc/include/portlistingparse.h b/libs/miniupnpc/include/miniupnpc/portlistingparse.h
similarity index 100%
rename from libs/miniupnpc/include/portlistingparse.h
rename to libs/miniupnpc/include/miniupnpc/portlistingparse.h
diff --git a/libs/miniupnpc/include/upnpcommands.h b/libs/miniupnpc/include/miniupnpc/upnpcommands.h
similarity index 100%
rename from libs/miniupnpc/include/upnpcommands.h
rename to libs/miniupnpc/include/miniupnpc/upnpcommands.h
diff --git a/libs/miniupnpc/include/upnpdev.h b/libs/miniupnpc/include/miniupnpc/upnpdev.h
similarity index 100%
rename from libs/miniupnpc/include/upnpdev.h
rename to libs/miniupnpc/include/miniupnpc/upnpdev.h
diff --git a/libs/miniupnpc/include/upnperrors.h b/libs/miniupnpc/include/miniupnpc/upnperrors.h
similarity index 100%
rename from libs/miniupnpc/include/upnperrors.h
rename to libs/miniupnpc/include/miniupnpc/upnperrors.h
diff --git a/libs/miniupnpc/include/upnpreplyparse.h b/libs/miniupnpc/include/miniupnpc/upnpreplyparse.h
similarity index 100%
rename from libs/miniupnpc/include/upnpreplyparse.h
rename to libs/miniupnpc/include/miniupnpc/upnpreplyparse.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 486f4e913057af02c22a6acd6c554bd7b76801b3..20caecf7bd6a65a20631318799016da319d3f13d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -134,10 +134,13 @@ add_dependencies(SRB2SDL2 _SRB2_reconf)
 
 if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
 	target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase")
-	if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}")
+	if("${SRB2_CONFIG_STATIC_STDLIB}")
 		# On MinGW with internal libraries, link the standard library statically
 		target_link_options(SRB2SDL2 PRIVATE "-static")
 	endif()
+	if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+		target_link_options(SRB2SDL2 PRIVATE "-Wl,--large-address-aware")
+	endif()
 endif()
 
 target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
@@ -182,12 +185,7 @@ if("${SRB2_CONFIG_USE_GME}")
 	endif()
 endif()
 
-target_link_libraries(SRB2SDL2 PRIVATE openmpt)
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_OPENMPT)
-
-target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB PNG::PNG CURL::libcurl)
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_ZLIB -DHAVE_PNG -DHAVE_CURL -D_LARGEFILE64_SOURCE)
-target_sources(SRB2SDL2 PRIVATE apng.c)
+target_compile_definitions(SRB2SDL2 PRIVATE -D_LARGEFILE64_SOURCE)
 
 set(SRB2_HAVE_THREADS ON)
 target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_THREADS)
@@ -403,8 +401,66 @@ if(SRB2_CONFIG_PROFILEMODE AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
 endif()
 
 add_subdirectory(sdl)
-if(SRB2_CONFIG_ENABLE_TESTS)
-	add_subdirectory(tests)
+
+if(TARGET ZLIB::ZLIB)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_ZLIB)
+	message(STATUS "Zlib Found")
+else()
+	message(STATUS "No Zlib Found")
+endif()
+
+if(TARGET PNG::PNG)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_PNG)
+	target_sources(SRB2SDL2 PRIVATE apng.c ${libapng_HEADER})
+	target_include_directories(SRB2SDL2 PRIVATE ${libapng_INCLUDE_DIRS} ${libpng_BINARY_DIR})
+	#message(STATUS "libpng inc DIRS at ${libapng_INCLUDE_DIRS}")
+	#message(STATUS "libpng bin DIRS at ${libpng_BINARY_DIR}")
+	#message(STATUS "png.h at ${libapng_HEADER}")
+	message(STATUS "libpng Found")
+else()
+	message(STATUS "No libpng Found")
+endif()
+
+if(TARGET PNG::PNG AND TARGET ZLIB::ZLIB)
+#libpng links zlib too?
+target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG)
+endif()
+
+if(NOT TARGET PNG::PNG AND TARGET ZLIB::ZLIB)
+#got no libpng? we need zlib
+target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB)
+endif()
+
+if(TARGET gme::gme)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_GME)
+	target_link_libraries(SRB2SDL2 PRIVATE gme::gme)
+	message(STATUS "libgme Found")
+else()
+	message(STATUS "No libgme Found")
+endif()
+
+if(TARGET libopenmpt::libopenmpt)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_OPENMPT)
+	target_link_libraries(SRB2SDL2 PRIVATE libopenmpt::libopenmpt)
+	message(STATUS "libopenmpt Found")
+else()
+	message(STATUS "No libopenmpt Found")
+endif()
+
+if(TARGET CURL::libcurl)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_CURL)
+	target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl)
+	message(STATUS "libcurl Found")
+else()
+	message(STATUS "No libcurl Found")
+endif()
+
+if(TARGET miniupnpc::miniupnpc)
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MINIUPNPC)
+	target_link_libraries(SRB2SDL2 PRIVATE miniupnpc::miniupnpc)
+	message(STATUS "miniupnpc Found")
+else()
+	message(STATUS "No miniupnpc Found")
 endif()
 
 # strip debug symbols into separate file when using gcc.
diff --git a/src/b_bot.c b/src/b_bot.c
index af57d65ecf6e3c24e725ed38b9533b9ab6509763..6229cb1d61893b328e667ba357fbbefe333e51f4 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -387,7 +387,8 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
 	}
 
 	// Bot AI isn't programmed in analog.
-	CV_SetValue(&cv_analog[1], false);
+	if (!dedicated)
+		CV_SetValue(&cv_analog[1], false);
 
 	// Let Lua scripts build ticcmds
 	if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)))
diff --git a/src/console.c b/src/console.c
index b12a1ab846a26546a73ddea3580c8f086a37f7db..0c3eac4f793854dad336dc641a73874cea74d510 100644
--- a/src/console.c
+++ b/src/console.c
@@ -922,8 +922,6 @@ static void CON_InputDelChar(void)
 //
 boolean CON_Responder(event_t *ev)
 {
-	static UINT8 consdown = false; // console is treated differently due to rare usage
-
 	// sequential completions a la 4dos
 	static char completioncmd[80 + sizeof("find ")] = "find ";
 	static char *completion = &completioncmd[sizeof("find ")-1];
@@ -943,32 +941,28 @@ boolean CON_Responder(event_t *ev)
 	// let go keyup events, don't eat them
 	if (ev->type != ev_keydown && ev->type != ev_text && ev->type != ev_console)
 	{
-		if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1])
-			consdown = false;
 		return false;
 	}
 
 	key = ev->key;
 
 	// check for console toggle key
-	if (ev->type != ev_console)
+	if (ev->type == ev_keydown)
 	{
 		if (modeattacking || metalrecording || marathonmode)
 			return false;
 
-		if (ev->type == ev_keydown && ((key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) && !shiftdown))
+		if ((key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) && !shiftdown)
 		{
-			if (consdown) // ignore repeat
-				return true;
+			I_SetTextInputMode(con_destlines == 0); // inverse, since this is changed next tic.
 			consoletoggle = true;
-			consdown = true;
 			return true;
 		}
 
 		// check other keys only if console prompt is active
 		if (!consoleready && key < NUMINPUTS) // metzgermeister: boundary check!!
 		{
-			if (ev->type == ev_keydown && !menuactive && bindtable[key])
+			if (!menuactive && bindtable[key])
 			{
 				COM_BufAddText(bindtable[key]);
 				COM_BufAddText("\n");
@@ -980,14 +974,14 @@ boolean CON_Responder(event_t *ev)
 		// escape key toggle off console
 		if (key == KEY_ESCAPE)
 		{
+			I_SetTextInputMode(false);
 			consoletoggle = true;
 			return true;
 		}
 	}
-
-	if (ev->type == ev_text)
+	else if (ev->type == ev_text)
 	{
-		if (!consoletoggle)
+		if (!consoletoggle && consoleready)
 			CON_InputAddChar(key);
 		return true;
 	}
@@ -1036,7 +1030,7 @@ boolean CON_Responder(event_t *ev)
 	}
 	else if (key == KEY_BACKSPACE)
 	{
-		if (ctrldown)
+		if (ctrldown && input_cur != 0)
 		{
 			input_sel = M_JumpWordReverse(inputlines[inputline], input_cur);
 			CON_InputDelSelection();
@@ -1094,7 +1088,9 @@ boolean CON_Responder(event_t *ev)
 
 		if (key == 'x' || key == 'X')
 		{
-			if (input_sel > input_cur)
+			if (input_sel == input_cur) // Don't replace the clipboard without a text selection
+				return true;
+			else if (input_sel > input_cur)
 				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
 			else
 				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
@@ -1104,7 +1100,9 @@ boolean CON_Responder(event_t *ev)
 		}
 		else if (key == 'c' || key == 'C')
 		{
-			if (input_sel > input_cur)
+			if (input_sel == input_cur) // Don't replace the clipboard without a text selection
+				return true;
+			else if (input_sel > input_cur)
 				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
 			else
 				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
@@ -1707,11 +1705,11 @@ static void CON_DrawHudlines(void)
 			}
 			if (c >= con_width)
 				break;
-			if (*p < HU_FONTSTART)
+			if (*p < FONTSTART)
 				;//charwidth = 4 * con_scalefactor;
 			else
 			{
-				//charwidth = (hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
+				//charwidth = (hu_font.chars['A'-FONTSTART]->width) * con_scalefactor;
 				V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
 			}
 		}
@@ -1730,12 +1728,12 @@ static void CON_DrawBackpic(void)
 
 	// Get the lumpnum for CONSBACK, STARTUP (Only during game startup) or fallback into MISSING.
 	if (con_startup)
-		piclump = W_CheckNumForName("STARTUP");
+		piclump = W_CheckNumForPatchName("STARTUP");
 	else
-		piclump = W_CheckNumForName("CONSBACK");
+		piclump = W_CheckNumForPatchName("CONSBACK");
 
 	if (piclump == LUMPERROR)
-		piclump = W_GetNumForName("MISSING");
+		piclump = W_GetNumForPatchName("MISSING");
 
 	// Cache the patch.
 	con_backpic = W_CachePatchNum(piclump, PU_PATCH);
diff --git a/src/d_main.c b/src/d_main.c
index c139650d1eb039a057da10d063f392f33c94fac2..2405b01365ba8c47f4e54036839e7e704b6aaa4b 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -758,9 +758,9 @@ void D_SRB2Loop(void)
 	/* Smells like a hack... Don't fade Sonic's ass into the title screen. */
 	if (gamestate != GS_TITLESCREEN)
 	{
-		gstartuplumpnum = W_CheckNumForName("STARTUP");
+		gstartuplumpnum = W_CheckNumForPatchName("STARTUP");
 		if (gstartuplumpnum == LUMPERROR)
-			gstartuplumpnum = W_GetNumForName("MISSING");
+			gstartuplumpnum = W_GetNumForPatchName("MISSING");
 		V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(gstartuplumpnum, PU_PATCH));
 	}
 
@@ -983,7 +983,7 @@ void D_StartTitle(void)
 	emeralds = 0;
 	memset(&luabanks, 0, sizeof(luabanks));
 	lastmaploaded = 0;
-	pickedchar = R_SkinAvailable(cv_defaultskin.string);
+	pickedchar = R_SkinAvailable(cv_skin.string);
 
 	// In case someone exits out at the same time they start a time attack run,
 	// reset modeattacking
@@ -1842,17 +1842,21 @@ static boolean check_top_dir(const char **path, const char *top)
 	return true;
 }
 
-static int cmp_strlen_desc(const void *a, const void *b)
+static int cmp_strlen_desc(const void *A, const void *B)
 {
-	return ((int)strlen(*(const char*const*)b) - (int)strlen(*(const char*const*)a));
+	const char *pA = A;
+	const char *pB = B;
+	size_t As = strlen(pA);
+	size_t Bs = strlen(pB);
+	return ((int)Bs - (int)As);
 }
 
 boolean D_IsPathAllowed(const char *path)
 {
-	const char *paths[] = {
+	char *paths[] = {
 		srb2home,
 		srb2path,
-		cv_addons_folder.string
+		cv_addons_folder.zstring
 	};
 
 	const size_t n_paths = sizeof paths / sizeof *paths;
diff --git a/src/d_player.h b/src/d_player.h
index 098b4485ca5e602328a4b03b5e0c6719fe6d154b..95d2f609dab322189fcb3892d7beace6d0fd45dc 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -373,6 +373,16 @@ typedef enum
 	AI_SPINFOLLOW
 } aistatetype_t;
 
+// NiGHTS text
+typedef enum
+{
+	NTV_NONE = 0,
+	NTV_GETSPHERES,
+	NTV_GETMORESPHERES,
+	NTV_BONUSTIMESTART,
+	NTV_BONUSTIMEEND,
+} nightstextvar_t;
+
 
 // ========================================================================
 //                          PLAYER STRUCTURE
@@ -572,7 +582,8 @@ typedef struct player_s
 	// Statistical purposes.
 	tic_t marebegunat; // Leveltime when mare begun
 	tic_t startedtime; // Time which you started this mare with.
-	tic_t finishedtime; // Time it took you to finish the mare (used for display)
+	tic_t finishedtime; // The time it took to destroy the capsule on this mare (used for bonus time display)
+	tic_t lastmaretime; // The time it took to complete the last mare (used for rank display)
 	tic_t lapbegunat; // Leveltime when lap begun
 	tic_t lapstartedtime; // Time which you started this lap with.
 	INT16 finishedspheres; // The spheres you had left upon finishing the mare
@@ -587,7 +598,7 @@ typedef struct player_s
 	UINT8 totalmarebonuslap; // total mare bonus lap
 	INT32 maxlink; // maximum link obtained
 	UINT8 texttimer; // nights_texttime should not be local
-	UINT8 textvar; // which line of NiGHTS text to show -- let's not use cheap hacks
+	UINT8 textvar; // which line of NiGHTS text to show -- see nightstextvar_t
 
 	INT16 lastsidehit, lastlinehit;
 
diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c
index 858dfaf20234cb6898ffe008bce3c3f76e8b950b..413b366b865c035a08ece29008c30004ea58666e 100644
--- a/src/dedicated/i_system.c
+++ b/src/dedicated/i_system.c
@@ -1585,5 +1585,15 @@ void I_GetCursorPosition(INT32 *x, INT32 *y)
 	(void)y;
 }
 
+void I_SetTextInputMode(boolean active)
+{
+	(void)active;
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return false;
+}
+
 #include "../sdl/dosstr.c"
 
diff --git a/src/deh_lua.c b/src/deh_lua.c
index c056db82a7ca65c7bb9c1ba363708ce5880d253f..64fb52fc7423a7486c9d6736762fedd0fcde64ba 100644
--- a/src/deh_lua.c
+++ b/src/deh_lua.c
@@ -59,24 +59,19 @@ static inline int lib_freeslot(lua_State *L)
 		}
 		else if (fastcmp(type, "SPR"))
 		{
-			char wad;
 			spritenum_t j;
-			lua_getfield(L, LUA_REGISTRYINDEX, "WAD");
-			wad = (char)lua_tointeger(L, -1);
-			lua_pop(L, 1);
+
+			if (strlen(word) > MAXSPRITENAME)
+				return luaL_error(L, "Sprite name is longer than %d characters\n", MAXSPRITENAME);
+
 			for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++)
 			{
-				if (used_spr[(j-SPR_FIRSTFREESLOT)/8] & (1<<(j%8)))
-				{
-					if (!sprnames[j][4] && memcmp(sprnames[j],word,4)==0)
-						sprnames[j][4] = wad;
+				if (in_bit_array(used_spr, j - SPR_FIRSTFREESLOT))
 					continue; // Already allocated, next.
-				}
 				// Found a free slot!
 				CONS_Printf("Sprite SPR_%s allocated.\n",word);
-				strncpy(sprnames[j],word,4);
-				//sprnames[j][4] = 0;
-				used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
+				strcpy(sprnames[j], word);
+				set_bit_array(used_spr, j - SPR_FIRSTFREESLOT); // Okay, this sprite slot has been named now.
 				// Lua needs to update the value in _G if it exists
 				LUA_UpdateSprName(word, j);
 				lua_pushinteger(L, j);
@@ -455,17 +450,19 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
 	}
 	else if (fastncmp("SPR_",word,4)) {
 		p = word+4;
-		for (i = 0; i < NUMSPRITES; i++)
-			if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
-				// updating overridden sprnames is not implemented for soc parser,
-				// so don't use cache
-				if (mathlib)
-					lua_pushinteger(L, i);
-				else
-					CacheAndPushConstant(L, word, i);
-				return 1;
-			}
-		if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word);
+		i = R_GetSpriteNumByName(p);
+		if (i != NUMSPRITES)
+		{
+			// updating overridden sprnames is not implemented for soc parser,
+			// so don't use cache
+			if (mathlib)
+				lua_pushinteger(L, i);
+			else
+				CacheAndPushConstant(L, word, i);
+			return 1;
+		}
+		else if (mathlib)
+			return luaL_error(L, "sprite '%s' could not be found.\n", word);
 		return 0;
 	}
 	else if (fastncmp("SPR2_",word,5)) {
@@ -738,18 +735,18 @@ static inline int lib_getenum(lua_State *L)
 // If a sprname has been "cached" to _G, update it to a new value.
 void LUA_UpdateSprName(const char *name, lua_Integer value)
 {
-	char fullname[9] = "SPR_XXXX";
+	char fullname[4 + MAXSPRITENAME + 1] = "SPR_";
 
 	if (!gL)
 		return;
 
-	strncpy(&fullname[4], name, 4);
+	strcpy(&fullname[4], name);
 	lua_pushstring(gL, fullname);
 	lua_rawget(gL, LUA_GLOBALSINDEX);
 
 	if (!lua_isnil(gL, -1))
 	{
-		lua_pushstring(gL, name);
+		lua_pushstring(gL, fullname);
 		lua_pushinteger(gL, value);
 		lua_rawset(gL, LUA_GLOBALSINDEX);
 	}
diff --git a/src/deh_soc.c b/src/deh_soc.c
index beaf7cbf0cd4f861ce413fc9c504755a2b4965e8..dda3b2ef4b31352b1579623421cdc2733da56585 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -405,7 +405,6 @@ void readfreeslots(MYFILE *f)
 {
 	char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
 	char *word,*type;
-	char *tmp;
 	int i;
 
 	do
@@ -415,10 +414,13 @@ void readfreeslots(MYFILE *f)
 			if (s[0] == '\n')
 				break;
 
-			tmp = strchr(s, '#');
-			if (tmp)
-				*tmp = '\0';
-			if (s == tmp)
+			char *hashtag = strchr(s, '#');
+			char *space = strchr(s, ' ');
+			if (hashtag)
+				*hashtag = '\0';
+			if (space)
+				*space = '\0';
+			if (s == hashtag || s == space)
 				continue; // Skip comment lines, but don't break.
 
 			type = strtok(s, "_");
@@ -440,18 +442,16 @@ void readfreeslots(MYFILE *f)
 				S_AddSoundFx(word, false, 0, false);
 			else if (fastcmp(type, "SPR"))
 			{
+				if (strlen(word) > MAXSPRITENAME)
+					I_Error("Sprite name is longer than %d characters\n", MAXSPRITENAME);
+
 				for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++)
 				{
-					if (used_spr[(i-SPR_FIRSTFREESLOT)/8] & (1<<(i%8)))
-					{
-						if (!sprnames[i][4] && memcmp(sprnames[i],word,4)==0)
-							sprnames[i][4] = (char)f->wad;
+					if (in_bit_array(used_spr, i - SPR_FIRSTFREESLOT))
 						continue; // Already allocated, next.
-					}
 					// Found a free slot!
-					strncpy(sprnames[i],word,4);
-					//sprnames[i][4] = 0;
-					used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now.
+					strcpy(sprnames[i], word);
+					set_bit_array(used_spr, i - SPR_FIRSTFREESLOT); // Okay, this sprite slot has been named now.
 					// Lua needs to update the value in _G if it exists
 					LUA_UpdateSprName(word, i);
 					break;
@@ -1543,6 +1543,12 @@ void readlevelheader(MYFILE *f, INT32 num)
 				P_AddGradesForMare((INT16)(num-1), mare-1, word2);
 			}
 
+			// NiGHTS time limits (per mare)
+			else if (fastncmp(word, "NIGHTSTIME", 10))
+			{
+				P_AddNiGHTSTimes((INT16)(num-1), word2);
+			}
+
 			// Strings that can be truncated
 			else if (fastcmp(word, "SELECTHEADING"))
 			{
@@ -4176,9 +4182,9 @@ spritenum_t get_sprite(const char *word)
 		return atoi(word);
 	if (fastncmp("SPR_",word,4))
 		word += 4; // take off the SPR_
-	for (i = 0; i < NUMSPRITES; i++)
-		if (!sprnames[i][4] && memcmp(word,sprnames[i],4)==0)
-			return i;
+	i = R_GetSpriteNumByName(word);
+	if (i != NUMSPRITES)
+		return i;
 	deh_warning("Couldn't find sprite named 'SPR_%s'",word);
 	return SPR_NULL;
 }
diff --git a/src/deh_tables.c b/src/deh_tables.c
index 93a70b779c8c4c62e56a93dc1c78dc123bf51650..f113f6b19c8eb8b0a9c511406778db8bebd2e81d 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -31,7 +31,7 @@
 char *FREE_STATES[NUMSTATEFREESLOTS];
 char *FREE_MOBJS[NUMMOBJFREESLOTS];
 char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
-UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
+bitarray_t used_spr[BIT_ARRAY_SIZE(NUMSPRITEFREESLOTS)]; // Sprite freeslots in use
 
 const char NIGHTSGRADE_LIST[] = {
 	'F', // GRADE_F
@@ -5096,6 +5096,10 @@ struct int_const_s const INT_CONST[] = {
 	{"RF_SHADOWEFFECTS",RF_SHADOWEFFECTS},
 	{"RF_DROPSHADOW",RF_DROPSHADOW},
 
+	// Animation flags
+	{"SPR2F_MASK",SPR2F_MASK},
+	{"SPR2F_SUPER",SPR2F_SUPER},
+
 	// Level flags
 	{"LF_SCRIPTISFILE",LF_SCRIPTISFILE},
 	{"LF_SPEEDMUSIC",LF_SPEEDMUSIC},
@@ -5800,6 +5804,10 @@ struct int_const_s const INT_CONST[] = {
 	{"MB_SCROLLUP",MB_SCROLLUP},
 	{"MB_SCROLLDOWN",MB_SCROLLDOWN},
 
+	// screen.h constants
+	{"BASEVIDWIDTH",BASEVIDWIDTH},
+	{"BASEVIDHEIGHT",BASEVIDHEIGHT},
+
 	{NULL,0}
 };
 
diff --git a/src/deh_tables.h b/src/deh_tables.h
index 42716f9b4bd271c98aca83737f419670d862d7e5..b6986adff0166c3132be5f70ca78c7835030998f 100644
--- a/src/deh_tables.h
+++ b/src/deh_tables.h
@@ -23,13 +23,13 @@
 extern char *FREE_STATES[NUMSTATEFREESLOTS];
 extern char *FREE_MOBJS[NUMMOBJFREESLOTS];
 extern char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
-extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
+extern bitarray_t used_spr[BIT_ARRAY_SIZE(NUMSPRITEFREESLOTS)]; // Sprite freeslots in use
 
 #define initfreeslots() {\
-	memset(FREE_STATES,0,sizeof(char *) * NUMSTATEFREESLOTS);\
-	memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\
-	memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\
-	memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\
+	memset(FREE_STATES, 0, sizeof(FREE_STATES));\
+	memset(FREE_MOBJS, 0, sizeof(FREE_MOBJS));\
+	memset(FREE_SKINCOLORS, 0, sizeof(FREE_SKINCOLORS));\
+	memset(used_spr, 0, sizeof(used_spr));\
 	memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\
 }
 
diff --git a/src/doomstat.h b/src/doomstat.h
index c2fc963478b56682a03acf6d592398c134e861bc..bde2bacc72890d47b61a6085a26c5cda33dcfad0 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -335,6 +335,7 @@ typedef struct
 	INT32 sstimer;              ///< Timer for special stages.
 	UINT32 ssspheres;           ///< Sphere requirement in special stages.
 	fixed_t gravity;            ///< Map-wide gravity.
+	UINT16 nightstimer[8];      ///< Per-mare time limits for NiGHTS stages.
 
 	// Title card.
 	char ltzzpatch[8+1];        ///< Zig zag patch.
diff --git a/src/doomtype.h b/src/doomtype.h
index 4070e346a1b13dd516a91504f056cebc4defb20d..fa8616793e0aeab7bea18c77ef78a4520770b802 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -108,6 +108,7 @@ char *nongnu_strcasestr(const char *in, const char *what);
 
 int startswith (const char *base, const char *tag);
 int endswith (const char *base, const char *tag);
+char *xstrtok(char *line, const char *delims);
 
 #if defined (_WIN32) || defined (__HAIKU__)
 #define HAVE_DOSSTR_FUNCS
diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c
index ecabe3576d3f15b06513315a945562076587aff5..99bfa9f363ca04c9281b17b0cffeda5cc4314586 100644
--- a/src/dummy/i_system.c
+++ b/src/dummy/i_system.c
@@ -211,5 +211,15 @@ const char *I_GetSysName(void)
 	return NULL;
 }
 
+void I_SetTextInputMode(boolean active)
+{
+	(void)active;
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return false;
+}
+
 #include "../sdl/dosstr.c"
 
diff --git a/src/f_finale.c b/src/f_finale.c
index c221ed52ffd3643d835848f98f30abc232c3b7da..810af4e82f3ea4f08d035b626a6afffef52a0467 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -229,6 +229,7 @@ static UINT8 cutscene_boostspeed = 0;
 char stjrintro[9] = "STJRI000";
 
 static huddrawlist_h luahuddrawlist_title;
+static huddrawlist_h luahuddrawlist_continue[2];
 
 //
 // This alters the text string cutscene_disptext.
@@ -2335,7 +2336,7 @@ void F_SkyScroll(const char *patchname)
 }
 
 #define LOADTTGFX(arr, name, maxf) \
-lumpnum = W_CheckNumForName(name); \
+lumpnum = W_CheckNumForPatchName(name); \
 if (lumpnum != LUMPERROR) \
 { \
 	arr[0] = W_CachePatchName(name, PU_PATCH_LOWPRIORITY); \
@@ -2349,7 +2350,7 @@ else if (strlen(name) <= 6) \
 	{ \
 		sprintf(&lumpname[cnt], "%.2hu", (UINT16)(i+1)); \
 		lumpname[8] = 0; \
-		lumpnum = W_CheckNumForName(lumpname); \
+		lumpnum = W_CheckNumForPatchName(lumpname); \
 		if (lumpnum != LUMPERROR) \
 			arr[i] = W_CachePatchName(lumpname, PU_PATCH_LOWPRIORITY); \
 		else \
@@ -3530,11 +3531,16 @@ void F_TitleDemoTicker(void)
 // ==========
 
 static skin_t *contskins[2];
-static UINT8 cont_spr2[2][6];
+static UINT16 cont_spr2[2][6];
 static UINT8 *contcolormaps[2];
+static player_t *contPlayers[2];
+static skincolornum_t contColors[2]; // it's possible to change your skincolor in the continue screen, so this is for Lua to identify the skincolor that was used to cache the colormap
+static boolean contOverrides[2];
 
 void F_StartContinue(void)
 {
+	UINT8 i;
+
 	I_Assert(!netgame && !multiplayer);
 
 	if (continuesInSession && players[consoleplayer].continues <= 0)
@@ -3557,9 +3563,12 @@ void F_StartContinue(void)
 	S_ChangeMusicInternal("_conti", false);
 	S_StopSounds();
 
+	contPlayers[0] = &players[consoleplayer];
 	contskins[0] = skins[players[consoleplayer].skin];
+
 	cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL);
 	cont_spr2[0][2] = contskins[0]->contangle & 7;
+	contColors[0] = players[consoleplayer].skincolor;
 	contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE);
 	cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes;
 	cont_spr2[0][5] = max(1, contskins[0]->contspeed);
@@ -3573,9 +3582,12 @@ void F_StartContinue(void)
 		else // HACK
 			secondplaya = 1;
 
+		contPlayers[1] = &players[secondplaya];
 		contskins[1] = skins[players[secondplaya].skin];
+
 		cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL);
 		cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7;
+		contColors[1] = players[secondplaya].skincolor;
 		contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE);
 		cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes;
 		if (cont_spr2[1][0] == SPR2_CNT4)
@@ -3595,6 +3607,58 @@ void F_StartContinue(void)
 
 	timetonext = (11*TICRATE)+11;
 	continuetime = 0;
+
+	// allocate and/or clear Lua continue screen draw lists
+	for (i = 0; i < 2; i++)
+	{
+		if (!LUA_HUD_IsDrawListValid(luahuddrawlist_continue[i]))
+		{
+			LUA_HUD_DestroyDrawList(luahuddrawlist_continue[i]);
+			luahuddrawlist_continue[i] = LUA_HUD_CreateDrawList();
+		}
+		LUA_HUD_ClearDrawList(luahuddrawlist_continue[i]);
+		contOverrides[i] = false;
+	}
+}
+
+static void F_DestroyContinueDrawLists(void)
+{
+	UINT8 i;
+	for (i = 0; i < 2; i++)
+	{
+		LUA_HUD_DestroyDrawList(luahuddrawlist_continue[i]);
+		luahuddrawlist_continue[i] = NULL;
+		contOverrides[i] = false;
+	}
+}
+
+static void F_DrawContinueCharacter(INT32 dx, INT32 dy, UINT8 n)
+{
+	spritedef_t *sprdef;
+	spriteframe_t *sprframe;
+	patch_t *patch;
+
+	if (renderisnewtic)
+	{
+		LUA_HUD_ClearDrawList(luahuddrawlist_continue[n]);
+		contOverrides[n] = LUA_HookCharacterHUD
+		(
+			HUD_HOOK(continue), luahuddrawlist_continue[n], contPlayers[n],
+			dx, dy, contskins[n]->highresscale,
+			(INT32)(&contskins[n] - skins), cont_spr2[n][0], cont_spr2[n][1], cont_spr2[n][2] + 1, contColors[n], // add 1 to rotation to convert internal angle numbers (0-7) to WAD editor angle numbers (1-8)
+			imcontinuing ? continuetime : timetonext, imcontinuing
+		);
+	}
+
+	LUA_HUD_DrawList(luahuddrawlist_continue[n]);
+
+	if (contOverrides[n] == true)
+		return;
+
+	sprdef = &contskins[n]->sprites[cont_spr2[n][0]];
+	sprframe = &sprdef->spriteframes[cont_spr2[n][1]];
+	patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);
+	V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);
 }
 
 //
@@ -3603,8 +3667,6 @@ void F_StartContinue(void)
 //
 void F_ContinueDrawer(void)
 {
-	spritedef_t *sprdef;
-	spriteframe_t *sprframe;
 	patch_t *patch;
 	INT32 i, x = (BASEVIDWIDTH>>1), ncontinues = players[consoleplayer].continues;
 	char numbuf[9] = "CONTNUM*";
@@ -3649,7 +3711,7 @@ void F_ContinueDrawer(void)
 	else if (ncontinues > 10)
 	{
 		if (!(continuetime & 1) || continuetime > 17)
-			V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
+			V_DrawContinueIcon(x, 68, 0, (INT32)(&contskins[0] - skins), contColors[0]);
 		V_DrawScaledPatch(x+12, 66, 0, stlivex);
 		V_DrawRightAlignedString(x+38, 64, 0,
 			va("%d",(imcontinuing ? ncontinues-1 : ncontinues)));
@@ -3663,7 +3725,7 @@ void F_ContinueDrawer(void)
 		{
 			if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17))
 				continue;
-			V_DrawContinueIcon(x - (i*30), 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
+			V_DrawContinueIcon(x - (i*30), 68, 0, (INT32)(&contskins[0] - skins), contColors[0]);
 		}
 		x = BASEVIDWIDTH>>1;
 	}
@@ -3703,21 +3765,12 @@ void F_ContinueDrawer(void)
 	else if (lift[0] > TICRATE+5)
 		lift[0] = TICRATE+5;
 
-#define drawchar(dx, dy, n)	{\
-								sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\
-								sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\
-								patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);\
-								V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\
-							}
-
 	if (offsy < 0)
-		drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
+		F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
 	if (contskins[1])
-		drawchar((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
+		F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
 	if (offsy >= 0)
-		drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
-
-#undef drawchar
+		F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
 
 	if (timetonext > (11*TICRATE))
 		V_DrawFadeScreen(31, timetonext-(11*TICRATE));
@@ -3733,6 +3786,7 @@ void F_ContinueTicker(void)
 		{
 			if (!(--timetonext))
 			{
+				F_DestroyContinueDrawLists();
 				Command_ExitGame_f();
 				return;
 			}
@@ -3742,6 +3796,7 @@ void F_ContinueTicker(void)
 	{
 		if (++continuetime == 3*TICRATE)
 		{
+			F_DestroyContinueDrawLists();
 			G_Continue();
 			return;
 		}
@@ -4061,7 +4116,7 @@ static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *b
 	// reuse:
 	// cutnum -> promptnum
 	// scenenum -> pagenum
-	lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
+	lumpnum_t iconlump = W_CheckNumForPatchName(textprompts[cutnum]->page[scenenum].iconname);
 
 	*pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4;
 	*rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside);
@@ -4453,7 +4508,7 @@ void F_TextPromptDrawer(void)
 	if (!promptactive)
 		return;
 
-	iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
+	iconlump = W_CheckNumForPatchName(textprompts[cutnum]->page[scenenum].iconname);
 	F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
 
 	// Draw gfx first
diff --git a/src/filesrch.c b/src/filesrch.c
index 6429b6fa2f13b49979c7e5efa1614bf47cac02be..3a729a9c80ee4b80e7b1bcff9385f631651694d1 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -699,6 +699,15 @@ static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
 		dirpathindex[depthleft]--;
 }
 
+//sortdir by name? 
+static int lumpnamecompare(const void *A, const void *B)
+{
+	const lumpinfo_t *pA = A;
+	const lumpinfo_t *pB = B;
+	return strcmp((pA->fullname), (pB->fullname));
+
+}
+
 lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
 {
 	DIR **dirhandle;
@@ -889,6 +898,9 @@ lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
 	free(dirpathindex);
 	free(dirhandle);
 
+	//sort files and directories
+	qsort (lumpinfo, numlumps, sizeof(lumpinfo_t), lumpnamecompare);
+
 	(*nlmp) = numlumps;
 	return lumpinfo;
 }
@@ -1185,7 +1197,7 @@ boolean preparefilemenu(boolean samedepth)
 					{
 						if (!filenamebuf[i][0])
 						{
-							strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH);
+							strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH-1);
 							filenamebuf[i][MAX_WADPATH - 1] = '\0';
 							nameonly(filenamebuf[i]);
 						}
diff --git a/src/g_demo.c b/src/g_demo.c
index e445c4b5db017570095d97a2f805879954e96249..cfa34fc7e76c7978a52603fdd05f3e55d19f3e17 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -67,6 +67,8 @@ static UINT8 *metalbuffer = NULL;
 static UINT8 *metal_p;
 static UINT16 metalversion;
 
+consvar_t cv_resyncdemo = CVAR_INIT("resyncdemo", "On", 0, CV_OnOff, NULL);
+
 // extra data stuff (events registered this frame while recording)
 static struct {
 	UINT8 flags; // EZT flags
@@ -413,7 +415,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 	{
 		oldghost.sprite2 = ghost->sprite2;
 		ziptic |= GZT_SPR2;
-		WRITEUINT8(demo_p,oldghost.sprite2);
+		WRITEUINT16(demo_p,oldghost.sprite2);
 	}
 
 	// Check for sprite set changes
@@ -513,7 +515,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 		temp = ghost->player->followmobj->z-ghost->z;
 		WRITEFIXED(demo_p,temp);
 		if (followtic & FZT_SKIN)
-			WRITEUINT8(demo_p,ghost->player->followmobj->sprite2);
+			WRITEUINT16(demo_p,ghost->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
 		WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK));
 		WRITEUINT16(demo_p,ghost->player->followmobj->color);
@@ -549,6 +551,9 @@ void G_ConsGhostTic(void)
 
 	testmo = players[0].mo;
 
+	if (P_MobjWasRemoved(testmo))
+		return; // No valid mobj exists, probably because of unexpected quit
+
 	// Grab ghost data.
 	ziptic = READUINT8(demo_p);
 	if (ziptic & GZT_XYZ)
@@ -575,7 +580,7 @@ void G_ConsGhostTic(void)
 	if (ziptic & GZT_FRAME)
 		demo_p++;
 	if (ziptic & GZT_SPR2)
-		demo_p++;
+		demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
 
 	if (ziptic & GZT_EXTRA)
 	{ // But wait, there's more!
@@ -644,7 +649,7 @@ void G_ConsGhostTic(void)
 		// momx, momy and momz
 		demo_p += (demoversion < 0x000e) ? sizeof(INT16) * 3 : sizeof(fixed_t) * 3;
 		if (followtic & FZT_SKIN)
-			demo_p++;
+			demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
 		demo_p += sizeof(UINT16);
 		demo_p++;
 		demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16);
@@ -664,11 +669,14 @@ void G_ConsGhostTic(void)
 			CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
 		demosynced = false;
 
-		P_UnsetThingPosition(testmo);
-		testmo->x = oldghost.x;
-		testmo->y = oldghost.y;
-		P_SetThingPosition(testmo);
-		testmo->z = oldghost.z;
+		if (cv_resyncdemo.value)
+		{
+			P_UnsetThingPosition(testmo);
+			testmo->x = oldghost.x;
+			testmo->y = oldghost.y;
+			P_SetThingPosition(testmo);
+			testmo->z = oldghost.z;
+		}
 	}
 
 	if (*demo_p == DEMOMARKER)
@@ -726,7 +734,7 @@ void G_GhostTicker(void)
 		if (ziptic & GZT_FRAME)
 			g->oldmo.frame = READUINT8(g->p);
 		if (ziptic & GZT_SPR2)
-			g->oldmo.sprite2 = READUINT8(g->p);
+			g->oldmo.sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
 
 		// Update ghost
 		P_UnsetThingPosition(g->mo);
@@ -941,7 +949,7 @@ void G_GhostTicker(void)
 				follow->z = g->mo->z + temp;
 				P_SetThingPosition(follow);
 				if (followtic & FZT_SKIN)
-					follow->sprite2 = READUINT8(g->p);
+					follow->sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
 				else
 					follow->sprite2 = 0;
 				follow->sprite = READUINT16(g->p);
@@ -1056,7 +1064,7 @@ void G_ReadMetalTic(mobj_t *metal)
 			oldmetal.frame = G_ConvertOldFrameFlags(oldmetal.frame);
 	}
 	if (ziptic & GZT_SPR2)
-		oldmetal.sprite2 = READUINT8(metal_p);
+		oldmetal.sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
 
 	// Set movement, position, and angle
 	// oldmetal contains where you're supposed to be.
@@ -1199,7 +1207,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				follow->z = metal->z + temp;
 				P_SetThingPosition(follow);
 				if (followtic & FZT_SKIN)
-					follow->sprite2 = READUINT8(metal_p);
+					follow->sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
 				else
 					follow->sprite2 = 0;
 				follow->sprite = READUINT16(metal_p);
@@ -1207,7 +1215,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				if (metalversion < 0x000f)
 					follow->frame = G_ConvertOldFrameFlags(follow->frame);
 				follow->angle = metal->angle;
-				follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
+				follow->color = (metalversion == 0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
 
 				if (!(followtic & FZT_SPAWNED))
 				{
@@ -1308,7 +1316,7 @@ void G_WriteMetalTic(mobj_t *metal)
 	{
 		oldmetal.sprite2 = metal->sprite2;
 		ziptic |= GZT_SPR2;
-		WRITEUINT8(demo_p,oldmetal.sprite2);
+		WRITEUINT16(demo_p,oldmetal.sprite2);
 	}
 
 	// Check for sprite set changes
@@ -1383,7 +1391,7 @@ void G_WriteMetalTic(mobj_t *metal)
 		temp = metal->player->followmobj->z-metal->z;
 		WRITEFIXED(demo_p,temp);
 		if (followtic & FZT_SKIN)
-			WRITEUINT8(demo_p,metal->player->followmobj->sprite2);
+			WRITEUINT16(demo_p,metal->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,metal->player->followmobj->sprite);
 		WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits
 		WRITEUINT16(demo_p,metal->player->followmobj->color);
@@ -2607,10 +2615,10 @@ void G_AddGhost(char *defdemoname)
 		}
 	gh->oldmo.color = gh->mo->color;
 
-	gh->mo->state = states+S_PLAY_STND;
+	gh->mo->state = &states[S_PLAY_STND];
 	gh->mo->sprite = gh->mo->state->sprite;
-	gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK);
-	//gh->mo->frame = tr_trans30<<FF_TRANSSHIFT;
+	gh->mo->sprite2 = P_GetStateSprite2(gh->mo->state);
+	gh->mo->frame = (gh->mo->state->frame & ~FF_FRAMEMASK) | P_GetSprite2StateFrame(gh->mo->state);
 	gh->mo->flags2 |= MF2_DONTDRAW;
 	gh->fadein = (9-3)*6; // fade from invisible to trans30 over as close to 35 tics as possible
 	gh->mo->tics = -1;
diff --git a/src/g_demo.h b/src/g_demo.h
index e8c0c8d956187161ea5bbaffe9c145c764a40ba4..67f61f54de1166034d4376faa6ca340b39779e9d 100644
--- a/src/g_demo.h
+++ b/src/g_demo.h
@@ -35,6 +35,7 @@ typedef enum
 } demo_file_override_e;
 
 extern demo_file_override_e demofileoverride;
+extern consvar_t cv_resyncdemo;
 
 // Quit after playing a demo from cmdline.
 extern boolean singledemo;
diff --git a/src/g_game.c b/src/g_game.c
index 8d19c9e7cb68df142e68e7d0277b2425153f9206..bf369d111bb2ea1da40514e1b2b6b5ad3845d0af 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1363,11 +1363,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL);
 	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))
@@ -1386,6 +1386,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0))
 		cmd->buttons |= BT_SPIN;
 
+	if (gamestate != GS_LEVEL) // not in a level, don't build anything else
+	{
+		cmd->angleturn = ticcmd_oldangleturn[forplayer];
+		cmd->aiming = G_ClipAimingPitch(myaiming);
+		return;
+	}
+
 	// Centerview can be a toggle in simple mode!
 	{
 		static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior
@@ -1420,7 +1427,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 
 		ticcmd_centerviewdown[forplayer] = true;
 	}
-	else if (ticcmd_centerviewdown[forplayer])
+	else if (ticcmd_centerviewdown[forplayer] || (leveltime < 5))
 	{
 		if (controlstyle == CS_SIMPLE)
 		{
@@ -1435,6 +1442,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	{
 		if (
 			P_MobjWasRemoved(ticcmd_ztargetfocus[forplayer]) ||
+			(leveltime < 5) ||
+			(player->playerstate != PST_LIVE) ||
+			player->exiting ||
 			!ticcmd_ztargetfocus[forplayer]->health ||
 			(ticcmd_ztargetfocus[forplayer]->type == MT_EGGMOBILE3 && !ticcmd_ztargetfocus[forplayer]->movecount) // Sea Egg is moving around underground and shouldn't be tracked
 		)
@@ -1466,7 +1476,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 			P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]);
 			newtarget->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
 
-			if (player->mo && P_AproxDistance(
+			if (player->mo && R_PointToDist2(0, 0,
 				player->mo->x - ticcmd_ztargetfocus[forplayer]->x,
 				player->mo->y - ticcmd_ztargetfocus[forplayer]->y
 			) > 50*player->mo->scale)
@@ -1714,7 +1724,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	// At this point, cmd doesn't contain the final angle yet,
 	// So we need to temporarily transform it so Lua scripters
 	// don't need to handle it differently than in other hooks.
-	if (addedtogame && gamestate == GS_LEVEL)
+	if (addedtogame)
 	{
 		INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn;
 		INT16 origangle = cmd->angleturn;
@@ -4018,7 +4028,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
 	INT32 i;
 	INT16 newmapnum;
 	boolean spec = G_IsSpecialStage(gamemap);
-	
+
 	// go to next level
 	// newmapnum is 0-based, unlike gamemap
 	if (nextmapoverride != 0)
@@ -4122,7 +4132,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
 
 	if (spec && (!gottoken || ignoretokens) && !nextmapoverride)
 		newmapnum = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001
-	
+
 	if (!(gametyperules & GTR_CAMPAIGN))
 	{
 		if (cv_advancemap.value == 0) // Stay on same map.
@@ -4130,7 +4140,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
 		else if (cv_advancemap.value == 2) // Go to random map.
 			newmapnum = RandMap(G_TOLFlag(gametype_to_use), prevmap);
 	}
-	
+
 	return newmapnum;
 }
 
@@ -4140,7 +4150,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
 static void G_DoCompleted(void)
 {
 	INT32 i;
-	
+
 	tokenlist = 0; // Reset the list
 
 	if (modeattacking && pausedelay)
@@ -4168,7 +4178,7 @@ static void G_DoCompleted(void)
 	//Get and set prevmap/nextmap
 	prevmap = (INT16)(gamemap-1);
 	nextmap = G_GetNextMap(false, false);
-	
+
 	automapactive = false;
 
 	// We are committed to this map now.
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index bd8f316178dad3e48835e921c5cf7db0af734660..831c8d7c4bce2190311647ce4ec06ae7029593a3 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -1533,14 +1533,14 @@ static void HWR_ProcessSeg(void)
 				if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
 					continue;
 
-				side_t *side = R_GetFFloorSide(gl_curline, rover);
+				side_t *side = R_GetFFloorSide(gl_curline->linedef, rover, gl_backsector);
 
 				boolean do_texture_skew;
 				boolean dont_peg_bottom;
 
 				if (rover->master->flags & ML_TFERLINE)
 				{
-					line_t *newline = R_GetFFloorLine(gl_curline, rover);
+					line_t *newline = R_GetFFloorLine(gl_curline->linedef, rover, gl_backsector);
 					do_texture_skew = newline->flags & ML_SKEWTD;
 					dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
 				}
@@ -1689,14 +1689,14 @@ static void HWR_ProcessSeg(void)
 				if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
 					continue;
 
-				side_t *side = R_GetFFloorSide(gl_curline, rover);
+				side_t *side = R_GetFFloorSide(gl_curline->linedef, rover, gl_backsector);
 
 				boolean do_texture_skew;
 				boolean dont_peg_bottom;
 
 				if (rover->master->flags & ML_TFERLINE)
 				{
-					line_t *newline = R_GetFFloorLine(gl_curline, rover);
+					line_t *newline = R_GetFFloorLine(gl_curline->linedef, rover, gl_backsector);
 					do_texture_skew = newline->flags & ML_SKEWTD;
 					dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
 				}
@@ -4364,9 +4364,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	//Fab : 02-08-98: 'skin' override spritedef currently used for skin
 	if (thing->skin && thing->sprite == SPR_PLAY)
 	{
-		sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
+		sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
 #ifdef ROTSPRITE
-		sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
+		sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
 #endif
 	}
 	else
@@ -5221,7 +5221,9 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean
 	if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))
 	{
 		fixed_t fixedaiming = AIMINGTODY(aimingangle);
-		trans->viewaiming = FIXED_TO_FLOAT(fixedaiming);
+		trans->viewaiming = FIXED_TO_FLOAT(fixedaiming) * ((float)vid.width / vid.height) / ((float)BASEVIDWIDTH / BASEVIDHEIGHT);
+		if (splitscreen)
+			trans->viewaiming *= 2.125; // splitscreen adjusts fov with 0.8, so compensate (but only halfway, since splitscreen means only half the screen is used)
 		trans->shearing = true;
 		gl_aimingangle = 0;
 	}
@@ -5953,7 +5955,7 @@ void HWR_DoPostProcessor(player_t *player)
 		if (*type == postimg_water)
 		{
 			WAVELENGTH = 5;
-			AMPLITUDE = 20;
+			AMPLITUDE = 40;
 			FREQUENCY = 8;
 		}
 		else
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index ef0341bd5da7b73b5b9757a06a8eab2df521967f..0f466f051c6adc6f025444ca16e2bcb90b38ba71 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -571,19 +571,15 @@ void HWR_LoadModels(void)
 		}
 
 		// Add sprite models.
-		// Must be 4 characters long exactly. Otherwise, it's not a sprite name.
-		if (len == 4)
+		for (i = 0; i < numsprites; i++)
 		{
-			for (i = 0; i < numsprites; i++)
+			if (stricmp(name, sprnames[i]) == 0)
 			{
-				if (stricmp(name, sprnames[i]) == 0)
-				{
-					md2_models[i].scale = scale;
-					md2_models[i].offset = offset;
-					md2_models[i].found = true;
-					strcpy(md2_models[i].filename, filename);
-					goto modelfound;
-				}
+				md2_models[i].scale = scale;
+				md2_models[i].offset = offset;
+				md2_models[i].found = true;
+				strcpy(md2_models[i].filename, filename);
+				goto modelfound;
 			}
 		}
 
@@ -1078,30 +1074,47 @@ static boolean HWR_CanInterpolateSprite2(modelspr2frames_t *spr2frame)
 	return spr2frame->interpolate;
 }
 
-//
-// HWR_GetModelSprite2 (see P_GetSkinSprite2)
-// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
-// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
-//
-
-static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *player)
+static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2)
 {
-	UINT8 super = 0, i = 0;
+	if (!md2 || !md2->model)
+		return NULL;
 
-	if (!md2 || !md2->model || !md2->model->spr2frames || !skin)
-		return 0;
+	boolean is_super = spr2 & SPR2F_SUPER;
+
+	spr2 &= SPR2F_MASK;
+
+	if (spr2 >= free_spr2)
+		return NULL;
+
+	if (is_super)
+	{
+		modelspr2frames_t *frames = md2->model->superspr2frames;
+		if (frames && md2->model->superspr2frames[spr2].numframes)
+			return &md2->model->superspr2frames[spr2];
+	}
+
+	if (md2->model->spr2frames[spr2].numframes)
+		return &md2->model->spr2frames[spr2];
+
+	return NULL;
+}
 
-	if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
+static UINT16 HWR_GetModelSprite2Num(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player)
+{
+	UINT16 super = 0;
+	UINT8 i = 0;
+
+	if (!md2 || !md2->model || !skin)
 		return 0;
 
-	while (!md2->model->spr2frames[spr2].numframes
+	while (!HWR_GetModelSprite2Frames(md2, spr2)
 		&& spr2 != SPR2_STND
-		&& ++i != 32) // recursion limiter
+		&& ++i < 32) // recursion limiter
 	{
-		if (spr2 & FF_SPR2SUPER)
+		if (spr2 & SPR2F_SUPER)
 		{
-			super = FF_SPR2SUPER;
-			spr2 &= ~FF_SPR2SUPER;
+			super = SPR2F_SUPER;
+			spr2 &= ~SPR2F_SUPER;
 			continue;
 		}
 
@@ -1130,7 +1143,7 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
 	}
 
 	if (i >= 32) // probably an infinite loop...
-		return 0;
+		spr2 = 0;
 
 	return spr2;
 }
@@ -1188,7 +1201,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 	char filename[64];
 	INT32 frame = 0;
 	INT32 nextFrame = -1;
-	UINT8 spr2 = 0;
+	modelspr2frames_t *spr2frames = NULL;
 	FTransform p;
 	FSurfaceInfo Surf;
 
@@ -1256,6 +1269,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj));
 		const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj));
 		spritedef_t *sprdef;
+		UINT16 spr2 = 0;
 		spriteframe_t *sprframe;
 		INT32 mod;
 		interpmobjstate_t interp;
@@ -1418,18 +1432,28 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			tics = (float)spr->mobj->anim_duration;
 		}
 
+		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
+			sprdef = P_GetSkinSpritedef(spr->mobj->skin, spr->mobj->sprite2);
+		else
+			sprdef = &sprites[spr->mobj->sprite];
+
 		frame = (spr->mobj->frame & FF_FRAMEMASK);
-		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
+		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
 		{
-			spr2 = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
-			mod = md2->model->spr2frames[spr2].numframes;
+			spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
+			spr2frames = HWR_GetModelSprite2Frames(md2, spr2);
+		}
+		if (spr2frames)
+		{
+			spritedef_t *defaultdef = P_GetSkinSpritedef(spr->mobj->skin, spr2);
+			mod = spr2frames->numframes;
 #ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod
-			if (mod > (INT32)((skin_t *)spr->mobj->skin)->sprites[spr2].numframes)
-				mod = ((skin_t *)spr->mobj->skin)->sprites[spr2].numframes;
+			if (mod > (INT32)defaultdef->numframes)
+				mod = defaultdef->numframes;
 #endif
 			if (!mod)
 				mod = 1;
-			frame = md2->model->spr2frames[spr2].frames[frame%mod];
+			frame = spr2frames->frames[frame % mod];
 		}
 		else
 		{
@@ -1449,13 +1473,18 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			if (durs > INTERPOLERATION_LIMIT)
 				durs = INTERPOLERATION_LIMIT;
 
-			if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames)
+			if (spr2frames)
 			{
-				if (HWR_CanInterpolateSprite2(&md2->model->spr2frames[spr2])
+				UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]);
+
+				// Add or remove SPR2F_SUPER based on certain conditions
+				next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj);
+
+				if (HWR_CanInterpolateSprite2(spr2frames)
 					&& (spr->mobj->frame & FF_ANIMATE
 					|| (spr->mobj->state->nextstate != S_NULL
 					&& states[spr->mobj->state->nextstate].sprite == SPR_PLAY
-					&& ((P_GetSkinSprite2(spr->mobj->skin, (((spr->mobj->player && spr->mobj->player->powers[pw_super]) ? FF_SPR2SUPER : 0)|states[spr->mobj->state->nextstate].frame) & FF_FRAMEMASK, spr->mobj->player) == spr->mobj->sprite2)))))
+					&& ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2)))))
 				{
 					nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1;
 					if (nextFrame >= mod)
@@ -1466,7 +1495,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 							nextFrame = 0;
 					}
 					if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE))
-						nextFrame = md2->model->spr2frames[spr2].frames[nextFrame];
+						nextFrame = spr2frames->frames[nextFrame];
 					else
 						nextFrame = -1;
 				}
@@ -1502,11 +1531,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		else
 			p.z = FIXED_TO_FLOAT(interp.z);
 
-		if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
-			sprdef = &((skin_t *)spr->mobj->skin)->sprites[spr->mobj->sprite2];
-		else
-			sprdef = &sprites[spr->mobj->sprite];
-
 		sprframe = &sprdef->spriteframes[spr->mobj->frame & FF_FRAMEMASK];
 
 		if (sprframe->rotate || papersprite)
diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c
index 0d656f35ad8e72673134f1bf53f561842b280f49..5856473e4c9855c6416f97843cd476fde2c587d2 100644
--- a/src/hardware/hw_model.c
+++ b/src/hardware/hw_model.c
@@ -292,6 +292,7 @@ void LoadModelSprite2(model_t *model)
 {
 	INT32 i;
 	modelspr2frames_t *spr2frames = NULL;
+	modelspr2frames_t *superspr2frames = NULL;
 	INT32 numframes = model->meshes[0].numFrames;
 	char *framename = model->frameNames;
 
@@ -335,25 +336,33 @@ void LoadModelSprite2(model_t *model)
 				spr2idx = 0;
 				while (spr2idx < free_spr2)
 				{
+					modelspr2frames_t *frames = NULL;
 					if (!memcmp(spr2names[spr2idx], name, 4))
 					{
 						if (!spr2frames)
-							spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES*2, PU_STATIC, NULL);
+							spr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
+						frames = spr2frames;
+
 						if (super)
-							spr2idx |= FF_SPR2SUPER;
+						{
+							if (!superspr2frames)
+								superspr2frames = (modelspr2frames_t*)Z_Calloc(sizeof(modelspr2frames_t)*NUMPLAYERSPRITES, PU_STATIC, NULL);
+							frames = superspr2frames;
+						}
+
 						if (framechars[0])
 						{
 							frame = atoi(framechars);
-							if (spr2frames[spr2idx].numframes < frame+1)
-								spr2frames[spr2idx].numframes = frame+1;
+							if (frames[spr2idx].numframes < frame+1)
+								frames[spr2idx].numframes = frame+1;
 						}
 						else
 						{
-							frame = spr2frames[spr2idx].numframes;
-							spr2frames[spr2idx].numframes++;
+							frame = frames[spr2idx].numframes;
+							frames[spr2idx].numframes++;
 						}
-						spr2frames[spr2idx].frames[frame] = i;
-						spr2frames[spr2idx].interpolate = interpolate;
+						frames[spr2idx].frames[frame] = i;
+						frames[spr2idx].interpolate = interpolate;
 						break;
 					}
 					spr2idx++;
@@ -366,7 +375,10 @@ void LoadModelSprite2(model_t *model)
 
 	if (model->spr2frames)
 		Z_Free(model->spr2frames);
+	if (model->superspr2frames)
+		Z_Free(model->superspr2frames);
 	model->spr2frames = spr2frames;
+	model->superspr2frames = superspr2frames;
 }
 
 //
diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h
index f057271df1397f528a615f93331480f620586417..5eb649b173303d72dba16a46c0793ab4d29f351c 100644
--- a/src/hardware/hw_model.h
+++ b/src/hardware/hw_model.h
@@ -101,6 +101,7 @@ typedef struct model_s
 	char *frameNames;
 	boolean interpolate[256];
 	modelspr2frames_t *spr2frames;
+	modelspr2frames_t *superspr2frames;
 
 	// the max_s and max_t values that the uvs are currently adjusted to
 	// (if a sprite is used as a texture)
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 13d499495535c4320aee7a498154cbfec9c256c2..d784c2358a82eecbff441d3e22d535b7b34ceaf5 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -61,21 +61,22 @@
 #define HU_CSAY       2 // Server CECHOes to everyone.
 
 //-------------------------------------------
-//              heads up font
+//              Fonts & stuff
 //-------------------------------------------
-patch_t *hu_font[HU_FONTSIZE];
-patch_t *tny_font[HU_FONTSIZE];
+// Font definitions
+fontdef_t hu_font;
+fontdef_t tny_font;
+fontdef_t cred_font;
+fontdef_t lt_font;
+fontdef_t ntb_font;
+fontdef_t nto_font;
+
+// Numbers
 patch_t *tallnum[10]; // 0-9
 patch_t *nightsnum[10]; // 0-9
-
-// Level title and credits fonts
-patch_t *lt_font[LT_FONTSIZE];
-patch_t *cred_font[CRED_FONTSIZE];
 patch_t *ttlnum[10]; // act numbers (0-9)
-
-// Name tag fonts
-patch_t *ntb_font[NT_FONTSIZE];
-patch_t *nto_font[NT_FONTSIZE];
+patch_t *tallminus;
+patch_t *tallinfin;
 
 static player_t *plr;
 boolean chat_on; // entering a chat message?
@@ -91,8 +92,6 @@ patch_t *bflagico;
 patch_t *rmatcico;
 patch_t *bmatcico;
 patch_t *tagico;
-patch_t *tallminus;
-patch_t *tallinfin;
 
 //-------------------------------------------
 //              coop hud
@@ -188,53 +187,26 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum);
 void HU_LoadGraphics(void)
 {
 	char buffer[9];
-	INT32 i, j;
+	INT32 i;
 
 	if (dedicated)
 		return;
 
-	j = HU_FONTSTART;
-	for (i = 0; i < HU_FONTSIZE; i++, j++)
-	{
-		// cache the heads-up font for entire game execution
-		sprintf(buffer, "STCFN%.3d", j);
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			hu_font[i] = NULL;
-		else
-			hu_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-
-		// tiny version of the heads-up font
-		sprintf(buffer, "TNYFN%.3d", j);
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			tny_font[i] = NULL;
-		else
-			tny_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	j = LT_FONTSTART;
-	for (i = 0; i < LT_FONTSIZE; i++)
-	{
-		sprintf(buffer, "LTFNT%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			lt_font[i] = NULL;
-		else
-			lt_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	// cache the credits font for entire game execution (why not?)
-	j = CRED_FONTSTART;
-	for (i = 0; i < CRED_FONTSIZE; i++)
-	{
-		sprintf(buffer, "CRFNT%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			cred_font[i] = NULL;
-		else
-			cred_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
+	// Cache fonts
+	HU_LoadFontCharacters(&hu_font,   "STCFN");
+	HU_LoadFontCharacters(&tny_font,  "TNYFN");
+	HU_LoadFontCharacters(&cred_font, "CRFNT");
+	HU_LoadFontCharacters(&lt_font,   "LTFNT");
+	HU_LoadFontCharacters(&ntb_font,  "NTFNT");
+	HU_LoadFontCharacters(&nto_font,  "NTFNO");
+
+	// For each font, set kerning, space width, character width and line spacing
+	HU_SetFontProperties(&hu_font,   0,  4,  8, 12);
+	HU_SetFontProperties(&tny_font,  0,  2,  4, 12);
+	HU_SetFontProperties(&cred_font, 0, 16, 16, 16);
+	HU_SetFontProperties(&lt_font,   0, 16, 20, 20);
+	HU_SetFontProperties(&ntb_font,  2,  4, 20, 21);
+	HU_SetFontProperties(&nto_font,  0,  4, 20, 21);
 
 	//cache numbers too!
 	for (i = 0; i < 10; i++)
@@ -243,45 +215,14 @@ void HU_LoadGraphics(void)
 		tallnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
 		sprintf(buffer, "NGTNUM%d", i);
 		nightsnum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
+		sprintf(buffer, "TTL%.2d", i);
+		ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
 	}
 
 	// minus for negative tallnums
 	tallminus = (patch_t *)W_CachePatchName("STTMINUS", PU_HUDGFX);
 	tallinfin = (patch_t *)W_CachePatchName("STTINFIN", PU_HUDGFX);
 
-	// cache act numbers for level titles
-	for (i = 0; i < 10; i++)
-	{
-		sprintf(buffer, "TTL%.2d", i);
-		ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	// cache the base name tag font for entire game execution
-	j = NT_FONTSTART;
-	for (i = 0; i < NT_FONTSIZE; i++)
-	{
-		sprintf(buffer, "NTFNT%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			ntb_font[i] = NULL;
-		else
-			ntb_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
-	// cache the outline name tag font for entire game execution
-	j = NT_FONTSTART;
-	for (i = 0; i < NT_FONTSIZE; i++)
-	{
-		sprintf(buffer, "NTFNO%.3d", j);
-		j++;
-
-		if (W_CheckNumForName(buffer) == LUMPERROR)
-			nto_font[i] = NULL;
-		else
-			nto_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
-	}
-
 	// cache the crosshairs, don't bother to know which one is being used,
 	// just cache all 3, they're so small anyway.
 	for (i = 0; i < HU_CROSSHAIRS; i++)
@@ -323,6 +264,29 @@ void HU_LoadGraphics(void)
 	//emeraldpics[2][7] = W_CachePatchName("EMBOX8", PU_HUDGFX); -- unused
 }
 
+void HU_LoadFontCharacters(fontdef_t *font, const char *prefix)
+{
+		char buffer[9];
+		INT32 i, j = FONTSTART;
+
+		for (i = 0; i < FONTSIZE; i++, j++)
+		{
+			sprintf(buffer, "%.5s%.3d", prefix, j);
+			if (W_CheckNumForPatchName(buffer) == LUMPERROR)
+				font->chars[i] = NULL;
+			else
+				font->chars[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
+		}
+}
+
+void HU_SetFontProperties(fontdef_t *font, INT32 kerning, UINT32 spacewidth, UINT32 charwidth, UINT32 linespacing)
+{
+	font->kerning = kerning;
+	font->spacewidth = spacewidth;
+	font->charwidth = charwidth;
+	font->linespacing = linespacing;
+}
+
 // Initialise Heads up
 // once at game startup.
 //
@@ -1035,6 +999,7 @@ static void HU_sendChatMessage(void)
 void HU_clearChatChars(void)
 {
 	memset(w_chat, '\0', sizeof(w_chat));
+	I_SetTextInputMode(false);
 	chat_on = false;
 	c_input = 0;
 
@@ -1084,6 +1049,7 @@ boolean HU_Responder(event_t *ev)
 		if ((ev->key == gamecontrol[GC_TALKKEY][0] || ev->key == gamecontrol[GC_TALKKEY][1])
 			&& netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise.
 		{
+			I_SetTextInputMode(true);
 			chat_on = true;
 			chat_on_first_event = false;
 			w_chat[0] = 0;
@@ -1095,6 +1061,7 @@ boolean HU_Responder(event_t *ev)
 		if ((ev->key == gamecontrol[GC_TEAMKEY][0] || ev->key == gamecontrol[GC_TEAMKEY][1])
 			&& netgame && !OLD_MUTE)
 		{
+			I_SetTextInputMode(true);
 			chat_on = true;
 			chat_on_first_event = false;
 			w_chat[0] = 0;
@@ -1117,7 +1084,7 @@ boolean HU_Responder(event_t *ev)
 
 		if (ev->type == ev_text)
 		{
-			if ((c < HU_FONTSTART || c > HU_FONTEND || !hu_font[c-HU_FONTSTART])
+			if ((c < FONTSTART || c > FONTEND || !hu_font.chars[c-FONTSTART])
 				&& c != ' ') // Allow spaces, of course
 			{
 				return false;
@@ -1169,6 +1136,7 @@ boolean HU_Responder(event_t *ev)
 			if (!CHAT_MUTE)
 				HU_sendChatMessage();
 
+			I_SetTextInputMode(false);
 			chat_on = false;
 			c_input = 0; // reset input cursor
 			chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :)
@@ -1179,6 +1147,7 @@ boolean HU_Responder(event_t *ev)
 			|| c == gamecontrol[GC_TEAMKEY][0] || c == gamecontrol[GC_TEAMKEY][1])
 			&& c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle.
 		{
+			I_SetTextInputMode(false);
 			chat_on = false;
 			c_input = 0; // reset input cursor
 			I_UpdateMouseGrab();
@@ -1236,199 +1205,81 @@ boolean HU_Responder(event_t *ev)
 //                         HEADS UP DRAWING
 //======================================================================
 
-// Precompile a wordwrapped string to any given width.
-// This is a muuuch better method than V_WORDWRAP.
-// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
-// this one is simplified for the chat drawer.
-static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
-{
-	INT32 c;
-	size_t chw, i, lastusablespace = 0;
-	size_t slen;
-	char *newstring = Z_StrDup(string);
-	INT32 spacewidth = (vid.width < 640) ? 8 : 4, charwidth = (vid.width < 640) ? 8 : 4;
-
-	slen = strlen(string);
-	x = 0;
-
-	for (i = 0; i < slen; ++i)
-	{
-		c = newstring[i];
-		if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09
-			continue;
-
-		if (c == '\n')
-		{
-			x = 0;
-			lastusablespace = 0;
-			continue;
-		}
-
-		if (!(option & V_ALLOWLOWERCASE))
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			chw = spacewidth;
-			lastusablespace = i;
-		}
-		else
-			chw = charwidth;
-
-		x += chw;
-
-		if (lastusablespace != 0 && x > w)
-		{
-			//CONS_Printf("Wrap at index %d\n", i);
-			newstring[lastusablespace] = '\n';
-			i = lastusablespace+1;
-			lastusablespace = 0;
-			x = 0;
-		}
-	}
-	return newstring;
-}
-
-
 // 30/7/18: chaty is now the distance at which the lowest point of the chat will be drawn if that makes any sense.
 
 INT16 chatx = 13, chaty = 169; // let's use this as our coordinates
 
-// chat stuff by VincyTM LOL XD!
-
 // HU_DrawMiniChat
 
 static void HU_drawMiniChat(void)
 {
-	INT32 x = chatx+2;
+	INT32 x = chatx+2, y;
+	INT32 chatheight = 0;
 	INT32 charwidth = 4, charheight = 6;
 	INT32 boxw = cv_chatwidth.value;
 	INT32 dx = 0, dy = 0;
-	size_t i = chat_nummsg_min;
-	boolean prev_linereturn = false; // a hack to prevent double \n while I have no idea why they happen in the first place.
-
-	INT32 msglines = 0;
-	// process all messages once without rendering anything or doing anything fancy so that we know how many lines each message has...
-	INT32 y;
 
 	if (!chat_nummsg_min)
 		return; // needless to say it's useless to do anything if we don't have anything to draw.
 
-	/*if (splitscreen > 1)
-		boxw = max(64, boxw/2);*/
-
-	for (; i>0; i--)
+	for (size_t i = chat_nummsg_min; i > 0; i--)
 	{
-		char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]);
-		size_t j = 0;
-		INT32 linescount = 0;
-
-		while(msg[j]) // iterate through msg
+		char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]);
+		for(size_t j = 0; msg[j]; j++) // iterate through msg
 		{
-			if (msg[j] < HU_FONTSTART) // don't draw
-			{
-				if (msg[j] == '\n') // get back down.
-				{
-					++j;
-					if (!prev_linereturn)
-					{
-						linescount += 1;
-						dx = 0;
-					}
-					prev_linereturn = true;
-					continue;
-				}
-				else if (msg[j] & 0x80) // stolen from video.c, nice.
-				{
-					++j;
-					continue;
-				}
-
-				++j;
-			}
-			else
+			if (msg[j] == '\n') // get back down.
 			{
-				j++;
+				chatheight += charheight;
+				dx = 0;
 			}
-			prev_linereturn = false;
-			dx += charwidth;
-			if (dx >= boxw)
+			else if (msg[j] >= FONTSTART)
 			{
-				dx = 0;
-				linescount += 1;
+				dx += charwidth;
+				if (dx >= boxw)
+				{
+					dx = 0;
+					chatheight += charheight;
+				}
 			}
 		}
-		dy = 0;
 		dx = 0;
-		msglines += linescount+1;
+		chatheight += charheight;
 
 		if (msg)
 			Z_Free(msg);
 	}
 
-	y = chaty - charheight*(msglines+1);
+	y = chaty - (chatheight + charheight);
 
-	/*if (splitscreen)
+	for (size_t i = 0; i < chat_nummsg_min; i++) // iterate through our hot messages
 	{
-		y -= BASEVIDHEIGHT/2;
-		if (splitscreen > 1)
-			y += 16;
-	}*/
-
-	dx = 0;
-	dy = 0;
-	i = 0;
-	prev_linereturn = false;
-
-	for (; i<=(chat_nummsg_min-1); i++) // iterate through our hot messages
-	{
-		INT32 clrflag = 0;
 		INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below...
 		INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one.
-		size_t j = 0;
-		char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it.
+		char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it.
 		UINT8 *colormap = NULL;
 
-		while(msg[j]) // iterate through msg
+		for(size_t j = 0; msg[j]; j++) // iterate through msg
 		{
-			if (msg[j] < HU_FONTSTART) // don't draw
+			if (msg[j] == '\n') // get back down.
 			{
-				if (msg[j] == '\n') // get back down.
-				{
-					++j;
-					if (!prev_linereturn)
-					{
-						dy += charheight;
-						dx = 0;
-					}
-					prev_linereturn = true;
-					continue;
-				}
-				else if (msg[j] & 0x80) // stolen from video.c, nice.
-				{
-					clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-					colormap = V_GetStringColormap(clrflag);
-					++j;
-					continue;
-				}
-
-				++j;
+				dy += charheight;
+				dx = 0;
 			}
-			else
+			else if (msg[j] & 0x80) // get colormap
+				colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
+			else if (msg[j] >= FONTSTART)
 			{
 				if (cv_chatbacktint.value) // on request of wolfy
 					V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
 
-				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap);
-			}
+				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap);
 
-			dx += charwidth;
-			prev_linereturn = false;
-			if (dx >= boxw)
-			{
-				dx = 0;
-				dy += charheight;
+				dx += charwidth;
+				if (dx >= boxw)
+				{
+					dx = 0;
+					dy += charheight;
+				}
 			}
 		}
 		dy += charheight;
@@ -1440,7 +1291,6 @@ static void HU_drawMiniChat(void)
 
 	// decrement addy and make that shit smooth:
 	addy /= 2;
-
 }
 
 // HU_DrawChatLog
@@ -1485,44 +1335,28 @@ static void HU_drawChatLog(INT32 offset)
 
 	for (i=0; i<chat_nummsg_log; i++) // iterate through our chatlog
 	{
-		INT32 clrflag = 0;
-		INT32 j = 0;
-		char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it.
+		char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it.
 		UINT8 *colormap = NULL;
-		while(msg[j]) // iterate through msg
+		for(size_t j = 0; msg[j]; j++) // iterate through msg
 		{
-			if (msg[j] < HU_FONTSTART) // don't draw
+			if (msg[j] == '\n') // get back down.
 			{
-				if (msg[j] == '\n') // get back down.
-				{
-					++j;
-					dy += charheight;
-					dx = 0;
-					continue;
-				}
-				else if (msg[j] & 0x80) // stolen from video.c, nice.
-				{
-					clrflag = ((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-					colormap = V_GetStringColormap(clrflag);
-					++j;
-					continue;
-				}
-
-				++j;
+				dy += charheight;
+				dx = 0;
 			}
-			else
+			else if (msg[j] & 0x80) // get colormap
+				colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
+			else if (msg[j] >= FONTSTART)
 			{
 				if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
-					V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
-				else
-					j++; // don't forget to increment this or we'll get stuck in the limbo.
-			}
+					V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
 
-			dx += charwidth;
-			if (dx >= boxw-charwidth-2 && i<chat_nummsg_log && msg[j] >= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!!
-			{
-				dx = 0;
-				dy += charheight;
+				dx += charwidth;
+				if (dx >= boxw-charwidth-2 && i<chat_nummsg_log) // end of message shouldn't count, nor should invisible characters!!!!
+				{
+					dx = 0;
+					dy += charheight;
+				}
 			}
 		}
 		dy += charheight;
@@ -1532,30 +1366,25 @@ static void HU_drawChatLog(INT32 offset)
 			Z_Free(msg);
 	}
 
-
 	if (((chat_scroll >= chat_maxscroll) || (chat_scrollmedown)) && !(justscrolleddown || justscrolledup || chat_scrolltime)) // was already at the bottom of the page before new maxscroll calculation and was NOT scrolling.
-	{
 		atbottom = true; // we should scroll
-	}
+
 	chat_scrollmedown = false;
 
-	// getmaxscroll through a lazy hack. We do all these loops,
-	// so let's not do more loops that are gonna lag the game more. :P
+	// getmaxscroll through a lazy hack. We do all these loops, so let's not do more loops that are gonna lag the game more. :P
 	chat_maxscroll = max(dy / charheight - cv_chatheight.value, 0);
 
 	// if we're not bound by the time, autoscroll for next frame:
 	if (atbottom)
 		chat_scroll = chat_maxscroll;
 
-	// draw arrows to indicate that we can (or not) scroll.
-	// account for Y = -1 offset in tinyfont
+	// draw arrows to indicate that we can (or not) scroll, accounting for Y = -1 offset in tinyfont
 	if (chat_scroll > 0)
 		V_DrawThinString(chatx-8, ((justscrolledup) ? (chat_topy-1) : (chat_topy)) - 1, V_SNAPTOBOTTOM | V_SNAPTOLEFT | V_YELLOWMAP, "\x1A"); // up arrow
 	if (chat_scroll < chat_maxscroll)
 		V_DrawThinString(chatx-8, chat_bottomy-((justscrolleddown) ? 5 : 6) - 1, V_SNAPTOBOTTOM | V_SNAPTOLEFT | V_YELLOWMAP, "\x1B"); // down arrow
 
-	justscrolleddown = false;
-	justscrolledup = false;
+	justscrolleddown = justscrolledup = false;
 }
 
 //
@@ -1587,15 +1416,7 @@ static void HU_DrawChat(void)
 #endif
 
 	if (teamtalk)
-	{
 		talk = ttalk;
-#if 0
-		if (players[consoleplayer].ctfteam == 1)
-			t = 0x500;  // Red
-		else if (players[consoleplayer].ctfteam == 2)
-			t = 0x400; // Blue
-#endif
-	}
 
 	if (CHAT_MUTE)
 	{
@@ -1609,16 +1430,10 @@ static void HU_DrawChat(void)
 
 	V_DrawFillConsoleMap(chatx, y-1, boxw, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT);
 
-	while (talk[i])
+	for (i = 0; talk[i]; i++)
 	{
-		if (talk[i] < HU_FONTSTART)
-			++i;
-		else
-		{
+		if (talk[i] >= FONTSTART)
 			V_DrawChatCharacter(chatx + c + 2, y, talk[i] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|cflag, true, V_GetStringColormap(talk[i]|cflag));
-			i++;
-		}
-
 		c += charwidth;
 	}
 
@@ -1629,13 +1444,12 @@ static void HU_DrawChat(void)
 		return;
 	}
 
-	i = 0;
 	typelines = 1;
 
 	if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
 		V_DrawChatCharacter(chatx + 2 + c, y+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, true, NULL);
 
-	while (w_chat[i])
+	for (i = 0; w_chat[i]; i++)
 	{
 		boolean skippedline = false;
 		if (c_input == (i+1))
@@ -1652,14 +1466,11 @@ static void HU_DrawChat(void)
 			}
 		}
 
-		//Hurdler: isn't it better like that?
-		if (w_chat[i] < HU_FONTSTART)
-			++i;
-		else
-			V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
+		if (w_chat[i] >= FONTSTART)
+			V_DrawChatCharacter(chatx + c + 2, y, w_chat[i] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
 
 		c += charwidth;
-		if (c > boxw-(charwidth*2) && !skippedline)
+		if (c > boxw-charwidth && !skippedline)
 		{
 			c = 0;
 			y += charheight;
@@ -1681,8 +1492,7 @@ static void HU_DrawChat(void)
 		}
 #endif
 
-		i = 0;
-		for(i=0; (i<MAXPLAYERS); i++)
+		for(i=0; i<MAXPLAYERS; i++)
 		{
 			// filter: (code needs optimization pls help I'm bad with C)
 			if (w_chat[3])
@@ -1697,32 +1507,16 @@ static void HU_DrawChat(void)
 				playernum[3] = 0;
 				n = atoi(playernum); // turn that into a number
 				// special cases:
-
-				if ((n == 0) && !(w_chat[4] == '0'))
-				{
-					if (!(i<10))
-						continue;
-				}
-				else if ((n == 1) && !(w_chat[3] == '0'))
-				{
-					if (!((i == 1) || ((i >= 10) && (i <= 19))))
-						continue;
-				}
-				else if ((n == 2) && !(w_chat[3] == '0'))
-				{
-					if (!((i == 2) || ((i >= 20) && (i <= 29))))
-						continue;
-				}
-				else if ((n == 3) && !(w_chat[3] == '0'))
-				{
-					if (!((i == 3) || ((i >= 30) && (i <= 31))))
-						continue;
-				}
+				if ((n == 0) && !(w_chat[4] == '0') && (!(i<10)))
+					continue;
+				else if ((n == 1) && !(w_chat[3] == '0') && (!((i == 1) || ((i >= 10) && (i <= 19)))))
+					continue;
+				else if ((n == 2) && !(w_chat[3] == '0') && (!((i == 2) || ((i >= 20) && (i <= 29)))))
+					continue; 
+				else if ((n == 3) && !(w_chat[3] == '0') && (!((i == 3) || ((i >= 30) && (i <= 31)))))
+					continue; 
 				else	// general case.
-				{
-					if (i != n)
-						continue;
-				}
+					if (i != n) continue;
 			}
 
 			if (playeringame[i])
@@ -1753,41 +1547,22 @@ static void HU_DrawChat_Old(void)
 	size_t i = 0;
 	const char *ntalk = "Say: ", *ttalk = "Say-Team: ";
 	const char *talk = ntalk;
-	INT32 charwidth = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor;
-	INT32 charheight = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->height) * con_scalefactor;
+	INT32 charwidth = 8 * con_scalefactor, charheight = 8 * con_scalefactor;
 	if (teamtalk)
-	{
 		talk = ttalk;
-#if 0
-		if (players[consoleplayer].ctfteam == 1)
-			t = 0x500;  // Red
-		else if (players[consoleplayer].ctfteam == 2)
-			t = 0x400; // Blue
-#endif
-	}
 
-	while (talk[i])
+	for (i = 0; talk[i]; i++)
 	{
-		if (talk[i] < HU_FONTSTART)
-		{
-			++i;
-			//charwidth = 4 * con_scalefactor;
-		}
-		else
-		{
-			//charwidth = (hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor;
-			V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, true);
-		}
+		if (talk[i] >= FONTSTART)
+			V_DrawCharacter(HU_INPUTX + c, y, talk[i] | cv_constextsize.value | V_NOSCALESTART, true);
 		c += charwidth;
 	}
 
 	if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
 		V_DrawCharacter(HU_INPUTX+c, y+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
 
-	i = 0;
-	while (w_chat[i])
+	for (i = 0; w_chat[i]; i++)
 	{
-
 		if (c_input == (i+1) && hu_tick < 4)
 		{
 			INT32 cursorx = (HU_INPUTX+c+charwidth < vid.width) ? (HU_INPUTX + c + charwidth) : (HU_INPUTX); // we may have to go down.
@@ -1795,17 +1570,8 @@ static void HU_DrawChat_Old(void)
 			V_DrawCharacter(cursorx, cursory+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
 		}
 
-		//Hurdler: isn't it better like that?
-		if (w_chat[i] < HU_FONTSTART)
-		{
-			++i;
-			//charwidth = 4 * con_scalefactor;
-		}
-		else
-		{
-			//charwidth = (hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor;
-			V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, true);
-		}
+		if (w_chat[i] >= FONTSTART)
+			V_DrawCharacter(HU_INPUTX + c, y, w_chat[i] | cv_constextsize.value | V_NOSCALESTART | t, true);
 
 		c += charwidth;
 		if (c >= vid.width)
@@ -1814,9 +1580,6 @@ static void HU_DrawChat_Old(void)
 			y += charheight;
 		}
 	}
-
-	if (hu_tick < 4)
-		V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
 }
 
 // Draw crosshairs at the exact center of the view.
@@ -1902,21 +1665,6 @@ static void HU_DrawCEcho(void)
 	}
 }
 
-static void HU_drawGametype(void)
-{
-	const char *strvalue = NULL;
-
-	if (gametype < 0 || gametype >= gametypecount)
-		return; // not a valid gametype???
-
-	strvalue = Gametype_Names[gametype];
-
-	if (splitscreen)
-		V_DrawString(4, 184, 0, strvalue);
-	else
-		V_DrawString(4, 192, 0, strvalue);
-}
-
 //
 // demo info stuff
 //
@@ -2267,13 +2015,13 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		greycheck = greycheckdef;
 		supercheck = supercheckdef;
 
-		if (tab[i].color == skincolor_redteam) //red
+		if (players[tab[i].num].ctfteam == 1) //red
 		{
 			redplayers++;
 			x = 14 + (BASEVIDWIDTH/2);
 			y = (redplayers * 9) + 20;
 		}
-		else if (tab[i].color == skincolor_blueteam) //blue
+		else if (players[tab[i].num].ctfteam == 2) //blue
 		{
 			blueplayers++;
 			x = 14;
@@ -2355,7 +2103,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		if (players[tab[i].num].spectator)
 			continue; //ignore them.
 
-		if (tab[i].color == skincolor_redteam) //red
+		if (players[tab[i].num].ctfteam == 1) //red
 		{
 			if (redplayers++ > 8)
 			{
@@ -2363,7 +2111,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 				break; // don't make more loops than we need to.
 			}
 		}
-		else if (tab[i].color == skincolor_blueteam) //blue
+		else if (players[tab[i].num].ctfteam == 2) //blue
 		{
 			if (blueplayers++ > 8)
 			{
@@ -2394,14 +2142,14 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		if (players[tab[i].num].spectator)
 			continue; //ignore them.
 
-		if (tab[i].color == skincolor_redteam) //red
+		if (players[tab[i].num].ctfteam == 1) //red
 		{
 			if (redplayers++ > 8)
 				continue;
 			x = 32 + (BASEVIDWIDTH/2);
 			y = (redplayers * 16) + 16;
 		}
-		else if (tab[i].color == skincolor_blueteam) //blue
+		else if (players[tab[i].num].ctfteam == 2) //blue
 		{
 			if (blueplayers++ > 8)
 				continue;
@@ -2778,7 +2526,8 @@ static void HU_DrawRankings(void)
 	UINT32 whiteplayer;
 
 	// draw the current gametype in the lower right
-	HU_drawGametype();
+	if (gametype >= 0 && gametype < gametypecount)
+		V_DrawString(4, splitscreen ? 184 : 192, 0, Gametype_Names[gametype]);
 
 	if (gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT))
 	{
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index 9ca50e6e1b49e2b0f45b4e5d71a1fe70641693ca..ca77ed93002750d6cefa28584d8e4de7be3bfc65 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -19,33 +19,34 @@
 #include "r_defs.h"
 
 //------------------------------------
-//           heads up font
+//           Fonts & stuff
 //------------------------------------
-#define HU_FONTSTART '\x16' // the first font character
-#define HU_FONTEND '~'
-
-#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
-
-// Level title font
-#define LT_FONTSTART '!' // the first font characters
-#define LT_FONTEND 'z' // the last font characters
-#define LT_FONTSIZE (LT_FONTEND - LT_FONTSTART + 1)
-
-#define CRED_FONTSTART '!' // the first font character
-#define CRED_FONTEND 'Z' // the last font character
-#define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1)
-
-// Name tag font
-// Used by base and outline font set
-#define NT_FONTSTART '!' // the first font character
-#define NT_FONTEND 'Z' // the last font character
-#define NT_FONTSIZE (NT_FONTEND - NT_FONTSTART + 1)
+#define FONTSTART '\x16' // the first font character
+#define FONTEND '~'
+#define FONTSIZE (FONTEND - FONTSTART + 1)
 
 #define HU_CROSSHAIRS 3 // maximum of 9 - see HU_Init();
 
 extern char *shiftxform; // english translation shift table
 extern char english_shiftxform[];
 
+typedef struct
+{
+	patch_t *chars[FONTSIZE];
+	INT32 kerning;
+	UINT32 spacewidth;
+	UINT32 charwidth;
+	UINT32 linespacing;
+} fontdef_t;
+
+extern fontdef_t hu_font, tny_font, cred_font, lt_font;
+extern fontdef_t ntb_font, nto_font;
+extern patch_t *tallnum[10];
+extern patch_t *nightsnum[10];
+extern patch_t *ttlnum[10];
+extern patch_t *tallminus;
+extern patch_t *tallinfin;
+
 //------------------------------------
 //        sorted player lines
 //------------------------------------
@@ -78,22 +79,12 @@ void HU_AddChatText(const char *text, boolean playsound);
 // set true when entering a chat message
 extern boolean chat_on;
 
-extern patch_t *hu_font[HU_FONTSIZE], *tny_font[HU_FONTSIZE];
-extern patch_t *tallnum[10];
-extern patch_t *nightsnum[10];
-extern patch_t *lt_font[LT_FONTSIZE];
-extern patch_t *cred_font[CRED_FONTSIZE];
-extern patch_t *ntb_font[NT_FONTSIZE];
-extern patch_t *nto_font[NT_FONTSIZE];
-extern patch_t *ttlnum[10];
 extern patch_t *emeraldpics[3][8];
 extern patch_t *rflagico;
 extern patch_t *bflagico;
 extern patch_t *rmatcico;
 extern patch_t *bmatcico;
 extern patch_t *tagico;
-extern patch_t *tallminus;
-extern patch_t *tallinfin;
 extern patch_t *tokenicon;
 
 // set true whenever the tab rankings are being shown for any reason
@@ -103,6 +94,8 @@ extern boolean hu_showscores;
 void HU_Init(void);
 
 void HU_LoadGraphics(void);
+void HU_LoadFontCharacters(fontdef_t *font, const char *prefix);
+void HU_SetFontProperties(fontdef_t *font, INT32 kerning, UINT32 spacewidth, UINT32 charwidth, UINT32 linespacing);
 
 // reset heads up when consoleplayer respawns.
 void HU_Start(void);
diff --git a/src/i_system.h b/src/i_system.h
index 3f0e05d127fa4ed5ce9aa8fbe89ff109773851f4..f4d169113c50b0ae5e2c1aca53b4d04f128658f4 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -339,4 +339,12 @@ void I_SetMouseGrab(boolean grab);
 */
 const char *I_GetSysName(void);
 
+/** \brief Sets text input mode. When enabled, keyboard inputs will respect dead keys.
+ */
+void I_SetTextInputMode(boolean active);
+
+/** \brief Retrieves current text input mode.
+ */
+boolean I_GetTextInputMode(void);
+
 #endif
diff --git a/src/info.c b/src/info.c
index 8dd1aac80679d17ae21b0fe43ad6b042d35ed627..d66c24af81aaafb851e6a83e699d2027add29cb5 100644
--- a/src/info.c
+++ b/src/info.c
@@ -26,9 +26,10 @@
 #include "hardware/hw_light.h"
 #endif
 
+
 // Hey, moron! If you change this table, don't forget about the sprite enum in info.h and the sprite lights in hw_light.c!
 // For the sake of constant merge conflicts, let's spread this out
-char sprnames[NUMSPRITES + 1][5] =
+char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1] =
 {
 	"NULL", // invisible object
 	"UNKN",
@@ -525,7 +526,7 @@ char sprnames[NUMSPRITES + 1][5] =
 	"GWLR",
 };
 
-char spr2names[NUMPLAYERSPRITES][5] =
+char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1] =
 {
 	"STND",
 	"WAIT",
@@ -691,3309 +692,3309 @@ state_t states[NUMSTATES] =
 	// (or tr_trans10<<FF_TRANSSHIFT if you want to make it hard on yourself)
 
 	// Keep this comment directly above S_NULL.
-	{SPR_NULL, 0,  1, {NULL}, 0, 0, S_NULL}, // S_NULL
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_UNKNOWN
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_INVISIBLE
-
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 0, 0, S_NULL}, // S_SPAWNSTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 1, 0, S_NULL}, // S_SEESTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 2, 0, S_NULL}, // S_MELEESTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 3, 0, S_NULL}, // S_MISSILESTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 4, 0, S_NULL}, // S_DEATHSTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 5, 0, S_NULL}, // S_XDEATHSTATE
-	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL}, // S_RAISESTATE
+	{SPR_NULL, 0,  1, {NULL}, 0, 0, S_NULL, 0}, // S_NULL
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_UNKNOWN
+	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_INVISIBLE
+
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 0, 0, S_NULL, 0}, // S_SPAWNSTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 1, 0, S_NULL, 0}, // S_SEESTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 2, 0, S_NULL, 0}, // S_MELEESTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 3, 0, S_NULL, 0}, // S_MISSILESTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 4, 0, S_NULL, 0}, // S_DEATHSTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 5, 0, S_NULL, 0}, // S_XDEATHSTATE
+	{SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL, 0}, // S_RAISESTATE
 
 	// Thok
-	{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_THOK
+	{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL, 0}, // S_THOK
 
 	// Player
-	{SPR_PLAY, SPR2_STND|FF_ANIMATE,    105, {NULL}, 0,  7, S_PLAY_WAIT}, // S_PLAY_STND
-	{SPR_PLAY, SPR2_WAIT|FF_ANIMATE,     -1, {NULL}, 0, 16, S_NULL},      // S_PLAY_WAIT
-	{SPR_PLAY, SPR2_WALK,                 4, {NULL}, 0,  0, S_PLAY_WALK}, // S_PLAY_WALK
-	{SPR_PLAY, SPR2_SKID,                 1, {NULL}, 0,  0, S_PLAY_WALK}, // S_PLAY_SKID
-	{SPR_PLAY, SPR2_RUN ,                 2, {NULL}, 0,  0, S_PLAY_RUN},  // S_PLAY_RUN
-	{SPR_PLAY, SPR2_DASH,                 2, {NULL}, 0,  0, S_PLAY_DASH}, // S_PLAY_DASH
-	{SPR_PLAY, SPR2_PAIN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL}, // S_PLAY_PAIN
-	{SPR_PLAY, SPR2_STUN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL}, // S_PLAY_STUN
-	{SPR_PLAY, SPR2_DEAD|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL},      // S_PLAY_DEAD
-	{SPR_PLAY, SPR2_DRWN|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL},      // S_PLAY_DRWN
-	{SPR_PLAY, SPR2_ROLL,                 1, {NULL}, 0,  0, S_PLAY_ROLL}, // S_PLAY_ROLL
-	{SPR_PLAY, SPR2_GASP|FF_ANIMATE,     14, {NULL}, 0,  4, S_PLAY_WALK}, // S_PLAY_GASP
-	{SPR_PLAY, SPR2_JUMP,                 1, {NULL}, 0,  0, S_PLAY_JUMP}, // S_PLAY_JUMP
-	{SPR_PLAY, SPR2_SPNG,                 2, {NULL}, 0,  0, S_PLAY_SPRING}, // S_PLAY_SPRING
-	{SPR_PLAY, SPR2_FALL,                 2, {NULL}, 0,  0, S_PLAY_FALL}, // S_PLAY_FALL
-	{SPR_PLAY, SPR2_EDGE,                12, {NULL}, 0,  0, S_PLAY_EDGE}, // S_PLAY_EDGE
-	{SPR_PLAY, SPR2_RIDE,                 4, {NULL}, 0,  0, S_PLAY_RIDE}, // S_PLAY_RIDE
+	{SPR_PLAY, SPR2_STND|FF_ANIMATE,    105, {NULL}, 0,  7, S_PLAY_WAIT, 0}, // S_PLAY_STND
+	{SPR_PLAY, SPR2_WAIT|FF_ANIMATE,     -1, {NULL}, 0, 16, S_NULL, 0},      // S_PLAY_WAIT
+	{SPR_PLAY, SPR2_WALK,                 4, {NULL}, 0,  0, S_PLAY_WALK, 0}, // S_PLAY_WALK
+	{SPR_PLAY, SPR2_SKID,                 1, {NULL}, 0,  0, S_PLAY_WALK, 0}, // S_PLAY_SKID
+	{SPR_PLAY, SPR2_RUN ,                 2, {NULL}, 0,  0, S_PLAY_RUN, 0},  // S_PLAY_RUN
+	{SPR_PLAY, SPR2_DASH,                 2, {NULL}, 0,  0, S_PLAY_DASH, 0}, // S_PLAY_DASH
+	{SPR_PLAY, SPR2_PAIN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL, 0}, // S_PLAY_PAIN
+	{SPR_PLAY, SPR2_STUN|FF_ANIMATE,    350, {NULL}, 0,  4, S_PLAY_FALL, 0}, // S_PLAY_STUN
+	{SPR_PLAY, SPR2_DEAD|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL, 0},      // S_PLAY_DEAD
+	{SPR_PLAY, SPR2_DRWN|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL, 0},      // S_PLAY_DRWN
+	{SPR_PLAY, SPR2_ROLL,                 1, {NULL}, 0,  0, S_PLAY_ROLL, 0}, // S_PLAY_ROLL
+	{SPR_PLAY, SPR2_GASP|FF_ANIMATE,     14, {NULL}, 0,  4, S_PLAY_WALK, 0}, // S_PLAY_GASP
+	{SPR_PLAY, SPR2_JUMP,                 1, {NULL}, 0,  0, S_PLAY_JUMP, 0}, // S_PLAY_JUMP
+	{SPR_PLAY, SPR2_SPNG,                 2, {NULL}, 0,  0, S_PLAY_SPRING, 0}, // S_PLAY_SPRING
+	{SPR_PLAY, SPR2_FALL,                 2, {NULL}, 0,  0, S_PLAY_FALL, 0}, // S_PLAY_FALL
+	{SPR_PLAY, SPR2_EDGE,                12, {NULL}, 0,  0, S_PLAY_EDGE, 0}, // S_PLAY_EDGE
+	{SPR_PLAY, SPR2_RIDE,                 4, {NULL}, 0,  0, S_PLAY_RIDE, 0}, // S_PLAY_RIDE
 
 	// CA2_SPINDASH
-	{SPR_PLAY, SPR2_SPIN,                 2, {NULL}, 0,  0, S_PLAY_SPINDASH}, // S_PLAY_SPINDASH
+	{SPR_PLAY, SPR2_SPIN,                 2, {NULL}, 0,  0, S_PLAY_SPINDASH, 0}, // S_PLAY_SPINDASH
 
 	// CA_FLY/CA_SWIM
-	{SPR_PLAY, SPR2_FLY ,                 2, {NULL}, 0,  0, S_PLAY_FLY},  // S_PLAY_FLY
-	{SPR_PLAY, SPR2_SWIM,                 4, {NULL}, 0,  0, S_PLAY_SWIM}, // S_PLAY_SWIM
-	{SPR_PLAY, SPR2_TIRE,                12, {NULL}, 0,  0, S_PLAY_FLY_TIRED}, // S_PLAY_FLY_TIRED
+	{SPR_PLAY, SPR2_FLY ,                 2, {NULL}, 0,  0, S_PLAY_FLY, 0},  // S_PLAY_FLY
+	{SPR_PLAY, SPR2_SWIM,                 4, {NULL}, 0,  0, S_PLAY_SWIM, 0}, // S_PLAY_SWIM
+	{SPR_PLAY, SPR2_TIRE,                12, {NULL}, 0,  0, S_PLAY_FLY_TIRED, 0}, // S_PLAY_FLY_TIRED
 
 	// CA_GLIDEANDCLIMB
-	{SPR_PLAY, SPR2_GLID,                 2, {NULL}, 0,  0, S_PLAY_GLIDE}, // S_PLAY_GLIDE
-	{SPR_PLAY, SPR2_LAND,                 7, {NULL}, 0,  0, S_PLAY_STND},  // S_PLAY_GLIDE_LANDING
-	{SPR_PLAY, SPR2_CLNG|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL},       // S_PLAY_CLING
-	{SPR_PLAY, SPR2_CLMB,                 5, {NULL}, 0,  0, S_PLAY_CLIMB}, // S_PLAY_CLIMB
+	{SPR_PLAY, SPR2_GLID,                 2, {NULL}, 0,  0, S_PLAY_GLIDE, 0}, // S_PLAY_GLIDE
+	{SPR_PLAY, SPR2_LAND,                 7, {NULL}, 0,  0, S_PLAY_STND, 0},  // S_PLAY_GLIDE_LANDING
+	{SPR_PLAY, SPR2_CLNG|FF_ANIMATE,     -1, {NULL}, 0,  4, S_NULL, 0},       // S_PLAY_CLING
+	{SPR_PLAY, SPR2_CLMB,                 5, {NULL}, 0,  0, S_PLAY_CLIMB, 0}, // S_PLAY_CLIMB
 
 	// CA_FLOAT/CA_SLOWFALL
-	{SPR_PLAY, SPR2_FLT ,                 7, {NULL}, 0,  0, S_PLAY_FLOAT}, // S_PLAY_FLOAT
-	{SPR_PLAY, SPR2_FRUN,                 7, {NULL}, 0,  0, S_PLAY_FLOAT_RUN},  // S_PLAY_FLOAT_RUN
+	{SPR_PLAY, SPR2_FLT ,                 7, {NULL}, 0,  0, S_PLAY_FLOAT, 0}, // S_PLAY_FLOAT
+	{SPR_PLAY, SPR2_FRUN,                 7, {NULL}, 0,  0, S_PLAY_FLOAT_RUN, 0},  // S_PLAY_FLOAT_RUN
 
 	// CA_BOUNCE
-	{SPR_PLAY, SPR2_BNCE|FF_ANIMATE,     -1, {NULL},             0,  0, S_NULL},                // S_PLAY_BOUNCE
-	{SPR_PLAY, SPR2_LAND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE,  0, S_PLAY_BOUNCE_LANDING}, // S_PLAY_BOUNCE_LANDING
+	{SPR_PLAY, SPR2_BNCE|FF_ANIMATE,     -1, {NULL},             0,  0, S_NULL, 0},                // S_PLAY_BOUNCE
+	{SPR_PLAY, SPR2_LAND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE,  0, S_PLAY_BOUNCE_LANDING, 0}, // S_PLAY_BOUNCE_LANDING
 
 	// CA2_GUNSLINGER
-	{SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE,  2, {NULL}, S_PLAY_FIRE_FINISH, 0, S_PLAY_FIRE},   // S_PLAY_FIRE
-	{SPR_PLAY, SPR2_FIRE,                 15, {NULL},        S_PLAY_STND, 0, S_PLAY_STND},   // S_PLAY_FIRE_FINISH
+	{SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE,  2, {NULL}, S_PLAY_FIRE_FINISH, 0, S_PLAY_FIRE, 0},   // S_PLAY_FIRE
+	{SPR_PLAY, SPR2_FIRE,                 15, {NULL},        S_PLAY_STND, 0, S_PLAY_STND, 0},   // S_PLAY_FIRE_FINISH
 
 	// CA_TWINSPIN
-	{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN
+	{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN, 0}, // S_PLAY_TWINSPIN
 
 	// CA2_MELEE
-	{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
-	{SPR_PLAY, SPR2_MLEE,                70, {NULL},                   0, 0, S_PLAY_FALL},  // S_PLAY_MELEE_FINISH
-	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK},  // S_PLAY_MELEE_LANDING
+	{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE, 0}, // S_PLAY_MELEE
+	{SPR_PLAY, SPR2_MLEE,                70, {NULL},                   0, 0, S_PLAY_FALL, 0},  // S_PLAY_MELEE_FINISH
+	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK, 0},  // S_PLAY_MELEE_LANDING
 
 	// SF_SUPER
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS1
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3}, // S_PLAY_SUPER_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4}, // S_PLAY_SUPER_TRANS3
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5}, // S_PLAY_SUPER_TRANS4
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6}, // S_PLAY_SUPER_TRANS5
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL},         // S_PLAY_SUPER_TRANS6
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_SUPER_TRANS2, 0}, // S_PLAY_SUPER_TRANS1
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3, 0}, // S_PLAY_SUPER_TRANS2
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4, 0}, // S_PLAY_SUPER_TRANS3
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5, 0}, // S_PLAY_SUPER_TRANS4
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6, 0}, // S_PLAY_SUPER_TRANS5
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL, 0},         // S_PLAY_SUPER_TRANS6
 
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY
+	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY, 0}, //S_OBJPLACE_DUMMY
 
 	// 1-Up box sprites (uses player sprite)
-	{SPR_PLAY, SPR2_LIFE,  2, {NULL}, 0, 18, S_PLAY_BOX2},  // S_PLAY_BOX1
-	{SPR_NULL,         0,  1, {NULL}, 0, 18, S_PLAY_BOX1},  // S_PLAY_BOX2
-	{SPR_PLAY, SPR2_LIFE,  4, {NULL}, 0,  4, S_PLAY_ICON2}, // S_PLAY_ICON1
-	{SPR_NULL,         0, 12, {NULL}, 0,  4, S_PLAY_ICON3}, // S_PLAY_ICON2
-	{SPR_PLAY, SPR2_LIFE, 20, {NULL}, 0,  4, S_NULL},       // S_PLAY_ICON3
+	{SPR_PLAY, SPR2_LIFE,  2, {NULL}, 0, 18, S_PLAY_BOX2, 0},  // S_PLAY_BOX1
+	{SPR_NULL,         0,  1, {NULL}, 0, 18, S_PLAY_BOX1, 0},  // S_PLAY_BOX2
+	{SPR_PLAY, SPR2_LIFE,  4, {NULL}, 0,  4, S_PLAY_ICON2, 0}, // S_PLAY_ICON1
+	{SPR_NULL,         0, 12, {NULL}, 0,  4, S_PLAY_ICON3, 0}, // S_PLAY_ICON2
+	{SPR_PLAY, SPR2_LIFE, 20, {NULL}, 0,  4, S_NULL, 0},       // S_PLAY_ICON3
 
 	// Level end sign (uses player sprite)
-	{SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 2, {NULL}, 0, 29, S_PLAY_SIGN},         // S_PLAY_SIGN
+	{SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 2, {NULL}, 0, 29, S_PLAY_SIGN, 0},         // S_PLAY_SIGN
 
 	// NiGHTS Player, transforming
-	{SPR_PLAY, SPR2_TRNS|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_NIGHTS_TRANS2}, // S_PLAY_NIGHTS_TRANS1
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS3}, // S_PLAY_NIGHTS_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS4}, // S_PLAY_NIGHTS_TRANS3
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS5}, // S_PLAY_NIGHTS_TRANS4
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS6}, // S_PLAY_NIGHTS_TRANS5
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 21, {A_FadeOverlay}, 2, 0, S_PLAY_NIGHTS_FLOAT},  // S_PLAY_NIGHTS_TRANS5
+	{SPR_PLAY, SPR2_TRNS|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_NIGHTS_TRANS2, 0}, // S_PLAY_NIGHTS_TRANS1
+	{SPR_PLAY, SPR2_TRNS,                3, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS3, 0}, // S_PLAY_NIGHTS_TRANS2
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS4, 0}, // S_PLAY_NIGHTS_TRANS3
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS5, 0}, // S_PLAY_NIGHTS_TRANS4
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS6, 0}, // S_PLAY_NIGHTS_TRANS5
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 21, {A_FadeOverlay}, 2, 0, S_PLAY_NIGHTS_FLOAT, 0},  // S_PLAY_NIGHTS_TRANS5
 
 	// NiGHTS Player
-	{SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND},  // S_PLAY_NIGHTS_STAND
-	{SPR_PLAY, SPR2_NFLT, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_FLOAT},  // S_PLAY_NIGHTS_FLOAT
-	{SPR_PLAY, SPR2_NFLY, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY},    // S_PLAY_NIGHTS_FLY
-	{SPR_PLAY, SPR2_NDRL, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL},  // S_PLAY_NIGHTS_DRILL
-	{SPR_PLAY, SPR2_NSTN, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_STUN},   // S_PLAY_NIGHTS_STUN
-	{SPR_PLAY, SPR2_NPUL, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_PULL},   // S_PLAY_NIGHTS_PULL
-	{SPR_PLAY, SPR2_NATK, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_ATTACK}, // S_PLAY_NIGHTS_ATTACK
+	{SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND, 0},  // S_PLAY_NIGHTS_STAND
+	{SPR_PLAY, SPR2_NFLT, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_FLOAT, 0},  // S_PLAY_NIGHTS_FLOAT
+	{SPR_PLAY, SPR2_NFLY, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY, 0},    // S_PLAY_NIGHTS_FLY
+	{SPR_PLAY, SPR2_NDRL, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL, 0},  // S_PLAY_NIGHTS_DRILL
+	{SPR_PLAY, SPR2_NSTN, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_STUN, 0},   // S_PLAY_NIGHTS_STUN
+	{SPR_PLAY, SPR2_NPUL, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_PULL, 0},   // S_PLAY_NIGHTS_PULL
+	{SPR_PLAY, SPR2_NATK, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_ATTACK, 0}, // S_PLAY_NIGHTS_ATTACK
 
 	// c:
-	{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART,  5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND}, // S_TAILSOVERLAY_STAND
-	{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES}, // S_TAILSOVERLAY_0DEGREES
-	{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES}, // S_TAILSOVERLAY_PLUS30DEGREES
-	{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES}, // S_TAILSOVERLAY_PLUS60DEGREES
-	{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES}, // S_TAILSOVERLAY_MINUS30DEGREES
-	{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES}, // S_TAILSOVERLAY_MINUS60DEGREES
-	{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_RUN}, // S_TAILSOVERLAY_RUN
-	{SPR_PLAY, SPR2_TAL7|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_FLY}, // S_TAILSOVERLAY_FLY
-	{SPR_PLAY, SPR2_TAL8|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_TIRE}, // S_TAILSOVERLAY_TIRE
-	{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN}, // S_TAILSOVERLAY_PAIN
-	{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP
-	{SPR_PLAY, SPR2_TALB                , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE
-	{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH}, // S_TAILSOVERLAY_DASH
+	{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART,  5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND, 0}, // S_TAILSOVERLAY_STAND
+	{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES, 0}, // S_TAILSOVERLAY_0DEGREES
+	{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES, 0}, // S_TAILSOVERLAY_PLUS30DEGREES
+	{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES, 0}, // S_TAILSOVERLAY_PLUS60DEGREES
+	{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES, 0}, // S_TAILSOVERLAY_MINUS30DEGREES
+	{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES, 0}, // S_TAILSOVERLAY_MINUS60DEGREES
+	{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_RUN, 0}, // S_TAILSOVERLAY_RUN
+	{SPR_PLAY, SPR2_TAL7|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_FLY, 0}, // S_TAILSOVERLAY_FLY
+	{SPR_PLAY, SPR2_TAL8|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_TIRE, 0}, // S_TAILSOVERLAY_TIRE
+	{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN, 0}, // S_TAILSOVERLAY_PAIN
+	{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP, 0}, // S_TAILSOVERLAY_GASP
+	{SPR_PLAY, SPR2_TALB                , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE, 0}, // S_TAILSOVERLAY_EDGE
+	{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH, 0}, // S_TAILSOVERLAY_DASH
 
 	// [:
-	{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH
+	{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1, 0}, // S_JETFUMEFLASH
 
 	// Blue Crawla
-	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND},   // S_POSS_STND
-	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2},   // S_POSS_RUN1
-	{SPR_POSS, 1, 3, {A_Chase}, 0, 0, S_POSS_RUN3},   // S_POSS_RUN2
-	{SPR_POSS, 2, 3, {A_Chase}, 0, 0, S_POSS_RUN4},   // S_POSS_RUN3
-	{SPR_POSS, 3, 3, {A_Chase}, 0, 0, S_POSS_RUN5},   // S_POSS_RUN4
-	{SPR_POSS, 4, 3, {A_Chase}, 0, 0, S_POSS_RUN6},   // S_POSS_RUN5
-	{SPR_POSS, 5, 3, {A_Chase}, 0, 0, S_POSS_RUN1},   // S_POSS_RUN6
+	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND, 0},   // S_POSS_STND
+	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2, 0},   // S_POSS_RUN1
+	{SPR_POSS, 1, 3, {A_Chase}, 0, 0, S_POSS_RUN3, 0},   // S_POSS_RUN2
+	{SPR_POSS, 2, 3, {A_Chase}, 0, 0, S_POSS_RUN4, 0},   // S_POSS_RUN3
+	{SPR_POSS, 3, 3, {A_Chase}, 0, 0, S_POSS_RUN5, 0},   // S_POSS_RUN4
+	{SPR_POSS, 4, 3, {A_Chase}, 0, 0, S_POSS_RUN6, 0},   // S_POSS_RUN5
+	{SPR_POSS, 5, 3, {A_Chase}, 0, 0, S_POSS_RUN1, 0},   // S_POSS_RUN6
 
 	// Red Crawla
-	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND},   // S_SPOS_STND
-	{SPR_SPOS, 0, 1, {A_Chase}, 0, 0, S_SPOS_RUN2},   // S_SPOS_RUN1
-	{SPR_SPOS, 1, 1, {A_Chase}, 0, 0, S_SPOS_RUN3},   // S_SPOS_RUN2
-	{SPR_SPOS, 2, 1, {A_Chase}, 0, 0, S_SPOS_RUN4},   // S_SPOS_RUN3
-	{SPR_SPOS, 3, 1, {A_Chase}, 0, 0, S_SPOS_RUN5},   // S_SPOS_RUN4
-	{SPR_SPOS, 4, 1, {A_Chase}, 0, 0, S_SPOS_RUN6},   // S_SPOS_RUN5
-	{SPR_SPOS, 5, 1, {A_Chase}, 0, 0, S_SPOS_RUN1},   // S_SPOS_RUN6
+	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND, 0},   // S_SPOS_STND
+	{SPR_SPOS, 0, 1, {A_Chase}, 0, 0, S_SPOS_RUN2, 0},   // S_SPOS_RUN1
+	{SPR_SPOS, 1, 1, {A_Chase}, 0, 0, S_SPOS_RUN3, 0},   // S_SPOS_RUN2
+	{SPR_SPOS, 2, 1, {A_Chase}, 0, 0, S_SPOS_RUN4, 0},   // S_SPOS_RUN3
+	{SPR_SPOS, 3, 1, {A_Chase}, 0, 0, S_SPOS_RUN5, 0},   // S_SPOS_RUN4
+	{SPR_SPOS, 4, 1, {A_Chase}, 0, 0, S_SPOS_RUN6, 0},   // S_SPOS_RUN5
+	{SPR_SPOS, 5, 1, {A_Chase}, 0, 0, S_SPOS_RUN1, 0},   // S_SPOS_RUN6
 
 	// Greenflower Fish
-	{SPR_FISH, 1, 1, {NULL}, 0, 0, S_FISH2},         // S_FISH1
-	{SPR_FISH, 1, 1, {A_FishJump}, 0, 0, S_FISH1},   // S_FISH2
-	{SPR_FISH, 0, 1, {NULL}, 0, 0, S_FISH4},         // S_FISH3
-	{SPR_FISH, 0, 1, {A_FishJump}, 0, 0, S_FISH3},   // S_FISH4
+	{SPR_FISH, 1, 1, {NULL}, 0, 0, S_FISH2, 0},         // S_FISH1
+	{SPR_FISH, 1, 1, {A_FishJump}, 0, 0, S_FISH1, 0},   // S_FISH2
+	{SPR_FISH, 0, 1, {NULL}, 0, 0, S_FISH4, 0},         // S_FISH3
+	{SPR_FISH, 0, 1, {A_FishJump}, 0, 0, S_FISH3, 0},   // S_FISH4
 
 	// Gold Buzz
-	{SPR_BUZZ, 0, 2, {A_Look}, 0, 0, S_BUZZLOOK2},   // S_BUZZLOOK1
-	{SPR_BUZZ, 1, 2, {A_Look}, 0, 0, S_BUZZLOOK1},   // S_BUZZLOOK2
-	{SPR_BUZZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_BUZZFLY2}, // S_BUZZFLY1
-	{SPR_BUZZ, 1, 2, {A_BuzzFly}, 0, 0, S_BUZZFLY1}, // S_BUZZFLY2
+	{SPR_BUZZ, 0, 2, {A_Look}, 0, 0, S_BUZZLOOK2, 0},   // S_BUZZLOOK1
+	{SPR_BUZZ, 1, 2, {A_Look}, 0, 0, S_BUZZLOOK1, 0},   // S_BUZZLOOK2
+	{SPR_BUZZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_BUZZFLY2, 0}, // S_BUZZFLY1
+	{SPR_BUZZ, 1, 2, {A_BuzzFly}, 0, 0, S_BUZZFLY1, 0}, // S_BUZZFLY2
 
 	// Red Buzz
-	{SPR_RBUZ, 0, 2, {A_Look}, 0, 0, S_RBUZZLOOK2},   // S_RBUZZLOOK1
-	{SPR_RBUZ, 1, 2, {A_Look}, 0, 0, S_RBUZZLOOK1},   // S_RBUZZLOOK2
-	{SPR_RBUZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_RBUZZFLY2}, // S_RBUZZFLY1
-	{SPR_RBUZ, 1, 2, {A_BuzzFly}, 0, 0, S_RBUZZFLY1}, // S_RBUZZFLY2
+	{SPR_RBUZ, 0, 2, {A_Look}, 0, 0, S_RBUZZLOOK2, 0},   // S_RBUZZLOOK1
+	{SPR_RBUZ, 1, 2, {A_Look}, 0, 0, S_RBUZZLOOK1, 0},   // S_RBUZZLOOK2
+	{SPR_RBUZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_RBUZZFLY2, 0}, // S_RBUZZFLY1
+	{SPR_RBUZ, 1, 2, {A_BuzzFly}, 0, 0, S_RBUZZFLY1, 0}, // S_RBUZZFLY2
 
 	// Jetty-Syn Bomber
-	{SPR_JETB, 0, 4, {A_Look}, 0, 0, S_JETBLOOK2},      // S_JETBLOOK1
-	{SPR_JETB, 1, 4, {A_Look}, 0, 0, S_JETBLOOK1},      // S_JETBLOOK2
-	{SPR_JETB, 0, 1, {A_JetbThink}, 0, 0, S_JETBZOOM2}, // S_JETBZOOM1
-	{SPR_JETB, 1, 1, {A_JetbThink}, 0, 0, S_JETBZOOM1}, // S_JETBZOOM2
+	{SPR_JETB, 0, 4, {A_Look}, 0, 0, S_JETBLOOK2, 0},      // S_JETBLOOK1
+	{SPR_JETB, 1, 4, {A_Look}, 0, 0, S_JETBLOOK1, 0},      // S_JETBLOOK2
+	{SPR_JETB, 0, 1, {A_JetbThink}, 0, 0, S_JETBZOOM2, 0}, // S_JETBZOOM1
+	{SPR_JETB, 1, 1, {A_JetbThink}, 0, 0, S_JETBZOOM1, 0}, // S_JETBZOOM2
 
 	// Jetty-Syn Gunner
-	{SPR_JETG, 0, 4, {A_Look}, 0, 0, S_JETGLOOK2},       // S_JETGLOOK1
-	{SPR_JETG, 1, 4, {A_Look}, 0, 0, S_JETGLOOK1},       // S_JETGLOOK2
-	{SPR_JETG, 0, 1, {A_JetgThink}, 0, 0, S_JETGZOOM2},  // S_JETGZOOM1
-	{SPR_JETG, 1, 1, {A_JetgThink}, 0, 0, S_JETGZOOM1},  // S_JETGZOOM2
-	{SPR_JETG, 2, 1, {A_JetgShoot}, 0, 0, S_JETGSHOOT2}, // S_JETGSHOOT1
-	{SPR_JETG, 3, 1, {NULL}, 0, 0, S_JETGZOOM1},         // S_JETGSHOOT2
+	{SPR_JETG, 0, 4, {A_Look}, 0, 0, S_JETGLOOK2, 0},       // S_JETGLOOK1
+	{SPR_JETG, 1, 4, {A_Look}, 0, 0, S_JETGLOOK1, 0},       // S_JETGLOOK2
+	{SPR_JETG, 0, 1, {A_JetgThink}, 0, 0, S_JETGZOOM2, 0},  // S_JETGZOOM1
+	{SPR_JETG, 1, 1, {A_JetgThink}, 0, 0, S_JETGZOOM1, 0},  // S_JETGZOOM2
+	{SPR_JETG, 2, 1, {A_JetgShoot}, 0, 0, S_JETGSHOOT2, 0}, // S_JETGSHOOT1
+	{SPR_JETG, 3, 1, {NULL}, 0, 0, S_JETGZOOM1, 0},         // S_JETGSHOOT2
 
 	// Crawla Commander
-	{SPR_CCOM, 0, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND2}, // S_CCOMMAND1
-	{SPR_CCOM, 1, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND1}, // S_CCOMMAND2
-	{SPR_CCOM, 2, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND4}, // S_CCOMMAND3
-	{SPR_CCOM, 3, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND3}, // S_CCOMMAND4
+	{SPR_CCOM, 0, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND2, 0}, // S_CCOMMAND1
+	{SPR_CCOM, 1, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND1, 0}, // S_CCOMMAND2
+	{SPR_CCOM, 2, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND4, 0}, // S_CCOMMAND3
+	{SPR_CCOM, 3, 1, {A_CrawlaCommanderThink}, 0, 15*FRACUNIT, S_CCOMMAND3, 0}, // S_CCOMMAND4
 
 	// Deton
-	{SPR_DETN, 0, 35, {A_Look}, 0, 0, S_DETON1},       // S_DETON1
-	{SPR_DETN, 0,  1, {A_DetonChase}, 0, 0, S_DETON3},  // S_DETON2
-	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON4},  // S_DETON3
-	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON5},  // S_DETON4
-	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON6},  // S_DETON5
-	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON7},  // S_DETON6
-	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON8},  // S_DETON7
-	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON9},  // S_DETON8
-	{SPR_DETN, 7,  1, {A_DetonChase}, 0, 0, S_DETON10}, // S_DETON9
-	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON11}, // S_DETON10
-	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON12}, // S_DETON11
-	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON13}, // S_DETON12
-	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON14}, // S_DETON13
-	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON15}, // S_DETON14
-	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON2},  // S_DETON15
+	{SPR_DETN, 0, 35, {A_Look}, 0, 0, S_DETON1, 0},       // S_DETON1
+	{SPR_DETN, 0,  1, {A_DetonChase}, 0, 0, S_DETON3, 0},  // S_DETON2
+	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON4, 0},  // S_DETON3
+	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON5, 0},  // S_DETON4
+	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON6, 0},  // S_DETON5
+	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON7, 0},  // S_DETON6
+	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON8, 0},  // S_DETON7
+	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON9, 0},  // S_DETON8
+	{SPR_DETN, 7,  1, {A_DetonChase}, 0, 0, S_DETON10, 0}, // S_DETON9
+	{SPR_DETN, 6,  1, {A_DetonChase}, 0, 0, S_DETON11, 0}, // S_DETON10
+	{SPR_DETN, 5,  1, {A_DetonChase}, 0, 0, S_DETON12, 0}, // S_DETON11
+	{SPR_DETN, 4,  1, {A_DetonChase}, 0, 0, S_DETON13, 0}, // S_DETON12
+	{SPR_DETN, 3,  1, {A_DetonChase}, 0, 0, S_DETON14, 0}, // S_DETON13
+	{SPR_DETN, 2,  1, {A_DetonChase}, 0, 0, S_DETON15, 0}, // S_DETON14
+	{SPR_DETN, 1,  1, {A_DetonChase}, 0, 0, S_DETON2, 0},  // S_DETON15
 
 	// Skim Mine Dropper
-	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM2},    // S_SKIM1
-	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM1},    // S_SKIM2
-	{SPR_SKIM, 0, 14,        {NULL}, 0, 0, S_SKIM4},    // S_SKIM3
-	{SPR_SKIM, 0, 14,  {A_DropMine}, 0, 0, S_SKIM1},    // S_SKIM4
+	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM2, 0},    // S_SKIM1
+	{SPR_SKIM, 0,  1, {A_SkimChase}, 0, 0, S_SKIM1, 0},    // S_SKIM2
+	{SPR_SKIM, 0, 14,        {NULL}, 0, 0, S_SKIM4, 0},    // S_SKIM3
+	{SPR_SKIM, 0, 14,  {A_DropMine}, 0, 0, S_SKIM1, 0},    // S_SKIM4
 
 	// THZ Turret
-	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretStop}, 0, 0, S_TURRETFIRE},   // S_TURRET
-	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretFire}, 0, 0, S_TURRET},       // S_TURRETFIRE
-	{SPR_TRET, FF_FULLBRIGHT|1, 7, {A_Pain}, 0, 0, S_TURRETSHOCK2},       // S_TURRETSHOCK1
-	{SPR_TRET, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_TURRETSHOCK3},         // S_TURRETSHOCK2
-	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK4},         // S_TURRETSHOCK3
-	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK5},         // S_TURRETSHOCK4
-	{SPR_TRET, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_TURRETSHOCK6},         // S_TURRETSHOCK5
-	{SPR_TRET, FF_FULLBRIGHT|2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7},       // S_TURRETSHOCK6
-	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK8},         // S_TURRETSHOCK7
-	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK9},         // S_TURRETSHOCK8
-	{SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecuteFromArg}, 0, 0, S_XPLD1}, // S_TURRETSHOCK9
-
-	{SPR_TURR, 0, 1, {A_Look}, 1, 0, S_TURRETPOPDOWN8},          // S_TURRETLOOK
-	{SPR_TURR, 0, 0, {A_FaceTarget}, 0, 0, S_TURRETPOPUP1},  // S_TURRETSEE
-	{SPR_TURR, 1, 2, {A_Pain}, 0, 0, S_TURRETPOPUP2},  // S_TURRETPOPUP1
-	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPUP3},  // S_TURRETPOPUP2
-	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPUP4},  // S_TURRETPOPUP3
-	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPUP5},  // S_TURRETPOPUP4
-	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPUP6},  // S_TURRETPOPUP5
-	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPUP7},  // S_TURRETPOPUP6
-	{SPR_TURR, 7, 2, {NULL}, 0, 0, S_TURRETPOPUP8},  // S_TURRETPOPUP7
-	{SPR_TURR, 8, 14,{NULL}, 0, 0, S_TURRETSHOOT},   // S_TURRETPOPUP8
-	{SPR_TURR, 8, 14,{A_JetgShoot}, 0, 0, S_TURRETPOPDOWN1}, // S_TURRETSHOOT
-	{SPR_TURR, 7, 2, {A_Pain}, 0, 0, S_TURRETPOPDOWN2},        // S_TURRETPOPDOWN1
-	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPDOWN3},        // S_TURRETPOPDOWN2
-	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPDOWN4},        // S_TURRETPOPDOWN3
-	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPDOWN5},        // S_TURRETPOPDOWN4
-	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPDOWN6},        // S_TURRETPOPDOWN5
-	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPDOWN7},        // S_TURRETPOPDOWN6
-	{SPR_TURR, 1, 2, {NULL}, 0, 0, S_TURRETPOPDOWN8},        // S_TURRETPOPDOWN7
-	{SPR_TURR, 0, 69,{A_SetTics}, 0, 1, S_TURRETLOOK},       // S_TURRETPOPDOWN8
+	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretStop}, 0, 0, S_TURRETFIRE, 0},   // S_TURRET
+	{SPR_TRET, FF_FULLBRIGHT, 105, {A_TurretFire}, 0, 0, S_TURRET, 0},       // S_TURRETFIRE
+	{SPR_TRET, FF_FULLBRIGHT|1, 7, {A_Pain}, 0, 0, S_TURRETSHOCK2, 0},       // S_TURRETSHOCK1
+	{SPR_TRET, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_TURRETSHOCK3, 0},         // S_TURRETSHOCK2
+	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK4, 0},         // S_TURRETSHOCK3
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK5, 0},         // S_TURRETSHOCK4
+	{SPR_TRET, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_TURRETSHOCK6, 0},         // S_TURRETSHOCK5
+	{SPR_TRET, FF_FULLBRIGHT|2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7, 0},       // S_TURRETSHOCK6
+	{SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK8, 0},         // S_TURRETSHOCK7
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK9, 0},         // S_TURRETSHOCK8
+	{SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecuteFromArg}, 0, 0, S_XPLD1, 0}, // S_TURRETSHOCK9
+
+	{SPR_TURR, 0, 1, {A_Look}, 1, 0, S_TURRETPOPDOWN8, 0},          // S_TURRETLOOK
+	{SPR_TURR, 0, 0, {A_FaceTarget}, 0, 0, S_TURRETPOPUP1, 0},  // S_TURRETSEE
+	{SPR_TURR, 1, 2, {A_Pain}, 0, 0, S_TURRETPOPUP2, 0},  // S_TURRETPOPUP1
+	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPUP3, 0},  // S_TURRETPOPUP2
+	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPUP4, 0},  // S_TURRETPOPUP3
+	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPUP5, 0},  // S_TURRETPOPUP4
+	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPUP6, 0},  // S_TURRETPOPUP5
+	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPUP7, 0},  // S_TURRETPOPUP6
+	{SPR_TURR, 7, 2, {NULL}, 0, 0, S_TURRETPOPUP8, 0},  // S_TURRETPOPUP7
+	{SPR_TURR, 8, 14,{NULL}, 0, 0, S_TURRETSHOOT, 0},   // S_TURRETPOPUP8
+	{SPR_TURR, 8, 14,{A_JetgShoot}, 0, 0, S_TURRETPOPDOWN1, 0}, // S_TURRETSHOOT
+	{SPR_TURR, 7, 2, {A_Pain}, 0, 0, S_TURRETPOPDOWN2, 0},        // S_TURRETPOPDOWN1
+	{SPR_TURR, 6, 2, {NULL}, 0, 0, S_TURRETPOPDOWN3, 0},        // S_TURRETPOPDOWN2
+	{SPR_TURR, 5, 2, {NULL}, 0, 0, S_TURRETPOPDOWN4, 0},        // S_TURRETPOPDOWN3
+	{SPR_TURR, 4, 2, {NULL}, 0, 0, S_TURRETPOPDOWN5, 0},        // S_TURRETPOPDOWN4
+	{SPR_TURR, 3, 2, {NULL}, 0, 0, S_TURRETPOPDOWN6, 0},        // S_TURRETPOPDOWN5
+	{SPR_TURR, 2, 2, {NULL}, 0, 0, S_TURRETPOPDOWN7, 0},        // S_TURRETPOPDOWN6
+	{SPR_TURR, 1, 2, {NULL}, 0, 0, S_TURRETPOPDOWN8, 0},        // S_TURRETPOPDOWN7
+	{SPR_TURR, 0, 69,{A_SetTics}, 0, 1, S_TURRETLOOK, 0},       // S_TURRETPOPDOWN8
 
 	// Spincushion
-	{SPR_SHRP, 0,  2, {A_Look},                 0, 0, S_SPINCUSHION_LOOK},   // S_SPINCUSHION_LOOK
-	{SPR_SHRP, 1,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE2}, // S_SPINCUSHION_CHASE1
-	{SPR_SHRP, 2,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE3}, // S_SPINCUSHION_CHASE2
-	{SPR_SHRP, 3,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE4}, // S_SPINCUSHION_CHASE3
-	{SPR_SHRP, 0,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE1}, // S_SPINCUSHION_CHASE4
-	{SPR_SHRP, 0,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM2},   // S_SPINCUSHION_AIM1
-	{SPR_SHRP, 4,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM3},   // S_SPINCUSHION_AIM2
-	{SPR_SHRP, 5,  2, {A_SetObjectFlags}, MF_PAIN, 2, S_SPINCUSHION_AIM4},   // S_SPINCUSHION_AIM3
-	{SPR_SHRP, 6, 16, {A_MultiShotDist}, (MT_DUST<<16)|6, -32, S_SPINCUSHION_AIM5}, // S_SPINCUSHION_AIM4
-	{SPR_SHRP, 6,  0, {A_PlaySound},   sfx_shrpgo, 1, S_SPINCUSHION_SPIN1},  // S_SPINCUSHION_AIM5
-	{SPR_SHRP, 6,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN2},  // S_SPINCUSHION_SPIN1
-	{SPR_SHRP, 8,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN3},  // S_SPINCUSHION_SPIN2
-	{SPR_SHRP, 7,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN4},  // S_SPINCUSHION_SPIN3
-	{SPR_SHRP, 8,  1, {A_SharpSpin},  MT_SPINDUST, 0, S_SPINCUSHION_SPIN1},  // S_SPINCUSHION_SPIN4
-	{SPR_SHRP, 6,  1, {A_PlaySound},    sfx_s3k69, 1, S_SPINCUSHION_STOP2},  // S_SPINCUSHION_STOP1
-	{SPR_SHRP, 6,  4, {A_SharpDecel},           0, 0, S_SPINCUSHION_STOP2},  // S_SPINCUSHION_STOP2
-	{SPR_SHRP, 5,  4, {A_FaceTarget},           0, 0, S_SPINCUSHION_STOP4},  // S_SPINCUSHION_STOP3
-	{SPR_SHRP, 4,  4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK},   // S_SPINCUSHION_STOP4
+	{SPR_SHRP, 0,  2, {A_Look},                 0, 0, S_SPINCUSHION_LOOK, 0},   // S_SPINCUSHION_LOOK
+	{SPR_SHRP, 1,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE2, 0}, // S_SPINCUSHION_CHASE1
+	{SPR_SHRP, 2,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE3, 0}, // S_SPINCUSHION_CHASE2
+	{SPR_SHRP, 3,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE4, 0}, // S_SPINCUSHION_CHASE3
+	{SPR_SHRP, 0,  2, {A_SharpChase},           0, 0, S_SPINCUSHION_CHASE1, 0}, // S_SPINCUSHION_CHASE4
+	{SPR_SHRP, 0,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM2, 0},   // S_SPINCUSHION_AIM1
+	{SPR_SHRP, 4,  2, {NULL},                   0, 0, S_SPINCUSHION_AIM3, 0},   // S_SPINCUSHION_AIM2
+	{SPR_SHRP, 5,  2, {A_SetObjectFlags}, MF_PAIN, 2, S_SPINCUSHION_AIM4, 0},   // S_SPINCUSHION_AIM3
+	{SPR_SHRP, 6, 16, {A_MultiShotDist}, (MT_DUST<<16)|6, -32, S_SPINCUSHION_AIM5, 0}, // S_SPINCUSHION_AIM4
+	{SPR_SHRP, 6,  0, {A_PlaySound},   sfx_shrpgo, 1, S_SPINCUSHION_SPIN1, 0},  // S_SPINCUSHION_AIM5
+	{SPR_SHRP, 6,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN2, 0},  // S_SPINCUSHION_SPIN1
+	{SPR_SHRP, 8,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN3, 0},  // S_SPINCUSHION_SPIN2
+	{SPR_SHRP, 7,  1, {A_SharpSpin},            0, 0, S_SPINCUSHION_SPIN4, 0},  // S_SPINCUSHION_SPIN3
+	{SPR_SHRP, 8,  1, {A_SharpSpin},  MT_SPINDUST, 0, S_SPINCUSHION_SPIN1, 0},  // S_SPINCUSHION_SPIN4
+	{SPR_SHRP, 6,  1, {A_PlaySound},    sfx_s3k69, 1, S_SPINCUSHION_STOP2, 0},  // S_SPINCUSHION_STOP1
+	{SPR_SHRP, 6,  4, {A_SharpDecel},           0, 0, S_SPINCUSHION_STOP2, 0},  // S_SPINCUSHION_STOP2
+	{SPR_SHRP, 5,  4, {A_FaceTarget},           0, 0, S_SPINCUSHION_STOP4, 0},  // S_SPINCUSHION_STOP3
+	{SPR_SHRP, 4,  4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK, 0},   // S_SPINCUSHION_STOP4
 
 	// Crushstacean
-	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2},     // S_CRUSHSTACEAN_ROAM1
-	{SPR_CRAB, 1,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3},     // S_CRUSHSTACEAN_ROAM2
-	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4},     // S_CRUSHSTACEAN_ROAM3
-	{SPR_CRAB, 2,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1},     // S_CRUSHSTACEAN_ROAM4
-	{SPR_CRAB, 0, 40, {NULL},                0,                        0, S_CRUSHSTACEAN_ROAM1},     // S_CRUSHSTACEAN_ROAMPAUSE
-	{SPR_CRAB, 0, 10, {NULL},                0,                        0, S_CRUSHSTACEAN_PUNCH2},    // S_CRUSHSTACEAN_PUNCH1
-	{SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0,                        0, S_CRUSHSTACEAN_ROAMPAUSE}, // S_CRUSHSTACEAN_PUNCH2
-	{SPR_CRAB, 3,  1, {A_CrushclawAim},   40,               20, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_AIM
-	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 0, S_CRUSHCLAW_STAY, S_CRUSHCLAW_OUT}, // S_CRUSHCLAW_OUT
-	{SPR_CRAB, 3, 10, {NULL},              0,                0, S_CRUSHCLAW_IN},  // S_CRUSHCLAW_STAY
-	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN},  // S_CRUSHCLAW_IN
-	{SPR_CRAB, 3, 37, {NULL},              0,                0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_WAIT
-	{SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CRUSHCHAIN
+	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2, 0},     // S_CRUSHSTACEAN_ROAM1
+	{SPR_CRAB, 1,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3, 0},     // S_CRUSHSTACEAN_ROAM2
+	{SPR_CRAB, 0,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4, 0},     // S_CRUSHSTACEAN_ROAM3
+	{SPR_CRAB, 2,  3, {A_CrushstaceanWalk},  0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1, 0},     // S_CRUSHSTACEAN_ROAM4
+	{SPR_CRAB, 0, 40, {NULL},                0,                        0, S_CRUSHSTACEAN_ROAM1, 0},     // S_CRUSHSTACEAN_ROAMPAUSE
+	{SPR_CRAB, 0, 10, {NULL},                0,                        0, S_CRUSHSTACEAN_PUNCH2, 0},    // S_CRUSHSTACEAN_PUNCH1
+	{SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0,                        0, S_CRUSHSTACEAN_ROAMPAUSE, 0}, // S_CRUSHSTACEAN_PUNCH2
+	{SPR_CRAB, 3,  1, {A_CrushclawAim},   40,               20, S_CRUSHCLAW_AIM, 0}, // S_CRUSHCLAW_AIM
+	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 0, S_CRUSHCLAW_STAY, S_CRUSHCLAW_OUT, 0}, // S_CRUSHCLAW_OUT
+	{SPR_CRAB, 3, 10, {NULL},              0,                0, S_CRUSHCLAW_IN, 0},  // S_CRUSHCLAW_STAY
+	{SPR_CRAB, 3,  1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN, 0},  // S_CRUSHCLAW_IN
+	{SPR_CRAB, 3, 37, {NULL},              0,                0, S_CRUSHCLAW_AIM, 0}, // S_CRUSHCLAW_WAIT
+	{SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CRUSHCHAIN
 
 	// Banpyura
-	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM2}, // S_BANPYURA_ROAM1
-	{SPR_CR2B, 1,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM3}, // S_BANPYURA_ROAM2
-	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM4}, // S_BANPYURA_ROAM3
-	{SPR_CR2B, 2,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM1}, // S_BANPYURA_ROAM4
-	{SPR_CR2B, 0, 40, {NULL},                0,                    0, S_BANPYURA_ROAM1}, // S_BANPYURA_ROAMPAUSE
-
-	{SPR_CSPR, 0, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1}, // S_CDIAG1
-	{SPR_CSPR, 1, 1, {A_Pain},          0,  0, S_CDIAG3}, // S_CDIAG2
-	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG4}, // S_CDIAG3
-	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG5}, // S_CDIAG4
-	{SPR_CSPR, 4, 1, {A_CrushclawAim}, 50, 20, S_CDIAG6}, // S_CDIAG5
-	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG7}, // S_CDIAG6
-	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG8}, // S_CDIAG7
-	{SPR_CSPR, 1, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1}, // S_CDIAG8
+	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM2, 0}, // S_BANPYURA_ROAM1
+	{SPR_CR2B, 1,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM3, 0}, // S_BANPYURA_ROAM2
+	{SPR_CR2B, 0,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM4, 0}, // S_BANPYURA_ROAM3
+	{SPR_CR2B, 2,  3, {A_CrushstaceanWalk},  0, S_BANPYURA_ROAMPAUSE, S_BANPYURA_ROAM1, 0}, // S_BANPYURA_ROAM4
+	{SPR_CR2B, 0, 40, {NULL},                0,                    0, S_BANPYURA_ROAM1, 0}, // S_BANPYURA_ROAMPAUSE
+
+	{SPR_CSPR, 0, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1, 0}, // S_CDIAG1
+	{SPR_CSPR, 1, 1, {A_Pain},          0,  0, S_CDIAG3, 0}, // S_CDIAG2
+	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG4, 0}, // S_CDIAG3
+	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG5, 0}, // S_CDIAG4
+	{SPR_CSPR, 4, 1, {A_CrushclawAim}, 50, 20, S_CDIAG6, 0}, // S_CDIAG5
+	{SPR_CSPR, 3, 1, {A_CrushclawAim}, 50, 20, S_CDIAG7, 0}, // S_CDIAG6
+	{SPR_CSPR, 2, 1, {A_CrushclawAim}, 50, 20, S_CDIAG8, 0}, // S_CDIAG7
+	{SPR_CSPR, 1, 1, {A_CrushclawAim}, 50, 20, S_CDIAG1, 0}, // S_CDIAG8
 
 	// Jet Jaw
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM2}, // S_JETJAW_ROAM1
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM3}, // S_JETJAW_ROAM2
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM4}, // S_JETJAW_ROAM3
-	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM5}, // S_JETJAW_ROAM4
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM6}, // S_JETJAW_ROAM5
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM7}, // S_JETJAW_ROAM6
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM8}, // S_JETJAW_ROAM7
-	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM1}, // S_JETJAW_ROAM8
-	{SPR_JJAW, 0, 1, {A_DualAction}, S_JETJAW_CHOMP16, S_JETJAW_SOUND,  S_JETJAW_CHOMP2}, // S_JETJAW_CHOMP1
-	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP3}, // S_JETJAW_CHOMP2
-	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP4}, // S_JETJAW_CHOMP3
-	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP5}, // S_JETJAW_CHOMP4
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP6}, // S_JETJAW_CHOMP5
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP7}, // S_JETJAW_CHOMP6
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP8}, // S_JETJAW_CHOMP7
-	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP9}, // S_JETJAW_CHOMP8
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP10}, // S_JETJAW_CHOMP9
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP11}, // S_JETJAW_CHOMP10
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP12}, // S_JETJAW_CHOMP11
-	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP13}, // S_JETJAW_CHOMP12
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP14}, // S_JETJAW_CHOMP13
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP15}, // S_JETJAW_CHOMP14
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP16}, // S_JETJAW_CHOMP15
-	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP1}, // S_JETJAW_CHOMP16
-	{SPR_JJAW, 0, 1, {A_PlayAttackSound},          0,               0,   S_JETJAW_SOUND}, // S_JETJAW_SOUND
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM2, 0}, // S_JETJAW_ROAM1
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM3, 0}, // S_JETJAW_ROAM2
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM4, 0}, // S_JETJAW_ROAM3
+	{SPR_JJAW, 0, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM5, 0}, // S_JETJAW_ROAM4
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM6, 0}, // S_JETJAW_ROAM5
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM7, 0}, // S_JETJAW_ROAM6
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM8, 0}, // S_JETJAW_ROAM7
+	{SPR_JJAW, 1, 1, {A_JetJawRoam},               0,               0,   S_JETJAW_ROAM1, 0}, // S_JETJAW_ROAM8
+	{SPR_JJAW, 0, 1, {A_DualAction}, S_JETJAW_CHOMP16, S_JETJAW_SOUND,  S_JETJAW_CHOMP2, 0}, // S_JETJAW_CHOMP1
+	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP3, 0}, // S_JETJAW_CHOMP2
+	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP4, 0}, // S_JETJAW_CHOMP3
+	{SPR_JJAW, 0, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP5, 0}, // S_JETJAW_CHOMP4
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP6, 0}, // S_JETJAW_CHOMP5
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP7, 0}, // S_JETJAW_CHOMP6
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP8, 0}, // S_JETJAW_CHOMP7
+	{SPR_JJAW, 1, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP9, 0}, // S_JETJAW_CHOMP8
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP10, 0}, // S_JETJAW_CHOMP9
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP11, 0}, // S_JETJAW_CHOMP10
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP12, 0}, // S_JETJAW_CHOMP11
+	{SPR_JJAW, 2, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP13, 0}, // S_JETJAW_CHOMP12
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP14, 0}, // S_JETJAW_CHOMP13
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP15, 0}, // S_JETJAW_CHOMP14
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0, S_JETJAW_CHOMP16, 0}, // S_JETJAW_CHOMP15
+	{SPR_JJAW, 3, 1, {A_JetJawChomp},              0,               0,  S_JETJAW_CHOMP1, 0}, // S_JETJAW_CHOMP16
+	{SPR_JJAW, 0, 1, {A_PlayAttackSound},          0,               0,   S_JETJAW_SOUND, 0}, // S_JETJAW_SOUND
 
 	// Snailer
-	{SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1}, // S_SNAILER1
-	{SPR_BOM1, 0, 0, {A_FlickySpawn}, 1<<17, 0, S_XPLD1}, // S_SNAILER_FLICKY
+	{SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1, 0}, // S_SNAILER1
+	{SPR_BOM1, 0, 0, {A_FlickySpawn}, 1<<17, 0, S_XPLD1, 0}, // S_SNAILER_FLICKY
 
 	// Vulture
-	{SPR_VLTR, 4, 35,        {A_Look},         1, 0, S_VULTURE_STND},  // S_VULTURE_STND
-	{SPR_VLTR, 4, 3,         {A_VultureHover}, 0, 0, S_VULTURE_DRIFT}, // S_VULTURE_DRIFT
-	{SPR_VLTR, 0, 6,         {A_VultureBlast}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM1
-	{SPR_VLTR, 0, 3,         {A_VultureFly},   0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM2
-	{SPR_VLTR, 0, 3*TICRATE, {NULL},           0, 0, S_VULTURE_DRIFT}, // S_VULTURE_STUNNED
+	{SPR_VLTR, 4, 35,        {A_Look},         1, 0, S_VULTURE_STND, 0},  // S_VULTURE_STND
+	{SPR_VLTR, 4, 3,         {A_VultureHover}, 0, 0, S_VULTURE_DRIFT, 0}, // S_VULTURE_DRIFT
+	{SPR_VLTR, 0, 6,         {A_VultureBlast}, 0, 0, S_VULTURE_ZOOM2, 0}, // S_VULTURE_ZOOM1
+	{SPR_VLTR, 0, 3,         {A_VultureFly},   0, 0, S_VULTURE_ZOOM2, 0}, // S_VULTURE_ZOOM2
+	{SPR_VLTR, 0, 3*TICRATE, {NULL},           0, 0, S_VULTURE_DRIFT, 0}, // S_VULTURE_STUNNED
 
 	// Pointy
-	{SPR_PNTY, 0,  1, {A_PointyThink}, 0, 0, S_POINTY1}, // S_POINTY1
+	{SPR_PNTY, 0,  1, {A_PointyThink}, 0, 0, S_POINTY1, 0}, // S_POINTY1
 
 	// Pointy Ball
-	{SPR_PNTY, 1,  1, {A_CheckBuddy}, 0, 0, S_POINTYBALL1}, // S_POINTYBALL1
+	{SPR_PNTY, 1,  1, {A_CheckBuddy}, 0, 0, S_POINTYBALL1, 0}, // S_POINTYBALL1
 
 	// Robo-Hood
-	{SPR_ARCH, 0,       4,            {A_Look}, 2048<<FRACBITS,   0, S_ROBOHOOD_LOOK},  // S_ROBOHOOD_LOOK
-	{SPR_ARCH, 0,       1,       {A_HoodThink},              0,   0, S_ROBOHOOD_STAND}, // S_ROBOHOOD_STAND
-	{SPR_ARCH, 2, TICRATE, {A_PlayActiveSound},              0,   0, S_ROBOHOOD_FIRE2}, // S_ROBOHOOD_FIRE1
-	{SPR_ARCH, 2,      20,        {A_HoodFire},       MT_ARROW,   0, S_ROBOHOOD_STAND}, // S_ROBOHOOD_FIRE2
-	{SPR_ARCH, 1,       1,      {A_FaceTarget},              0,   0, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP1
-	{SPR_ARCH, 1,       1,        {A_BunnyHop},              4, -10, S_ROBOHOOD_JUMP3}, // S_ROBOHOOD_JUMP2
-	{SPR_ARCH, 1,       1,        {A_HoodFall},              0,   0, S_ROBOHOOD_JUMP3}, // S_ROBOHOOD_JUMP3
+	{SPR_ARCH, 0,       4,            {A_Look}, 2048<<FRACBITS,   0, S_ROBOHOOD_LOOK, 0},  // S_ROBOHOOD_LOOK
+	{SPR_ARCH, 0,       1,       {A_HoodThink},              0,   0, S_ROBOHOOD_STAND, 0}, // S_ROBOHOOD_STAND
+	{SPR_ARCH, 2, TICRATE, {A_PlayActiveSound},              0,   0, S_ROBOHOOD_FIRE2, 0}, // S_ROBOHOOD_FIRE1
+	{SPR_ARCH, 2,      20,        {A_HoodFire},       MT_ARROW,   0, S_ROBOHOOD_STAND, 0}, // S_ROBOHOOD_FIRE2
+	{SPR_ARCH, 1,       1,      {A_FaceTarget},              0,   0, S_ROBOHOOD_JUMP2, 0}, // S_ROBOHOOD_JUMP1
+	{SPR_ARCH, 1,       1,        {A_BunnyHop},              4, -10, S_ROBOHOOD_JUMP3, 0}, // S_ROBOHOOD_JUMP2
+	{SPR_ARCH, 1,       1,        {A_HoodFall},              0,   0, S_ROBOHOOD_JUMP3, 0}, // S_ROBOHOOD_JUMP3
 
 	// Castlebot Facestabber
-	{SPR_CBFS, 0,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND2},   // S_FACESTABBER_STND1
-	{SPR_CBFS, 1,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND3},   // S_FACESTABBER_STND2
-	{SPR_CBFS, 2,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND4},   // S_FACESTABBER_STND3
-	{SPR_CBFS, 3,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND5},   // S_FACESTABBER_STND4
-	{SPR_CBFS, 4,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND6},   // S_FACESTABBER_STND5
-	{SPR_CBFS, 5,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND1},   // S_FACESTABBER_STND6
-	{SPR_CBFS, 0,  1,  {A_FaceStabRev},                  20, S_FACESTABBER_CHARGE2, S_FACESTABBER_CHARGE1}, // S_FACESTABBER_CHARGE1
-	{SPR_CBFS, 0,  0,   {A_FaceTarget},                   0,                     0, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE2
-	{SPR_CBFS, 7,  1, {A_FaceStabHurl},                   6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE3
-	{SPR_CBFS, 7,  1, {A_FaceStabMiss}, 0,   S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE4
-	{SPR_CBFS, 0, 35,         {A_Pain}, 0,                     0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN
-	{SPR_CBFS, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE2},  // S_FACESTABBER_DIE1
-	{SPR_NULL, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE3},  // S_FACESTABBER_DIE2
-	{SPR_NULL, 0,  0,       {A_Repeat}, 7, S_FACESTABBER_DIE1,    S_XPLD_FLICKY},       // S_FACESTABBER_DIE3
-
-	{SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSPEAR
+	{SPR_CBFS, 0,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND2, 0},   // S_FACESTABBER_STND1
+	{SPR_CBFS, 1,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND3, 0},   // S_FACESTABBER_STND2
+	{SPR_CBFS, 2,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND4, 0},   // S_FACESTABBER_STND3
+	{SPR_CBFS, 3,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND5, 0},   // S_FACESTABBER_STND4
+	{SPR_CBFS, 4,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND6, 0},   // S_FACESTABBER_STND5
+	{SPR_CBFS, 5,  1,        {A_Chase},  0, 0, S_FACESTABBER_STND1, 0},   // S_FACESTABBER_STND6
+	{SPR_CBFS, 0,  1,  {A_FaceStabRev},                  20, S_FACESTABBER_CHARGE2, S_FACESTABBER_CHARGE1, 0}, // S_FACESTABBER_CHARGE1
+	{SPR_CBFS, 0,  0,   {A_FaceTarget},                   0,                     0, S_FACESTABBER_CHARGE3, 0}, // S_FACESTABBER_CHARGE2
+	{SPR_CBFS, 7,  1, {A_FaceStabHurl},                   6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3, 0}, // S_FACESTABBER_CHARGE3
+	{SPR_CBFS, 7,  1, {A_FaceStabMiss}, 0,   S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4, 0}, // S_FACESTABBER_CHARGE4
+	{SPR_CBFS, 0, 35,         {A_Pain}, 0,                     0, S_FACESTABBER_STND1, 0}, // S_FACESTABBER_PAIN
+	{SPR_CBFS, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE2, 0},  // S_FACESTABBER_DIE1
+	{SPR_NULL, 0,  2,   {A_BossScream}, 1, 0, S_FACESTABBER_DIE3, 0},  // S_FACESTABBER_DIE2
+	{SPR_NULL, 0,  0,       {A_Repeat}, 7, S_FACESTABBER_DIE1,    S_XPLD_FLICKY, 0},       // S_FACESTABBER_DIE3
+
+	{SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FACESTABBERSPEAR
 
 	// Egg Guard
-	{SPR_SPSH,  0,  1,       {A_Look}, 0, 0, S_EGGGUARD_STND},  // S_EGGGUARD_STND
-	{SPR_SPSH,  1,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK2}, // S_EGGGUARD_WALK1
-	{SPR_SPSH,  2,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK3}, // S_EGGGUARD_WALK2
-	{SPR_SPSH,  3,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK4}, // S_EGGGUARD_WALK3
-	{SPR_SPSH,  4,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK1}, // S_EGGGUARD_WALK4
-	{SPR_SPSH,  5,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD2},  // S_EGGGUARD_MAD1
-	{SPR_SPSH,  6,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD3},  // S_EGGGUARD_MAD2
-	{SPR_SPSH,  7, 15,         {NULL}, 0, 0, S_EGGGUARD_RUN1},  // S_EGGGUARD_MAD3
-	{SPR_SPSH,  8,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN2},  // S_EGGGUARD_RUN1
-	{SPR_SPSH,  9,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN3},  // S_EGGGUARD_RUN2
-	{SPR_SPSH, 10,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN4},  // S_EGGGUARD_RUN3
-	{SPR_SPSH, 11,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN1},  // S_EGGGUARD_RUN4
-
-	{SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD},  // S_EGGSHIELD
-	{SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_EGGSHIELDBREAK
+	{SPR_SPSH,  0,  1,       {A_Look}, 0, 0, S_EGGGUARD_STND, 0},  // S_EGGGUARD_STND
+	{SPR_SPSH,  1,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK2, 0}, // S_EGGGUARD_WALK1
+	{SPR_SPSH,  2,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK3, 0}, // S_EGGGUARD_WALK2
+	{SPR_SPSH,  3,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK4, 0}, // S_EGGGUARD_WALK3
+	{SPR_SPSH,  4,  3, {A_GuardChase}, 0, 0, S_EGGGUARD_WALK1, 0}, // S_EGGGUARD_WALK4
+	{SPR_SPSH,  5,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD2, 0},  // S_EGGGUARD_MAD1
+	{SPR_SPSH,  6,  5,         {NULL}, 0, 0, S_EGGGUARD_MAD3, 0},  // S_EGGGUARD_MAD2
+	{SPR_SPSH,  7, 15,         {NULL}, 0, 0, S_EGGGUARD_RUN1, 0},  // S_EGGGUARD_MAD3
+	{SPR_SPSH,  8,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN2, 0},  // S_EGGGUARD_RUN1
+	{SPR_SPSH,  9,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN3, 0},  // S_EGGGUARD_RUN2
+	{SPR_SPSH, 10,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN4, 0},  // S_EGGGUARD_RUN3
+	{SPR_SPSH, 11,  1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN1, 0},  // S_EGGGUARD_RUN4
+
+	{SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD, 0},  // S_EGGSHIELD
+	{SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL, 0}, // S_EGGSHIELDBREAK
 
 	// Green Snapper
-	{SPR_GSNP, 0, TICRATE, {NULL},             0,              0,               S_SNAPPER_SPAWN2}, // S_SNAPPER_SPAWN
-	{SPR_GSNP, 0, 2,       {A_SnapperSpawn},   MT_SNAPPER_LEG, MT_SNAPPER_HEAD, S_GSNAPPER_STND},  // S_SNAPPER_SPAWN2
-	{SPR_GSNP, 0, 1,       {A_SnapperThinker}, 0,              0,               S_GSNAPPER_STND},  // S_GSNAPPER_STND
-	{SPR_GSNP, 0, 2,       {A_Chase},          0,              0,               S_GSNAPPER2},      // S_GSNAPPER1
-	{SPR_GSNP, 1, 2,       {A_Chase},          0,              0,               S_GSNAPPER3},      // S_GSNAPPER2
-	{SPR_GSNP, 2, 2,       {A_Chase},          0,              0,               S_GSNAPPER4},      // S_GSNAPPER3
-	{SPR_GSNP, 3, 2,       {A_Chase},          0,              0,               S_GSNAPPER1},      // S_GSNAPPER4
-	{SPR_GSNP, 0, 0,       {A_KillSegments},   0,              0,               S_XPLD_FLICKY},    // S_SNAPPER_XPLD
-	{SPR_GSNL, 0, -1,      {NULL},             0,              0,               S_NULL},           // S_SNAPPER_LEG
-	{SPR_GSNL, 1, -1,      {NULL},             0,              0,               S_NULL},           // S_SNAPPER_LEGRAISE
-	{SPR_GSNH, 0, -1,      {NULL},             0,              0,               S_NULL},           // S_SNAPPER_HEAD
+	{SPR_GSNP, 0, TICRATE, {NULL},             0,              0,               S_SNAPPER_SPAWN2, 0}, // S_SNAPPER_SPAWN
+	{SPR_GSNP, 0, 2,       {A_SnapperSpawn},   MT_SNAPPER_LEG, MT_SNAPPER_HEAD, S_GSNAPPER_STND, 0},  // S_SNAPPER_SPAWN2
+	{SPR_GSNP, 0, 1,       {A_SnapperThinker}, 0,              0,               S_GSNAPPER_STND, 0},  // S_GSNAPPER_STND
+	{SPR_GSNP, 0, 2,       {A_Chase},          0,              0,               S_GSNAPPER2, 0},      // S_GSNAPPER1
+	{SPR_GSNP, 1, 2,       {A_Chase},          0,              0,               S_GSNAPPER3, 0},      // S_GSNAPPER2
+	{SPR_GSNP, 2, 2,       {A_Chase},          0,              0,               S_GSNAPPER4, 0},      // S_GSNAPPER3
+	{SPR_GSNP, 3, 2,       {A_Chase},          0,              0,               S_GSNAPPER1, 0},      // S_GSNAPPER4
+	{SPR_GSNP, 0, 0,       {A_KillSegments},   0,              0,               S_XPLD_FLICKY, 0},    // S_SNAPPER_XPLD
+	{SPR_GSNL, 0, -1,      {NULL},             0,              0,               S_NULL, 0},           // S_SNAPPER_LEG
+	{SPR_GSNL, 1, -1,      {NULL},             0,              0,               S_NULL, 0},           // S_SNAPPER_LEGRAISE
+	{SPR_GSNH, 0, -1,      {NULL},             0,              0,               S_NULL, 0},           // S_SNAPPER_HEAD
 
 	// Minus
-	{SPR_MNUD, 0,            1,  {NULL},           0, 0, S_MINUS_STND},     // S_MINUS_INIT (required for objectplace to work)
-	{SPR_NULL, 0,            10, {A_Look},         0, 0, S_MINUS_STND},     // S_MINUS_STND
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 1, 0, S_MINUS_DIGGING2}, // S_MINUS_DIGGING1
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING3}, // S_MINUS_DIGGING2
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING4}, // S_MINUS_DIGGING3
-	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING1}, // S_MINUS_DIGGING4
-	{SPR_NULL, 0,            25, {NULL},           0, 0, S_MINUS_POPUP},    // S_MINUS_BURST0
-	{SPR_MNUD, FF_ANIMATE,   5,  {NULL},           1, 2, S_MINUS_BURST2},   // S_MINUS_BURST1
-	{SPR_MNUD, 1|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST3},   // S_MINUS_BURST2
-	{SPR_MNUD, 2|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST4},   // S_MINUS_BURST3
-	{SPR_MNUD, 3|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST5},   // S_MINUS_BURST4
-	{SPR_MNUD, 4|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUSDIRT2},     // S_MINUS_BURST5
-	{SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1}, // S_MINUS_POPUP
-	{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2},   // S_MINUS_AERIAL1
-	{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3},   // S_MINUS_AERIAL2
-	{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4},   // S_MINUS_AERIAL3
-	{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1},   // S_MINUS_AERIAL4
-
-	{SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1
-	{SPR_MNUD, 5,          8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2
-	{SPR_MNUD, 4,          8, {NULL}, 3, 5, S_MINUSDIRT4}, // S_MINUSDIRT3
-	{SPR_MNUD, 3,          8, {NULL}, 3, 5, S_MINUSDIRT5}, // S_MINUSDIRT4
-	{SPR_MNUD, 2,          8, {NULL}, 3, 5, S_MINUSDIRT6}, // S_MINUSDIRT5
-	{SPR_MNUD, 1,          8, {NULL}, 3, 5, S_MINUSDIRT7}, // S_MINUSDIRT6
-	{SPR_MNUD, 0,          8, {NULL}, 3, 5, S_NULL},       // S_MINUSDIRT7
+	{SPR_MNUD, 0,            1,  {NULL},           0, 0, S_MINUS_STND, 0},     // S_MINUS_INIT (required for objectplace to work)
+	{SPR_NULL, 0,            10, {A_Look},         0, 0, S_MINUS_STND, 0},     // S_MINUS_STND
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 1, 0, S_MINUS_DIGGING2, 0}, // S_MINUS_DIGGING1
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING3, 0}, // S_MINUS_DIGGING2
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING4, 0}, // S_MINUS_DIGGING3
+	{SPR_NULL, 0,            1,  {A_MinusDigging}, 0, 0, S_MINUS_DIGGING1, 0}, // S_MINUS_DIGGING4
+	{SPR_NULL, 0,            25, {NULL},           0, 0, S_MINUS_POPUP, 0},    // S_MINUS_BURST0
+	{SPR_MNUD, FF_ANIMATE,   5,  {NULL},           1, 2, S_MINUS_BURST2, 0},   // S_MINUS_BURST1
+	{SPR_MNUD, 1|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST3, 0},   // S_MINUS_BURST2
+	{SPR_MNUD, 2|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST4, 0},   // S_MINUS_BURST3
+	{SPR_MNUD, 3|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUS_BURST5, 0},   // S_MINUS_BURST4
+	{SPR_MNUD, 4|FF_ANIMATE, 5,  {NULL},           1, 2, S_MINUSDIRT2, 0},     // S_MINUS_BURST5
+	{SPR_MNUS, 3, 1, {A_MinusPopup}, 0, 0, S_MINUS_AERIAL1, 0}, // S_MINUS_POPUP
+	{SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL2, 0},   // S_MINUS_AERIAL1
+	{SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL3, 0},   // S_MINUS_AERIAL2
+	{SPR_MNUS, 2, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL4, 0},   // S_MINUS_AERIAL3
+	{SPR_MNUS, 3, 1, {A_MinusCheck}, 0, 1, S_MINUS_AERIAL1, 0},   // S_MINUS_AERIAL4
+
+	{SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2, 0}, // S_MINUSDIRT1
+	{SPR_MNUD, 5,          8, {NULL}, 3, 5, S_MINUSDIRT3, 0}, // S_MINUSDIRT2
+	{SPR_MNUD, 4,          8, {NULL}, 3, 5, S_MINUSDIRT4, 0}, // S_MINUSDIRT3
+	{SPR_MNUD, 3,          8, {NULL}, 3, 5, S_MINUSDIRT5, 0}, // S_MINUSDIRT4
+	{SPR_MNUD, 2,          8, {NULL}, 3, 5, S_MINUSDIRT6, 0}, // S_MINUSDIRT5
+	{SPR_MNUD, 1,          8, {NULL}, 3, 5, S_MINUSDIRT7, 0}, // S_MINUSDIRT6
+	{SPR_MNUD, 0,          8, {NULL}, 3, 5, S_NULL, 0},       // S_MINUSDIRT7
 
 	// Spring Shell
-	{SPR_SSHL,  0,  4, {A_Look},  0, 0, S_SSHELL_STND},    // S_SSHELL_STND
-	{SPR_SSHL,  0,  4, {A_Chase}, 0, 0, S_SSHELL_RUN2},    // S_SSHELL_RUN1
-	{SPR_SSHL,  1,  4, {A_Chase}, 0, 0, S_SSHELL_RUN3},    // S_SSHELL_RUN2
-	{SPR_SSHL,  2,  4, {A_Chase}, 0, 0, S_SSHELL_RUN4},    // S_SSHELL_RUN3
-	{SPR_SSHL,  3,  4, {A_Chase}, 0, 0, S_SSHELL_RUN1},    // S_SSHELL_RUN4
-	{SPR_SSHL,  7,  4, {A_Pain},  0, 0, S_SSHELL_SPRING2}, // S_SSHELL_SPRING1
-	{SPR_SSHL,  6,  1, {NULL},    0, 0, S_SSHELL_SPRING3}, // S_SSHELL_SPRING2
-	{SPR_SSHL,  5,  1, {NULL},    0, 0, S_SSHELL_SPRING4}, // S_SSHELL_SPRING3
-	{SPR_SSHL,  4,  1, {NULL},    0, 0, S_SSHELL_RUN1},    // S_SSHELL_SPRING4
+	{SPR_SSHL,  0,  4, {A_Look},  0, 0, S_SSHELL_STND, 0},    // S_SSHELL_STND
+	{SPR_SSHL,  0,  4, {A_Chase}, 0, 0, S_SSHELL_RUN2, 0},    // S_SSHELL_RUN1
+	{SPR_SSHL,  1,  4, {A_Chase}, 0, 0, S_SSHELL_RUN3, 0},    // S_SSHELL_RUN2
+	{SPR_SSHL,  2,  4, {A_Chase}, 0, 0, S_SSHELL_RUN4, 0},    // S_SSHELL_RUN3
+	{SPR_SSHL,  3,  4, {A_Chase}, 0, 0, S_SSHELL_RUN1, 0},    // S_SSHELL_RUN4
+	{SPR_SSHL,  7,  4, {A_Pain},  0, 0, S_SSHELL_SPRING2, 0}, // S_SSHELL_SPRING1
+	{SPR_SSHL,  6,  1, {NULL},    0, 0, S_SSHELL_SPRING3, 0}, // S_SSHELL_SPRING2
+	{SPR_SSHL,  5,  1, {NULL},    0, 0, S_SSHELL_SPRING4, 0}, // S_SSHELL_SPRING3
+	{SPR_SSHL,  4,  1, {NULL},    0, 0, S_SSHELL_RUN1, 0},    // S_SSHELL_SPRING4
 
 	// Spring Shell (yellow)
-	{SPR_SSHL,  8,  4, {A_Look},  0, 0, S_YSHELL_STND},    // S_YSHELL_STND
-	{SPR_SSHL,  8,  4, {A_Chase}, 0, 0, S_YSHELL_RUN2},    // S_YSHELL_RUN1
-	{SPR_SSHL,  9,  4, {A_Chase}, 0, 0, S_YSHELL_RUN3},    // S_YSHELL_RUN2
-	{SPR_SSHL, 10,  4, {A_Chase}, 0, 0, S_YSHELL_RUN4},    // S_YSHELL_RUN3
-	{SPR_SSHL, 11,  4, {A_Chase}, 0, 0, S_YSHELL_RUN1},    // S_YSHELL_RUN4
-	{SPR_SSHL, 15,  4, {A_Pain},  0, 0, S_YSHELL_SPRING2}, // S_YSHELL_SPRING1
-	{SPR_SSHL, 14,  1, {NULL},    0, 0, S_YSHELL_SPRING3}, // S_YSHELL_SPRING2
-	{SPR_SSHL, 13,  1, {NULL},    0, 0, S_YSHELL_SPRING4}, // S_YSHELL_SPRING3
-	{SPR_SSHL, 12,  1, {NULL},    0, 0, S_YSHELL_RUN1},    // S_YSHELL_SPRING4
+	{SPR_SSHL,  8,  4, {A_Look},  0, 0, S_YSHELL_STND, 0},    // S_YSHELL_STND
+	{SPR_SSHL,  8,  4, {A_Chase}, 0, 0, S_YSHELL_RUN2, 0},    // S_YSHELL_RUN1
+	{SPR_SSHL,  9,  4, {A_Chase}, 0, 0, S_YSHELL_RUN3, 0},    // S_YSHELL_RUN2
+	{SPR_SSHL, 10,  4, {A_Chase}, 0, 0, S_YSHELL_RUN4, 0},    // S_YSHELL_RUN3
+	{SPR_SSHL, 11,  4, {A_Chase}, 0, 0, S_YSHELL_RUN1, 0},    // S_YSHELL_RUN4
+	{SPR_SSHL, 15,  4, {A_Pain},  0, 0, S_YSHELL_SPRING2, 0}, // S_YSHELL_SPRING1
+	{SPR_SSHL, 14,  1, {NULL},    0, 0, S_YSHELL_SPRING3, 0}, // S_YSHELL_SPRING2
+	{SPR_SSHL, 13,  1, {NULL},    0, 0, S_YSHELL_SPRING4, 0}, // S_YSHELL_SPRING3
+	{SPR_SSHL, 12,  1, {NULL},    0, 0, S_YSHELL_RUN1, 0},    // S_YSHELL_SPRING4
 
 	// Unidus
-	{SPR_UNID, 0, 4, {A_Look},       0, 0, S_UNIDUS_STND}, // S_UNIDUS_STND
-	{SPR_UNID, 0, 1, {A_Chase},      0, 0, S_UNIDUS_RUN }, // S_UNIDUS_RUN
-	{SPR_UNID, 1, 1, {A_UnidusBall}, 1, 0, S_UNIDUS_BALL}, // S_UNIDUS_BALL
+	{SPR_UNID, 0, 4, {A_Look},       0, 0, S_UNIDUS_STND, 0}, // S_UNIDUS_STND
+	{SPR_UNID, 0, 1, {A_Chase},      0, 0, S_UNIDUS_RUN , 0}, // S_UNIDUS_RUN
+	{SPR_UNID, 1, 1, {A_UnidusBall}, 1, 0, S_UNIDUS_BALL, 0}, // S_UNIDUS_BALL
 
 	// Canarivore
-	{SPR_CANA, 0, 5,  {A_Look},          1200*FRACUNIT+1,   1,                 S_CANARIVORE_LOOK},      // S_CANARIVORE_LOOK
-	{SPR_CANA, 0, 3,  {A_PlaySound},     sfx_s3k76,         1,                 S_CANARIVORE_AWAKEN2},   // S_CANARIVORE_AWAKEN1
-	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_AWAKEN3},   // S_CANARIVORE_AWAKEN2
-	{SPR_CANA, 2, 8,  {NULL},            0,                 0,                 S_CANARIVORE_GAS1},      // S_CANARIVORE_AWAKEN3
-	{SPR_CANA, 2, 15, {A_PlaySound},     sfx_s3k93,         1,                 S_CANARIVORE_GAS2},      // S_CANARIVORE_GAS1
-	{SPR_CANA, 1, 4,  {NULL},            0,                 0,                 S_CANARIVORE_GAS3},      // S_CANARIVORE_GAS2
-	{SPR_CANA, 2, 0,  {A_PlaySound},     sfx_s3k97,         1,                 S_CANARIVORE_GAS4},      // S_CANARIVORE_GAS3
-	{SPR_CANA, 2, 5,  {A_CanarivoreGas}, MT_CANARIVORE_GAS, 0,                 S_CANARIVORE_GAS5},      // S_CANARIVORE_GAS4
-	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_GASREPEAT}, // S_CANARIVORE_GAS5
-	{SPR_CANA, 2, 0,  {A_Repeat},        6,                 S_CANARIVORE_GAS4, S_CANARIVORE_CLOSE1},    // S_CANARIVORE_GASREPEAT
-	{SPR_CANA, 1, 8,  {NULL},            0,                 0,                 S_CANARIVORE_CLOSE2},     // S_CANARIVORE_CLOSE1
-	{SPR_CANA, 0, 90, {NULL},            sfx_s3k5d,         1,                 S_CANARIVORE_LOOK},      // S_CANARIVORE_CLOSE2
-
-	{SPR_CANG, 0|FF_TRANS90, 2,         {NULL},            0, 0,       S_CANARIVOREGAS_2}, // S_CANARIVOREGAS_1
-	{SPR_CANG, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_CANARIVOREGAS_3}, // S_CANARIVOREGAS_2
-	{SPR_CANG, 0|FF_TRANS40, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_4}, // S_CANARIVOREGAS_3
-	{SPR_CANG, 0|FF_TRANS50, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_5}, // S_CANARIVOREGAS_4
-	{SPR_CANG, 0|FF_TRANS60, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_6}, // S_CANARIVOREGAS_5
-	{SPR_CANG, 0|FF_TRANS70, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_7}, // S_CANARIVOREGAS_6
-	{SPR_CANG, 0|FF_TRANS80, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_8}, // S_CANARIVOREGAS_7
-	{SPR_CANG, 0|FF_TRANS90, 10,        {NULL},            0, 0,       S_NULL},            // S_CANARIVOREGAS_8
+	{SPR_CANA, 0, 5,  {A_Look},          1200*FRACUNIT+1,   1,                 S_CANARIVORE_LOOK, 0},      // S_CANARIVORE_LOOK
+	{SPR_CANA, 0, 3,  {A_PlaySound},     sfx_s3k76,         1,                 S_CANARIVORE_AWAKEN2, 0},   // S_CANARIVORE_AWAKEN1
+	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_AWAKEN3, 0},   // S_CANARIVORE_AWAKEN2
+	{SPR_CANA, 2, 8,  {NULL},            0,                 0,                 S_CANARIVORE_GAS1, 0},      // S_CANARIVORE_AWAKEN3
+	{SPR_CANA, 2, 15, {A_PlaySound},     sfx_s3k93,         1,                 S_CANARIVORE_GAS2, 0},      // S_CANARIVORE_GAS1
+	{SPR_CANA, 1, 4,  {NULL},            0,                 0,                 S_CANARIVORE_GAS3, 0},      // S_CANARIVORE_GAS2
+	{SPR_CANA, 2, 0,  {A_PlaySound},     sfx_s3k97,         1,                 S_CANARIVORE_GAS4, 0},      // S_CANARIVORE_GAS3
+	{SPR_CANA, 2, 5,  {A_CanarivoreGas}, MT_CANARIVORE_GAS, 0,                 S_CANARIVORE_GAS5, 0},      // S_CANARIVORE_GAS4
+	{SPR_CANA, 1, 5,  {NULL},            0,                 0,                 S_CANARIVORE_GASREPEAT, 0}, // S_CANARIVORE_GAS5
+	{SPR_CANA, 2, 0,  {A_Repeat},        6,                 S_CANARIVORE_GAS4, S_CANARIVORE_CLOSE1, 0},    // S_CANARIVORE_GASREPEAT
+	{SPR_CANA, 1, 8,  {NULL},            0,                 0,                 S_CANARIVORE_CLOSE2, 0},     // S_CANARIVORE_CLOSE1
+	{SPR_CANA, 0, 90, {NULL},            sfx_s3k5d,         1,                 S_CANARIVORE_LOOK, 0},      // S_CANARIVORE_CLOSE2
+
+	{SPR_CANG, 0|FF_TRANS90, 2,         {NULL},            0, 0,       S_CANARIVOREGAS_2, 0}, // S_CANARIVOREGAS_1
+	{SPR_CANG, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_CANARIVOREGAS_3, 0}, // S_CANARIVOREGAS_2
+	{SPR_CANG, 0|FF_TRANS40, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_4, 0}, // S_CANARIVOREGAS_3
+	{SPR_CANG, 0|FF_TRANS50, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_5, 0}, // S_CANARIVOREGAS_4
+	{SPR_CANG, 0|FF_TRANS60, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_6, 0}, // S_CANARIVOREGAS_5
+	{SPR_CANG, 0|FF_TRANS70, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_7, 0}, // S_CANARIVOREGAS_6
+	{SPR_CANG, 0|FF_TRANS80, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_8, 0}, // S_CANARIVOREGAS_7
+	{SPR_CANG, 0|FF_TRANS90, 10,        {NULL},            0, 0,       S_NULL, 0},            // S_CANARIVOREGAS_8
 
 	// Pyre Fly
-	{SPR_PYRE, FF_ANIMATE, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_FLY
-	{SPR_PYRE, 4|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_BURN
-	{SPR_FLAM, FF_FULLBRIGHT, 10, {NULL}, 0, 0, S_PYREFIRE2}, // S_PYREFIRE1
-	{SPR_FLAM, 1|FF_FULLBRIGHT, 10, {A_FireShrink}, 0, 16, S_NULL}, // S_PYREFIRE2
+	{SPR_PYRE, FF_ANIMATE, -1, {NULL}, 3, 2, S_NULL, 0}, // S_PYREFLY_FLY
+	{SPR_PYRE, 4|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 3, 2, S_NULL, 0}, // S_PYREFLY_BURN
+	{SPR_FLAM, FF_FULLBRIGHT, 10, {NULL}, 0, 0, S_PYREFIRE2, 0}, // S_PYREFIRE1
+	{SPR_FLAM, 1|FF_FULLBRIGHT, 10, {A_FireShrink}, 0, 16, S_NULL, 0}, // S_PYREFIRE2
 
 	// Pterabyte
-	{SPR_NULL, 0, -1, {A_SpawnPterabytes}, 0, 0, S_PTERABYTESPAWNER},    // S_PTERABYTESPAWNER
-	{SPR_NULL, 0,  1, {A_PterabyteHover},  0, 0, S_PTERABYTEWAYPOINT},   // S_PTERABYTEWAYPOINT
-	{SPR_PTER, 0,  6, {NULL},              0, 0, S_PTERABYTE_FLY2},      // S_PTERABYTE_FLY1
-	{SPR_PTER, 1,  2, {NULL},              0, 0, S_PTERABYTE_FLY3},      // S_PTERABYTE_FLY2
-	{SPR_PTER, 2,  6, {NULL},              0, 0, S_PTERABYTE_FLY4},      // S_PTERABYTE_FLY3
-	{SPR_PTER, 3,  2, {NULL},              0, 0, S_PTERABYTE_FLY1},      // S_PTERABYTE_FLY4
-	{SPR_PTER, 4,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPDOWN}, // S_PTERABYTE_SWOOPDOWN
-	{SPR_PTER, 0,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPUP},   // S_PTERABYTE_SWOOPUP
+	{SPR_NULL, 0, -1, {A_SpawnPterabytes}, 0, 0, S_PTERABYTESPAWNER, 0},    // S_PTERABYTESPAWNER
+	{SPR_NULL, 0,  1, {A_PterabyteHover},  0, 0, S_PTERABYTEWAYPOINT, 0},   // S_PTERABYTEWAYPOINT
+	{SPR_PTER, 0,  6, {NULL},              0, 0, S_PTERABYTE_FLY2, 0},      // S_PTERABYTE_FLY1
+	{SPR_PTER, 1,  2, {NULL},              0, 0, S_PTERABYTE_FLY3, 0},      // S_PTERABYTE_FLY2
+	{SPR_PTER, 2,  6, {NULL},              0, 0, S_PTERABYTE_FLY4, 0},      // S_PTERABYTE_FLY3
+	{SPR_PTER, 3,  2, {NULL},              0, 0, S_PTERABYTE_FLY1, 0},      // S_PTERABYTE_FLY4
+	{SPR_PTER, 4,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPDOWN, 0}, // S_PTERABYTE_SWOOPDOWN
+	{SPR_PTER, 0,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPUP, 0},   // S_PTERABYTE_SWOOPUP
 
 	// Dragonbomber
-	{SPR_DRAB,                0, -1, {A_DragonbomberSpawn}, 6, 0, S_NULL},                          // S_DRAGONBOMBER
-	{SPR_DRAB, FF_PAPERSPRITE|7,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING2},                   // S_DRAGONWING1
-	{SPR_DRAB, FF_PAPERSPRITE|8,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING3},                   // S_DRAGONWING2
-	{SPR_DRAB, FF_PAPERSPRITE|9,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING4},                   // S_DRAGONWING3
-	{SPR_DRAB, FF_PAPERSPRITE|10, 1,        {A_DragonWing}, 0, 0, S_DRAGONWING1},                   // S_DRAGONWING4
-	{SPR_DRAB,                1,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_LOADED},             // S_DRAGONTAIL_LOADED
-	{SPR_DRAB,                2,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_EMPTYLOOP},          // S_DRAGONTAIL_EMPTY
-	{SPR_DRAB,                2,  0,            {A_Repeat}, 3*TICRATE, S_DRAGONTAIL_EMPTY, S_DRAGONTAIL_RELOAD}, // S_DRAGONTAIL_EMPTYLOOP
-	{SPR_DRAB,                1,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONTAIL_LOADED},             // S_DRAGONTAIL_RELOAD
-	{SPR_DRAB,                3,  1,        {A_MinusCheck}, S_DRAGONMINE_LAND1, 0, S_DRAGONMINE},   // S_DRAGONMINE
-	{SPR_DRAB,                4,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONMINE_LAND2},              // S_DRAGONMINE_LAND1
-	{SPR_DRAB,                4,  2,            {A_Thrust}, 0, 1, S_DRAGONMINE_SLOWFLASH1},         // S_DRAGONMINE_LAND2
-	{SPR_DRAB,                5, 11,                {NULL}, 0, 0, S_DRAGONMINE_SLOWFLASH2},         // S_DRAGONMINE_SLOWFLASH1
-	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_SLOWLOOP},           // S_DRAGONMINE_SLOWFLASH2
-	{SPR_DRAB,                5,  0,            {A_Repeat}, 4, S_DRAGONMINE_SLOWFLASH1, S_DRAGONMINE_FASTFLASH1}, // S_DRAGONMINE_SLOWLOOP
-	{SPR_DRAB,                5,  3,                {NULL}, 0, 0, S_DRAGONMINE_FASTFLASH2},         // S_DRAGONMINE_FASTFLASH1
-	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_FASTLOOP},           // S_DRAGONMINE_FASTFLASH2
-	{SPR_DRAB,                5,  0,            {A_Repeat}, 5, S_DRAGONMINE_FASTFLASH1, S_DEATHSTATE}, // S_DRAGONMINE_FASTLOOP
+	{SPR_DRAB,                0, -1, {A_DragonbomberSpawn}, 6, 0, S_NULL, 0},                          // S_DRAGONBOMBER
+	{SPR_DRAB, FF_PAPERSPRITE|7,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING2, 0},                   // S_DRAGONWING1
+	{SPR_DRAB, FF_PAPERSPRITE|8,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING3, 0},                   // S_DRAGONWING2
+	{SPR_DRAB, FF_PAPERSPRITE|9,  1,        {A_DragonWing}, 0, 0, S_DRAGONWING4, 0},                   // S_DRAGONWING3
+	{SPR_DRAB, FF_PAPERSPRITE|10, 1,        {A_DragonWing}, 0, 0, S_DRAGONWING1, 0},                   // S_DRAGONWING4
+	{SPR_DRAB,                1,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_LOADED, 0},             // S_DRAGONTAIL_LOADED
+	{SPR_DRAB,                2,  1,     {A_DragonSegment}, 0, 0, S_DRAGONTAIL_EMPTYLOOP, 0},          // S_DRAGONTAIL_EMPTY
+	{SPR_DRAB,                2,  0,            {A_Repeat}, 3*TICRATE, S_DRAGONTAIL_EMPTY, S_DRAGONTAIL_RELOAD, 0}, // S_DRAGONTAIL_EMPTYLOOP
+	{SPR_DRAB,                1,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONTAIL_LOADED, 0},             // S_DRAGONTAIL_RELOAD
+	{SPR_DRAB,                3,  1,        {A_MinusCheck}, S_DRAGONMINE_LAND1, 0, S_DRAGONMINE, 0},   // S_DRAGONMINE
+	{SPR_DRAB,                4,  0,   {A_PlayActiveSound}, 0, 0, S_DRAGONMINE_LAND2, 0},              // S_DRAGONMINE_LAND1
+	{SPR_DRAB,                4,  2,            {A_Thrust}, 0, 1, S_DRAGONMINE_SLOWFLASH1, 0},         // S_DRAGONMINE_LAND2
+	{SPR_DRAB,                5, 11,                {NULL}, 0, 0, S_DRAGONMINE_SLOWFLASH2, 0},         // S_DRAGONMINE_SLOWFLASH1
+	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_SLOWLOOP, 0},           // S_DRAGONMINE_SLOWFLASH2
+	{SPR_DRAB,                5,  0,            {A_Repeat}, 4, S_DRAGONMINE_SLOWFLASH1, S_DRAGONMINE_FASTFLASH1, 0}, // S_DRAGONMINE_SLOWLOOP
+	{SPR_DRAB,                5,  3,                {NULL}, 0, 0, S_DRAGONMINE_FASTFLASH2, 0},         // S_DRAGONMINE_FASTFLASH1
+	{SPR_DRAB,  FF_FULLBRIGHT|6,  1,   {A_PlayAttackSound}, 0, 0, S_DRAGONMINE_FASTLOOP, 0},           // S_DRAGONMINE_FASTFLASH2
+	{SPR_DRAB,                5,  0,            {A_Repeat}, 5, S_DRAGONMINE_FASTFLASH1, S_DEATHSTATE, 0}, // S_DRAGONMINE_FASTLOOP
 
 	// Boss Explosion
-	{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE
+	{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL, 0}, // S_BOSSEXPLODE
 
 	// S3&K Boss Explosion
-	{SPR_BOM3, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION2}, // S_SONIC3KBOSSEXPLOSION1
-	{SPR_BOM3, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION3}, // S_SONIC3KBOSSEXPLOSION2
-	{SPR_BOM3, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION4}, // S_SONIC3KBOSSEXPLOSION3
-	{SPR_BOM3, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION5}, // S_SONIC3KBOSSEXPLOSION4
-	{SPR_BOM3, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION6}, // S_SONIC3KBOSSEXPLOSION5
-	{SPR_BOM3, FF_FULLBRIGHT|5, 4, {NULL}, 0, 0, S_NULL}, // S_SONIC3KBOSSEXPLOSION6
+	{SPR_BOM3, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION2, 0}, // S_SONIC3KBOSSEXPLOSION1
+	{SPR_BOM3, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION3, 0}, // S_SONIC3KBOSSEXPLOSION2
+	{SPR_BOM3, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION4, 0}, // S_SONIC3KBOSSEXPLOSION3
+	{SPR_BOM3, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION5, 0}, // S_SONIC3KBOSSEXPLOSION4
+	{SPR_BOM3, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION6, 0}, // S_SONIC3KBOSSEXPLOSION5
+	{SPR_BOM3, FF_FULLBRIGHT|5, 4, {NULL}, 0, 0, S_NULL, 0}, // S_SONIC3KBOSSEXPLOSION6
 
-	{SPR_JETF, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 2, 1, S_NULL}, // S_JETFUME1
+	{SPR_JETF, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 2, 1, S_NULL, 0}, // S_JETFUME1
 
 	// Boss 1
-	{SPR_EGGM,  0,   1, {A_Boss1Chase},            0, 0, S_EGGMOBILE_STND},   // S_EGGMOBILE_STND
-	{SPR_EGGM, FF_ANIMATE|17, 35, {A_FaceTarget},  1, 2, S_EGGMOBILE_STND},   // S_EGGMOBILE_ROFL
-	{SPR_EGGM,  1,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK2},  // S_EGGMOBILE_LATK1
-	{SPR_EGGM,  2,  15, {NULL},                    0, 0, S_EGGMOBILE_LATK3},  // S_EGGMOBILE_LATK2
-	{SPR_EGGM,  3,   2, {NULL},                    0, 0, S_EGGMOBILE_LATK4},  // S_EGGMOBILE_LATK3
-	{SPR_EGGM,  4,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK5},  // S_EGGMOBILE_LATK4
-	{SPR_EGGM,  6,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_LATK6},  // S_EGGMOBILE_LATK5
-	{SPR_EGGM,  5,   1, {A_Boss1Laser},     MT_LASER, 0, S_EGGMOBILE_LATK7},  // S_EGGMOBILE_LATK6
-	{SPR_EGGM,  6,   1, {A_Boss1Laser},     MT_LASER, (1<<16), S_EGGMOBILE_LATK8},  // S_EGGMOBILE_LATK7
-	{SPR_EGGM,  5,   0, {A_Repeat}, 45, S_EGGMOBILE_LATK6, S_EGGMOBILE_LATK9},  // S_EGGMOBILE_LATK8
-	{SPR_EGGM,  8,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_LATK9
-	{SPR_EGGM,  9,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK2},  // S_EGGMOBILE_RATK1
-	{SPR_EGGM, 10,  15, {NULL},                    0, 0, S_EGGMOBILE_RATK3},  // S_EGGMOBILE_RATK2
-	{SPR_EGGM, 11,   2, {NULL},                    0, 0, S_EGGMOBILE_RATK4},  // S_EGGMOBILE_RATK3
-	{SPR_EGGM, 12,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK5},  // S_EGGMOBILE_RATK4
-	{SPR_EGGM, 14,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_RATK6},  // S_EGGMOBILE_RATK5
-	{SPR_EGGM, 13,   1, {A_Boss1Laser},     MT_LASER, 1, S_EGGMOBILE_RATK7},  // S_EGGMOBILE_RATK6
-	{SPR_EGGM, 14,   1, {A_Boss1Laser},     MT_LASER, 1|(1<<16), S_EGGMOBILE_RATK8},  // S_EGGMOBILE_RATK7
-	{SPR_EGGM, 13,   0, {A_Repeat}, 45, S_EGGMOBILE_RATK6, S_EGGMOBILE_RATK9},  // S_EGGMOBILE_RATK8
-	{SPR_EGGM, 16,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_RATK9
-	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC2},  // S_EGGMOBILE_PANIC1
-	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC3},  // S_EGGMOBILE_PANIC2
-	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC4},  // S_EGGMOBILE_PANIC3
-	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC5},  // S_EGGMOBILE_PANIC4
-	{SPR_EGGM,  6,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC3, S_EGGMOBILE_PANIC6},  // S_EGGMOBILE_PANIC5
-	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC7},  // S_EGGMOBILE_PANIC6
-	{SPR_EGGM, FF_ANIMATE|9, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC8},  // S_EGGMOBILE_PANIC7
-	{SPR_EGGM, 15,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC9},  // S_EGGMOBILE_PANIC8
-	{SPR_EGGM, 14,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC10},  // S_EGGMOBILE_PANIC9
-	{SPR_EGGM, 14,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC8, S_EGGMOBILE_PANIC11}, // S_EGGMOBILE_PANIC10
-	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC12}, // S_EGGMOBILE_PANIC11
-	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC13}, // S_EGGMOBILE_PANIC12
-	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC14}, // S_EGGMOBILE_PANIC13
-	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC15}, // S_EGGMOBILE_PANIC14
-	{SPR_EGGM,  6,  0, {A_Repeat}, 45,    S_EGGMOBILE_PANIC13, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_PANIC15
-	{SPR_EGGM, 19,  24, {A_Pain},                  0, 0, S_EGGMOBILE_PAIN2},  // S_EGGMOBILE_PAIN
-	{SPR_EGGM, 19,  16, {A_SkullAttack},           3, 1, S_EGGMOBILE_STND},   // S_EGGMOBILE_PAIN2
-	{SPR_EGGM, 20,  2, {A_Fall},                  17, 0, S_EGGMOBILE_DIE2},   // S_EGGMOBILE_DIE1
-	{SPR_EGGM, 20,  2, {A_BossScream},             0, 0, S_EGGMOBILE_DIE3},   // S_EGGMOBILE_DIE2
-	{SPR_EGGM, 20,  0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4},   // S_EGGMOBILE_DIE3
-	{SPR_EGGM, 20,  -1, {A_BossDeath},             0, 0, S_NULL},             // S_EGGMOBILE_DIE4
-	{SPR_EGGM, 21,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE2},  // S_EGGMOBILE_FLEE1
-	{SPR_EGGM, 22,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE1},  // S_EGGMOBILE_FLEE2
-	{SPR_UNID,  1,  1, {A_UnidusBall},             2, 0, S_EGGMOBILE_BALL},   // S_EGGMOBILE_BALL
-	{SPR_NULL,  0,  1, {A_FocusTarget},            0, 0, S_EGGMOBILE_TARGET}, // S_EGGMOBILE_TARGET
-
-	{SPR_EGLZ, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSEGLZ1
-	{SPR_EGLZ, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSEGLZ2
+	{SPR_EGGM,  0,   1, {A_Boss1Chase},            0, 0, S_EGGMOBILE_STND, 0},   // S_EGGMOBILE_STND
+	{SPR_EGGM, FF_ANIMATE|17, 35, {A_FaceTarget},  1, 2, S_EGGMOBILE_STND, 0},   // S_EGGMOBILE_ROFL
+	{SPR_EGGM,  1,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK2, 0},  // S_EGGMOBILE_LATK1
+	{SPR_EGGM,  2,  15, {NULL},                    0, 0, S_EGGMOBILE_LATK3, 0},  // S_EGGMOBILE_LATK2
+	{SPR_EGGM,  3,   2, {NULL},                    0, 0, S_EGGMOBILE_LATK4, 0},  // S_EGGMOBILE_LATK3
+	{SPR_EGGM,  4,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_LATK5, 0},  // S_EGGMOBILE_LATK4
+	{SPR_EGGM,  6,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_LATK6, 0},  // S_EGGMOBILE_LATK5
+	{SPR_EGGM,  5,   1, {A_Boss1Laser},     MT_LASER, 0, S_EGGMOBILE_LATK7, 0},  // S_EGGMOBILE_LATK6
+	{SPR_EGGM,  6,   1, {A_Boss1Laser},     MT_LASER, (1<<16), S_EGGMOBILE_LATK8, 0},  // S_EGGMOBILE_LATK7
+	{SPR_EGGM,  5,   0, {A_Repeat}, 45, S_EGGMOBILE_LATK6, S_EGGMOBILE_LATK9, 0},  // S_EGGMOBILE_LATK8
+	{SPR_EGGM,  8,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL, 0}, // S_EGGMOBILE_LATK9
+	{SPR_EGGM,  9,   3, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK2, 0},  // S_EGGMOBILE_RATK1
+	{SPR_EGGM, 10,  15, {NULL},                    0, 0, S_EGGMOBILE_RATK3, 0},  // S_EGGMOBILE_RATK2
+	{SPR_EGGM, 11,   2, {NULL},                    0, 0, S_EGGMOBILE_RATK4, 0},  // S_EGGMOBILE_RATK3
+	{SPR_EGGM, 12,   2, {A_FaceTarget},            0, 0, S_EGGMOBILE_RATK5, 0},  // S_EGGMOBILE_RATK4
+	{SPR_EGGM, 14,   0, {A_PrepareRepeat},        45, 0, S_EGGMOBILE_RATK6, 0},  // S_EGGMOBILE_RATK5
+	{SPR_EGGM, 13,   1, {A_Boss1Laser},     MT_LASER, 1, S_EGGMOBILE_RATK7, 0},  // S_EGGMOBILE_RATK6
+	{SPR_EGGM, 14,   1, {A_Boss1Laser},     MT_LASER, 1|(1<<16), S_EGGMOBILE_RATK8, 0},  // S_EGGMOBILE_RATK7
+	{SPR_EGGM, 13,   0, {A_Repeat}, 45, S_EGGMOBILE_RATK6, S_EGGMOBILE_RATK9, 0},  // S_EGGMOBILE_RATK8
+	{SPR_EGGM, 16,  2, {NULL},                     0, 0, S_EGGMOBILE_ROFL, 0}, // S_EGGMOBILE_RATK9
+	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC2, 0},  // S_EGGMOBILE_PANIC1
+	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC3, 0},  // S_EGGMOBILE_PANIC2
+	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC4, 0},  // S_EGGMOBILE_PANIC3
+	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC5, 0},  // S_EGGMOBILE_PANIC4
+	{SPR_EGGM,  6,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC3, S_EGGMOBILE_PANIC6, 0},  // S_EGGMOBILE_PANIC5
+	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC7, 0},  // S_EGGMOBILE_PANIC6
+	{SPR_EGGM, FF_ANIMATE|9, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC8, 0},  // S_EGGMOBILE_PANIC7
+	{SPR_EGGM, 15,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC9, 0},  // S_EGGMOBILE_PANIC8
+	{SPR_EGGM, 14,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC10, 0},  // S_EGGMOBILE_PANIC9
+	{SPR_EGGM, 14,  0, {A_Repeat}, 45,  S_EGGMOBILE_PANIC8, S_EGGMOBILE_PANIC11, 0}, // S_EGGMOBILE_PANIC10
+	{SPR_EGGM,  0,  0, {A_PrepareRepeat},            45, 0, S_EGGMOBILE_PANIC12, 0}, // S_EGGMOBILE_PANIC11
+	{SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget},      3, 4, S_EGGMOBILE_PANIC13, 0}, // S_EGGMOBILE_PANIC12
+	{SPR_EGGM,  7,  1, {A_Boss1Laser},         MT_LASER, 2, S_EGGMOBILE_PANIC14, 0}, // S_EGGMOBILE_PANIC13
+	{SPR_EGGM,  6,  1, {A_Boss1Laser},         MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC15, 0}, // S_EGGMOBILE_PANIC14
+	{SPR_EGGM,  6,  0, {A_Repeat}, 45,    S_EGGMOBILE_PANIC13, S_EGGMOBILE_ROFL, 0}, // S_EGGMOBILE_PANIC15
+	{SPR_EGGM, 19,  24, {A_Pain},                  0, 0, S_EGGMOBILE_PAIN2, 0},  // S_EGGMOBILE_PAIN
+	{SPR_EGGM, 19,  16, {A_SkullAttack},           3, 1, S_EGGMOBILE_STND, 0},   // S_EGGMOBILE_PAIN2
+	{SPR_EGGM, 20,  2, {A_Fall},                  17, 0, S_EGGMOBILE_DIE2, 0},   // S_EGGMOBILE_DIE1
+	{SPR_EGGM, 20,  2, {A_BossScream},             0, 0, S_EGGMOBILE_DIE3, 0},   // S_EGGMOBILE_DIE2
+	{SPR_EGGM, 20,  0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4, 0},   // S_EGGMOBILE_DIE3
+	{SPR_EGGM, 20,  -1, {A_BossDeath},             0, 0, S_NULL, 0},             // S_EGGMOBILE_DIE4
+	{SPR_EGGM, 21,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE2, 0},  // S_EGGMOBILE_FLEE1
+	{SPR_EGGM, 22,  2, {A_BossScream},             0, 0, S_EGGMOBILE_FLEE1, 0},  // S_EGGMOBILE_FLEE2
+	{SPR_UNID,  1,  1, {A_UnidusBall},             2, 0, S_EGGMOBILE_BALL, 0},   // S_EGGMOBILE_BALL
+	{SPR_NULL,  0,  1, {A_FocusTarget},            0, 0, S_EGGMOBILE_TARGET, 0}, // S_EGGMOBILE_TARGET
+
+	{SPR_EGLZ, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSEGLZ1
+	{SPR_EGLZ, 1, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSEGLZ2
 
 	// Boss 2
-	{SPR_EGGN, 0, -1,              {NULL},           0,          0, S_NULL},             // S_EGGMOBILE2_STND
-	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO2}, // S_EGGMOBILE2_POGO1
-	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  9*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO3}, // S_EGGMOBILE2_POGO2
-	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_POGO3
-	{SPR_EGGN, 2, -1,              {NULL},           0,          0, S_NULL},             // S_EGGMOBILE2_POGO4
-	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO6}, // S_EGGMOBILE2_POGO5
-	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  7*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO7}, // S_EGGMOBILE2_POGO6
-	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_POGO7
-	{SPR_EGGN, 3, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_STND},  // S_EGGMOBILE2_PAIN
-	{SPR_EGGN, 4, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_PAIN2
-	{SPR_EGGN, 5, 2,             {A_Fall},           0,          0, S_EGGMOBILE2_DIE2},  // S_EGGMOBILE2_DIE1
-	{SPR_EGGN, 5, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_DIE3},  // S_EGGMOBILE2_DIE2
-	{SPR_EGGN, 5, 0,       {A_Repeat}, 17, S_EGGMOBILE2_DIE2, S_EGGMOBILE2_DIE4},  // S_EGGMOBILE2_DIE3
-	{SPR_EGGN, 5, -1,       {A_BossDeath},           0,          0, S_NULL},             // S_EGGMOBILE2_DIE4
-	{SPR_EGGN, 6, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE2}, // S_EGGMOBILE2_FLEE1
-	{SPR_EGGN, 7, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE1}, // S_EGGMOBILE2_FLEE2
-
-	{SPR_TANK, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK1
-	{SPR_TANK, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK2
-	{SPR_TANK, 2, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSPIGOT
+	{SPR_EGGN, 0, -1,              {NULL},           0,          0, S_NULL, 0},             // S_EGGMOBILE2_STND
+	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO2, 0}, // S_EGGMOBILE2_POGO1
+	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  9*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO3, 0}, // S_EGGMOBILE2_POGO2
+	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4, 0}, // S_EGGMOBILE2_POGO3
+	{SPR_EGGN, 2, -1,              {NULL},           0,          0, S_NULL, 0},             // S_EGGMOBILE2_POGO4
+	{SPR_EGGN, 1, 4,               {NULL},           0,          0, S_EGGMOBILE2_POGO6, 0}, // S_EGGMOBILE2_POGO5
+	{SPR_EGGN, 0, 2,  {A_Boss2PogoTarget},  7*FRACUNIT, 8*FRACUNIT, S_EGGMOBILE2_POGO7, 0}, // S_EGGMOBILE2_POGO6
+	{SPR_EGGN, 1, 2,               {NULL},           0,          0, S_EGGMOBILE2_POGO4, 0}, // S_EGGMOBILE2_POGO7
+	{SPR_EGGN, 3, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_STND, 0},  // S_EGGMOBILE2_PAIN
+	{SPR_EGGN, 4, 24, {A_Boss2TakeDamage},  24+TICRATE,          0, S_EGGMOBILE2_POGO4, 0}, // S_EGGMOBILE2_PAIN2
+	{SPR_EGGN, 5, 2,             {A_Fall},           0,          0, S_EGGMOBILE2_DIE2, 0},  // S_EGGMOBILE2_DIE1
+	{SPR_EGGN, 5, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_DIE3, 0},  // S_EGGMOBILE2_DIE2
+	{SPR_EGGN, 5, 0,       {A_Repeat}, 17, S_EGGMOBILE2_DIE2, S_EGGMOBILE2_DIE4, 0},  // S_EGGMOBILE2_DIE3
+	{SPR_EGGN, 5, -1,       {A_BossDeath},           0,          0, S_NULL, 0},             // S_EGGMOBILE2_DIE4
+	{SPR_EGGN, 6, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE2, 0}, // S_EGGMOBILE2_FLEE1
+	{SPR_EGGN, 7, 2,       {A_BossScream},           0,          0, S_EGGMOBILE2_FLEE1, 0}, // S_EGGMOBILE2_FLEE2
+
+	{SPR_TANK, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSTANK1
+	{SPR_TANK, 1, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSTANK2
+	{SPR_TANK, 2, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSSPIGOT
 
 	// Boss 2 Goop
-	{SPR_GOOP,            0,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP2}, // S_GOOP1
-	{SPR_GOOP,            1,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP1}, // S_GOOP2
-	{SPR_GOOP,            2, -1,                  {NULL}, 0,            0, S_NULL},  // S_GOOP3
-	{SPR_GOOP, FF_ANIMATE|3, 11,                  {NULL}, 2,            6, S_NULL},  // S_GOOPTRAIL
+	{SPR_GOOP,            0,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP2, 0}, // S_GOOP1
+	{SPR_GOOP,            1,  2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP1, 0}, // S_GOOP2
+	{SPR_GOOP,            2, -1,                  {NULL}, 0,            0, S_NULL, 0},  // S_GOOP3
+	{SPR_GOOP, FF_ANIMATE|3, 11,                  {NULL}, 2,            6, S_NULL, 0},  // S_GOOPTRAIL
 
 	// Boss 3
-	{SPR_EGGO,  0,   1, {NULL},                    0, 0, S_EGGMOBILE3_STND},    // S_EGGMOBILE3_STND
-	{SPR_EGGO,   FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2},  // S_EGGMOBILE3_SHOCK
-	{SPR_EGGO, 6|FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_ATK1
-	{SPR_EGGO,  2,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK3A},   // S_EGGMOBILE3_ATK2
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B},   // S_EGGMOBILE3_ATK3A
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 4, S_EGGMOBILE3_ATK3C},   // S_EGGMOBILE3_ATK3B
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D},   // S_EGGMOBILE3_ATK3C
-	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4},    // S_EGGMOBILE3_ATK3D
-	{SPR_EGGO,  4,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK5},    // S_EGGMOBILE3_ATK4
-	{SPR_EGGO,  5,   2, {NULL},                    0, 0, S_EGGMOBILE3_ROFL},  // S_EGGMOBILE3_ATK5
-	{SPR_EGGO,  6|FF_ANIMATE, 60, {NULL}, 1, 2, S_EGGMOBILE3_STND},  // S_EGGMOBILE3_ROFL
-	{SPR_EGGO,  8,   1, {A_Boss3TakeDamage},       0, 0, S_EGGMOBILE3_PAIN2},   // S_EGGMOBILE3_PAIN
-	{SPR_EGGO,  8,  23, {A_Pain},                  0, 0, S_EGGMOBILE3_STND},    // S_EGGMOBILE3_PAIN2
-	{SPR_EGGO,  9,   2, {A_Fall},                  0, 0, S_EGGMOBILE3_DIE2},    // S_EGGMOBILE3_DIE1
-	{SPR_EGGO,  9,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_DIE3},    // S_EGGMOBILE3_DIE2
-	{SPR_EGGO,  9,   0, {A_Repeat}, 17, S_EGGMOBILE3_DIE2, S_EGGMOBILE3_DIE4},  // S_EGGMOBILE3_DIE3
-	{SPR_EGGO,  9,  -1, {A_BossDeath},             0, 0, S_NULL},               // S_EGGMOBILE3_DIE4
-	{SPR_EGGO, 10,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE2},   // S_EGGMOBILE3_FLEE1
-	{SPR_EGGO, 11,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE1},   // S_EGGMOBILE3_FLEE2
+	{SPR_EGGO,  0,   1, {NULL},                    0, 0, S_EGGMOBILE3_STND, 0},    // S_EGGMOBILE3_STND
+	{SPR_EGGO,   FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2, 0},  // S_EGGMOBILE3_SHOCK
+	{SPR_EGGO, 6|FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2, 0}, // S_EGGMOBILE3_ATK1
+	{SPR_EGGO,  2,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK3A, 0},   // S_EGGMOBILE3_ATK2
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B, 0},   // S_EGGMOBILE3_ATK3A
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 4, S_EGGMOBILE3_ATK3C, 0},   // S_EGGMOBILE3_ATK3B
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D, 0},   // S_EGGMOBILE3_ATK3C
+	{SPR_EGGO,  3,   2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4, 0},    // S_EGGMOBILE3_ATK3D
+	{SPR_EGGO,  4,   2, {NULL},                    0, 0, S_EGGMOBILE3_ATK5, 0},    // S_EGGMOBILE3_ATK4
+	{SPR_EGGO,  5,   2, {NULL},                    0, 0, S_EGGMOBILE3_ROFL, 0},  // S_EGGMOBILE3_ATK5
+	{SPR_EGGO,  6|FF_ANIMATE, 60, {NULL}, 1, 2, S_EGGMOBILE3_STND, 0},  // S_EGGMOBILE3_ROFL
+	{SPR_EGGO,  8,   1, {A_Boss3TakeDamage},       0, 0, S_EGGMOBILE3_PAIN2, 0},   // S_EGGMOBILE3_PAIN
+	{SPR_EGGO,  8,  23, {A_Pain},                  0, 0, S_EGGMOBILE3_STND, 0},    // S_EGGMOBILE3_PAIN2
+	{SPR_EGGO,  9,   2, {A_Fall},                  0, 0, S_EGGMOBILE3_DIE2, 0},    // S_EGGMOBILE3_DIE1
+	{SPR_EGGO,  9,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_DIE3, 0},    // S_EGGMOBILE3_DIE2
+	{SPR_EGGO,  9,   0, {A_Repeat}, 17, S_EGGMOBILE3_DIE2, S_EGGMOBILE3_DIE4, 0},  // S_EGGMOBILE3_DIE3
+	{SPR_EGGO,  9,  -1, {A_BossDeath},             0, 0, S_NULL, 0},               // S_EGGMOBILE3_DIE4
+	{SPR_EGGO, 10,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE2, 0},   // S_EGGMOBILE3_FLEE1
+	{SPR_EGGO, 11,   2, {A_BossScream},            0, 0, S_EGGMOBILE3_FLEE1, 0},   // S_EGGMOBILE3_FLEE2
 
 	// Boss 3 Pinch
-	{SPR_FAKE, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE},       // S_FAKEMOBILE_INIT
-	{SPR_FAKE, 0,  1, {A_Boss3Path},              0, 0, S_FAKEMOBILE},       // S_FAKEMOBILE
-	{SPR_FAKE, 0, 22, {NULL},                     0, 0, S_FAKEMOBILE_ATK2},  // S_FAKEMOBILE_ATK1
-	{SPR_FAKE, 0,  2, {NULL},                     0, 0, S_FAKEMOBILE_ATK3A}, // S_FAKEMOBILE_ATK2
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 2, S_FAKEMOBILE_ATK3B}, // S_FAKEMOBILE_ATK3A
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C}, // S_FAKEMOBILE_ATK3B
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D}, // S_FAKEMOBILE_ATK3C
-	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE},       // S_FAKEMOBILE_ATK3D
-	{SPR_FAKE, 1,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE2},  // S_FAKEMOBILE_DIE1
-	{SPR_NULL, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE1},  // S_FAKEMOBILE_DIE2
-
-	{SPR_SEBH, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH1
-	{SPR_SEBH, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH2
+	{SPR_FAKE, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE, 0},       // S_FAKEMOBILE_INIT
+	{SPR_FAKE, 0,  1, {A_Boss3Path},              0, 0, S_FAKEMOBILE, 0},       // S_FAKEMOBILE
+	{SPR_FAKE, 0, 22, {NULL},                     0, 0, S_FAKEMOBILE_ATK2, 0},  // S_FAKEMOBILE_ATK1
+	{SPR_FAKE, 0,  2, {NULL},                     0, 0, S_FAKEMOBILE_ATK3A, 0}, // S_FAKEMOBILE_ATK2
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 2, S_FAKEMOBILE_ATK3B, 0}, // S_FAKEMOBILE_ATK3A
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C, 0}, // S_FAKEMOBILE_ATK3B
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D, 0}, // S_FAKEMOBILE_ATK3C
+	{SPR_FAKE, 0,  2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE, 0},       // S_FAKEMOBILE_ATK3D
+	{SPR_FAKE, 1,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE2, 0},  // S_FAKEMOBILE_DIE1
+	{SPR_NULL, 0,  1, {NULL},                     0, 0, S_FAKEMOBILE_DIE1, 0},  // S_FAKEMOBILE_DIE2
+
+	{SPR_SEBH, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSSEBH1
+	{SPR_SEBH, 1, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BOSSSEBH2
 
 	// Boss 3 Shockwave
 
-	{SPR_SHCK,   FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE2}, // S_SHOCKWAVE1
-	{SPR_SHCK, 3|FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE1}, // S_SHOCKWAVE2
+	{SPR_SHCK,   FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE2, 0}, // S_SHOCKWAVE1
+	{SPR_SHCK, 3|FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE1, 0}, // S_SHOCKWAVE2
 
 	// Boss 4
-	{SPR_EGGP, 0, -1, {NULL},           0,          0, S_NULL},              // S_EGGMOBILE4_STND
-	{SPR_EGGP, 1,  3, {NULL},           0,          0, S_EGGMOBILE4_LATK2},  // S_EGGMOBILE4_LATK1
-	{SPR_EGGP, 2, 15, {NULL},           0,          0, S_EGGMOBILE4_LATK3},  // S_EGGMOBILE4_LATK2
-	{SPR_EGGP, 3,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK4},  // S_EGGMOBILE4_LATK3
-	{SPR_EGGP, 4,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK5},  // S_EGGMOBILE4_LATK4
-	{SPR_EGGP, 5, 50, {A_Boss4Reverse}, sfx_mswing, 0, S_EGGMOBILE4_LATK6},  // S_EGGMOBILE4_LATK5
-	{SPR_EGGP, 6,  2, {NULL},           0,          0, S_EGGMOBILE4_STND},   // S_EGGMOBILE4_LATK6
-	{SPR_EGGP, 7,  3, {NULL},           0,          0, S_EGGMOBILE4_RATK2},  // S_EGGMOBILE4_RATK1
-	{SPR_EGGP, 8, 15, {NULL},           0,          0, S_EGGMOBILE4_RATK3},  // S_EGGMOBILE4_RATK2
-	{SPR_EGGP, 9,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK4},  // S_EGGMOBILE4_RATK3
-	{SPR_EGGP,10,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK5},  // S_EGGMOBILE4_RATK4
-	{SPR_EGGP,11,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6},  // S_EGGMOBILE4_RATK5
-	{SPR_EGGP,12,  2, {NULL},           0,          0, S_EGGMOBILE4_STND},   // S_EGGMOBILE4_RATK6
-	{SPR_EGGP,13, 20, {A_Boss4Raise},   sfx_doord1, 0, S_EGGMOBILE4_RAISE2}, // S_EGGMOBILE4_RAISE1
-	{SPR_EGGP,15|FF_ANIMATE, -1, {NULL},        1,        10, S_NULL},             // S_EGGMOBILE4_RAISE2
-	{SPR_EGGP,13,  0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1
-	{SPR_EGGP,13, 24, {A_Pain},                 0,         0, S_EGGMOBILE4_STND},  // S_EGGMOBILE4_PAIN2
-	{SPR_EGGP,14,  2, {A_Fall},         0,          0, S_EGGMOBILE4_DIE2},   // S_EGGMOBILE4_DIE1
-	{SPR_EGGP,14,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_DIE3},   // S_EGGMOBILE4_DIE2
-	{SPR_EGGP,14,  0, {A_Repeat},   17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4},   // S_EGGMOBILE4_DIE3
-	{SPR_EGGP,14, -1, {A_BossDeath},    0,          0, S_NULL},              // S_EGGMOBILE4_DIE4
-	{SPR_EGGP,15,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE2},  // S_EGGMOBILE4_FLEE1
-	{SPR_EGGP,16,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE1},  // S_EGGMOBILE4_FLEE2
-	{SPR_BMCE, 0, -1, {NULL},           0,          0, S_NULL},              // S_EGGMOBILE4_MACE
-	{SPR_BMCE, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE2},  // S_EGGMOBILE4_MACE_DIE1
-	{SPR_NULL, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE3},  // S_EGGMOBILE4_MACE_DIE2
-	{SPR_NULL, 0,  0, {A_Repeat},       7, S_EGGMOBILE4_MACE_DIE1, S_SONIC3KBOSSEXPLOSION1}, // S_EGGMOBILE4_MACE_DIE3
+	{SPR_EGGP, 0, -1, {NULL},           0,          0, S_NULL, 0},              // S_EGGMOBILE4_STND
+	{SPR_EGGP, 1,  3, {NULL},           0,          0, S_EGGMOBILE4_LATK2, 0},  // S_EGGMOBILE4_LATK1
+	{SPR_EGGP, 2, 15, {NULL},           0,          0, S_EGGMOBILE4_LATK3, 0},  // S_EGGMOBILE4_LATK2
+	{SPR_EGGP, 3,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK4, 0},  // S_EGGMOBILE4_LATK3
+	{SPR_EGGP, 4,  2, {NULL},           0,          0, S_EGGMOBILE4_LATK5, 0},  // S_EGGMOBILE4_LATK4
+	{SPR_EGGP, 5, 50, {A_Boss4Reverse}, sfx_mswing, 0, S_EGGMOBILE4_LATK6, 0},  // S_EGGMOBILE4_LATK5
+	{SPR_EGGP, 6,  2, {NULL},           0,          0, S_EGGMOBILE4_STND, 0},   // S_EGGMOBILE4_LATK6
+	{SPR_EGGP, 7,  3, {NULL},           0,          0, S_EGGMOBILE4_RATK2, 0},  // S_EGGMOBILE4_RATK1
+	{SPR_EGGP, 8, 15, {NULL},           0,          0, S_EGGMOBILE4_RATK3, 0},  // S_EGGMOBILE4_RATK2
+	{SPR_EGGP, 9,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK4, 0},  // S_EGGMOBILE4_RATK3
+	{SPR_EGGP,10,  2, {NULL},           0,          0, S_EGGMOBILE4_RATK5, 0},  // S_EGGMOBILE4_RATK4
+	{SPR_EGGP,11,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6, 0},  // S_EGGMOBILE4_RATK5
+	{SPR_EGGP,12,  2, {NULL},           0,          0, S_EGGMOBILE4_STND, 0},   // S_EGGMOBILE4_RATK6
+	{SPR_EGGP,13, 20, {A_Boss4Raise},   sfx_doord1, 0, S_EGGMOBILE4_RAISE2, 0}, // S_EGGMOBILE4_RAISE1
+	{SPR_EGGP,15|FF_ANIMATE, -1, {NULL},        1,        10, S_NULL, 0},             // S_EGGMOBILE4_RAISE2
+	{SPR_EGGP,13,  0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2, 0}, // S_EGGMOBILE4_PAIN1
+	{SPR_EGGP,13, 24, {A_Pain},                 0,         0, S_EGGMOBILE4_STND, 0},  // S_EGGMOBILE4_PAIN2
+	{SPR_EGGP,14,  2, {A_Fall},         0,          0, S_EGGMOBILE4_DIE2, 0},   // S_EGGMOBILE4_DIE1
+	{SPR_EGGP,14,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_DIE3, 0},   // S_EGGMOBILE4_DIE2
+	{SPR_EGGP,14,  0, {A_Repeat},   17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4, 0},   // S_EGGMOBILE4_DIE3
+	{SPR_EGGP,14, -1, {A_BossDeath},    0,          0, S_NULL, 0},              // S_EGGMOBILE4_DIE4
+	{SPR_EGGP,15,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE2, 0},  // S_EGGMOBILE4_FLEE1
+	{SPR_EGGP,16,  2, {A_BossScream},   0,          0, S_EGGMOBILE4_FLEE1, 0},  // S_EGGMOBILE4_FLEE2
+	{SPR_BMCE, 0, -1, {NULL},           0,          0, S_NULL, 0},              // S_EGGMOBILE4_MACE
+	{SPR_BMCE, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE2, 0},  // S_EGGMOBILE4_MACE_DIE1
+	{SPR_NULL, 0,  2, {A_BossScream},   1, 0, S_EGGMOBILE4_MACE_DIE3, 0},  // S_EGGMOBILE4_MACE_DIE2
+	{SPR_NULL, 0,  0, {A_Repeat},       7, S_EGGMOBILE4_MACE_DIE1, S_SONIC3KBOSSEXPLOSION1, 0}, // S_EGGMOBILE4_MACE_DIE3
 
 	// Boss 4 jet flame
-	{SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_JETFLAME
+	{SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL, 0}, // S_JETFLAME
 
 	// Boss 4 Spectator Eggrobo
-	{SPR_EGR1,            0, -1, {NULL}, 0, 0, S_NULL},            // S_EGGROBO1_STND
-	{SPR_EGR1,            5,  2, {NULL}, 0, 0, S_EGGROBO1_BSLAP2}, // S_EGGROBO1_BSLAP1
-	{SPR_EGR1, FF_ANIMATE|6, 35, {NULL}, 1, 2, S_EGGROBO1_STND},   // S_EGGROBO1_BSLAP2
-	{SPR_EGR1, FF_ANIMATE|3, -1, {NULL}, 1, 2, S_NULL},            // S_EGGROBO1_PISSED
+	{SPR_EGR1,            0, -1, {NULL}, 0, 0, S_NULL, 0},            // S_EGGROBO1_STND
+	{SPR_EGR1,            5,  2, {NULL}, 0, 0, S_EGGROBO1_BSLAP2, 0}, // S_EGGROBO1_BSLAP1
+	{SPR_EGR1, FF_ANIMATE|6, 35, {NULL}, 1, 2, S_EGGROBO1_STND, 0},   // S_EGGROBO1_BSLAP2
+	{SPR_EGR1, FF_ANIMATE|3, -1, {NULL}, 1, 2, S_NULL, 0},            // S_EGGROBO1_PISSED
 
 	// Boss 4 Spectator Eggrobo jet flame
-	{SPR_EFIR, FF_FULLBRIGHT|2,          -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBOJET
+	{SPR_EFIR, FF_FULLBRIGHT|2,          -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGROBOJET
 
 	// Boss 5
-	{SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0}, // S_FANG_SETUP
-
-	{SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1}, // S_FANG_INTRO0
-	{SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2}, // S_FANG_INTRO1
-	{SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3}, // S_FANG_INTRO2
-	{SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4}, // S_FANG_INTRO3
-	{SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5}, // S_FANG_INTRO4
-	{SPR_FANG, 27, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6}, // S_FANG_INTRO5
-	{SPR_FANG, 28, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7}, // S_FANG_INTRO6
-	{SPR_FANG, 29, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8}, // S_FANG_INTRO7
-	{SPR_FANG, 30, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5}, // S_FANG_INTRO8
-	{SPR_FANG, 23|FF_ANIMATE, 50, {NULL}, 1, 4, S_FANG_INTRO10}, // S_FANG_INTRO9
-	{SPR_FANG, 25, 5, {NULL}, 0, 0, S_FANG_INTRO11}, // S_FANG_INTRO10
-	{SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12}, // S_FANG_INTRO11
-	{SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1}, // S_FANG_INTRO12
-
-	{SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2}, // S_FANG_CLONE1
-	{SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3}, // S_FANG_INTRO2
-	{SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4}, // S_FANG_CLONE3
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4}, // S_FANG_CLONE4
-
-	{SPR_FANG, 0,  0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1}, // S_FANG_IDLE0
-	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1
-	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3}, // S_FANG_IDLE2
-	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4}, // S_FANG_IDLE3
-	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE5}, // S_FANG_IDLE4
-	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE6}, // S_FANG_IDLE5
-	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE7}, // S_FANG_IDLE6
-	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE8}, // S_FANG_IDLE7
-	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE1}, // S_FANG_IDLE8
-
-	{SPR_FANG, 14, 0, {A_DoNPCPain}, FRACUNIT, 0, S_FANG_PAIN2}, // S_FANG_PAIN1
-	{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART1, S_FANG_PINCHPATHINGSTART1, S_FANG_PAIN2}, // S_FANG_PAIN2
-
-	{SPR_FANG,  8, 0, {A_Boss5ExtraRepeat}, 5, 4, S_FANG_PATHINGSTART2}, // S_FANG_PATHINGSTART1
-	{SPR_FANG,  8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHING}, // S_FANG_PATHINGSTART2
-	{SPR_FANG,  8, 0, {A_Boss5FindWaypoint}, 0, 0, S_FANG_BOUNCE1}, // S_FANG_PATHING
-
-	{SPR_FANG,  8, 2, {A_Thrust}, 0, 1, S_FANG_BOUNCE2}, // S_FANG_BOUNCE1
-	{SPR_FANG,  9, 2, {NULL}, 0, 0, S_FANG_BOUNCE3}, // S_FANG_BOUNCE2
-	{SPR_FANG, 10, 1, {A_Boss5Jump}, 0, 0, S_FANG_BOUNCE4}, // S_FANG_BOUNCE3
-	{SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_CHECKPATH1, S_FANG_FALL1, S_FANG_BOUNCE4}, // S_FANG_BOUNCE4
-
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL2}, // S_FANG_FALL1
-	{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL1}, // S_FANG_FALL2
-
-	{SPR_FANG,  8, 0, {A_Boss5Calm}, 0, 0, S_FANG_CHECKPATH2}, // S_FANG_CHECKPATH1
-	{SPR_FANG,  8, 0, {A_Repeat}, 0, S_FANG_PATHINGCONT1, S_FANG_SKID1}, // S_FANG_CHECKPATH2
-
-	{SPR_FANG,  9, 0, {A_Boss5PinchShot}, MT_FBOMB, -16, S_FANG_PATHINGCONT2}, // S_FANG_PATHINGCONT1
-	{SPR_FANG,  9, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHINGCONT3}, // S_FANG_PATHINGCONT2
-	{SPR_FANG,  9, 2, {A_Thrust}, 0, 1, S_FANG_PATHING}, // S_FANG_PATHINGCONT3
-
-	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_SKID2}, // S_FANG_SKID1
-	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2}, // S_FANG_SKID2
-	{SPR_FANG,  4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK}, // S_FANG_SKID3
-
-	{SPR_FANG,  0, 0, {A_RandomState}, S_FANG_LOBSHOT0, S_FANG_FIRESTART1, S_NULL}, // S_FANG_CHOOSEATTACK
-
-	{SPR_FANG,  5,  0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2}, // S_FANG_FIRESTART1 // Reset loop
-	{SPR_FANG,  5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1}, // S_FANG_FIRESTART2
-	{SPR_FANG,  5,  5, {A_FireShot}, MT_CORK, -16, S_FANG_FIRE2}, // S_FANG_FIRE1 // Start of loop
-	{SPR_FANG,  6,  5, {NULL}, 0, 0, S_FANG_FIRE3}, // S_FANG_FIRE2
-	{SPR_FANG,  7,  5, {NULL}, 0, 0, S_FANG_FIRE4}, // S_FANG_FIRE3
-	{SPR_FANG,  5,  5, {NULL}, 2, 0, S_FANG_FIREREPEAT}, // S_FANG_FIRE4
-	{SPR_FANG,  5,  0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1}, // S_FANG_FIREREPEAT // End of loop
-
-	{SPR_FANG, 18, 16, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT1}, // S_FANG_LOBSHOT0
-	{SPR_FANG, 19,  2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2}, // S_FANG_LOBSHOT1
-	{SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1}, // S_FANG_LOBSHOT2
-
-	{SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2}, // S_FANG_WAIT1
-	{SPR_FANG,             0, 35, {A_Look}, 1, 0, S_FANG_IDLE1}, // S_FANG_WAIT2
-
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART2, S_FANG_PINCHPATHINGSTART1, S_FANG_WALLHIT}, // S_FANG_WALLHIT
-
-	{SPR_FANG,  8,  0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2}, // S_FANG_PINCHPATHINGSTART1
-	{SPR_FANG,  8,  0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING}, // S_FANG_PINCHPATHINGSTART2
-	{SPR_FANG,  8,  0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE0}, // S_FANG_PINCHPATHING
-	{SPR_FANG,  8,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_FANG_PINCHBOUNCE1}, // S_FANG_PINCHBOUNCE0
-	{SPR_FANG,  8,  2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2}, // S_FANG_PINCHBOUNCE1
-	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3}, // S_FANG_PINCHBOUNCE2
-	{SPR_FANG, 10,  2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE3
-	{SPR_FANG, 10,  1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE4
-	{SPR_FANG, 12,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 1, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL0
-	{SPR_FANG, 12,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2}, // S_FANG_PINCHFALL1
-	{SPR_FANG, 13,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL2
-	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID1
-	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID2
-	{SPR_FANG, 18, 16, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT1}, // S_FANG_PINCHLOBSHOT0
-	{SPR_FANG, 19,  2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2}, // S_FANG_PINCHLOBSHOT1
-	{SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3}, // S_FANG_PINCHLOBSHOT2
-	{SPR_FANG, 20, 18, {A_LinedefExecuteFromArg}, 4, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3
-	{SPR_FANG,  0,  0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1}, // S_FANG_PINCHLOBSHOT4
-
-	{SPR_FANG, 21, 0, {A_DoNPCPain},                    0, 0, S_FANG_DIE2}, // S_FANG_DIE1
-	{SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2
-
-	{SPR_FANG, 22,  0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3
-	{SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5}, // S_FANG_DIE4
-
-	{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5
-	{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6
-	{SPR_FANG, 11, 1, {A_Boss5CheckFalling}, S_FANG_FLEEPATHING1, S_FANG_DIE8, S_FANG_DIE7}, // S_FANG_DIE7
-	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_FLEEPATHING1, 0, S_FANG_DIE8}, // S_FANG_DIE8
-
-	{SPR_FANG,  9,  0, {A_PlayActiveSound}, 0, 0, S_FANG_FLEEPATHING2}, // S_FANG_FLEEPATHING1
-	{SPR_FANG,  8,  2, {A_Boss5FindWaypoint}, 2, 0, S_FANG_FLEEBOUNCE1}, // S_FANG_FLEEPATHING2
-	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2}, // S_FANG_FLEEBOUNCE1
-	{SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_FANG_FLEEBOUNCE2
-
-	{SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO
-
-	{SPR_NULL, 0, -1, {A_RandomStateRange}, S_BROKENROBOTA, S_BROKENROBOTF, S_NULL}, // S_BROKENROBOTRANDOM
-	{SPR_BRKN,    FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTA
-	{SPR_BRKN,  4|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTB
-	{SPR_BRKN,  8|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTC
-	{SPR_BRKN, 12|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTD
-	{SPR_BRKN, 16|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTE
-	{SPR_BRKN, 20|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTF
-
-	{SPR_WHAT,   FF_ANIMATE|FF_FULLBRIGHT,  4, {NULL}, 1, 2, S_ALART2}, // S_ALART1
-	{SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL},   // S_ALART2
-
-	{SPR_VWRE,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREF
-	{SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREB
-
-	{SPR_PROJ,   FF_TRANS20|FF_FULLBRIGHT,  4, {NULL}, 0, 0, S_PROJECTORLIGHT2}, // S_PROJECTORLIGHT1
-	{SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT3}, // S_PROJECTORLIGHT2
-	{SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT4}, // S_PROJECTORLIGHT3
-	{SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT,  2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5}, // S_PROJECTORLIGHT4
-	{SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT,  2, {NULL}, 0, 0, S_NULL}, // S_PROJECTORLIGHT5
-
-	{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1
-	{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2
-	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2}, // S_FBOMB_EXPL1
-	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_Boss5BombExplode}, MT_TNTDUST, 0, S_FBOMB_EXPL3}, // S_FBOMB_EXPL2
-	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_FBOMB_EXPL4}, // S_FBOMB_EXPL3
-	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL5}, // S_FBOMB_EXPL4
-	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL6}, // S_FBOMB_EXPL5
-	{SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FBOMB_EXPL6
-	{SPR_BARD, 0|FF_TRANS90, 2, {NULL}, 0, 0, S_TNTDUST_2}, // S_TNTDUST_1
-	{SPR_BARD, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_TNTDUST_3}, // S_TNTDUST_2
-	{SPR_BARD, 0|FF_TRANS40, 10, {NULL}, 0, 0, S_TNTDUST_4}, // S_TNTDUST_3
-	{SPR_BARD, 0|FF_TRANS50, 10, {NULL}, 0, 0, S_TNTDUST_5}, // S_TNTDUST_4
-	{SPR_BARD, 0|FF_TRANS60, 10, {NULL}, 0, 0, S_TNTDUST_6}, // S_TNTDUST_5
-	{SPR_BARD, 0|FF_TRANS70, 10, {NULL}, 0, 0, S_TNTDUST_7}, // S_TNTDUST_6
-	{SPR_BARD, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_TNTDUST_8}, // S_TNTDUST_7
-	{SPR_BARD, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL}, // S_TNTDUST_8
-	{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNA
-	{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNB
-	{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNC
-	{SPR_FSGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGND
+	{SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0, 0}, // S_FANG_SETUP
+
+	{SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1, 0}, // S_FANG_INTRO0
+	{SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2, 0}, // S_FANG_INTRO1
+	{SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3, 0}, // S_FANG_INTRO2
+	{SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4, 0}, // S_FANG_INTRO3
+	{SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5, 0}, // S_FANG_INTRO4
+	{SPR_FANG, 27, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6, 0}, // S_FANG_INTRO5
+	{SPR_FANG, 28, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7, 0}, // S_FANG_INTRO6
+	{SPR_FANG, 29, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8, 0}, // S_FANG_INTRO7
+	{SPR_FANG, 30, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5, 0}, // S_FANG_INTRO8
+	{SPR_FANG, 23|FF_ANIMATE, 50, {NULL}, 1, 4, S_FANG_INTRO10, 0}, // S_FANG_INTRO9
+	{SPR_FANG, 25, 5, {NULL}, 0, 0, S_FANG_INTRO11, 0}, // S_FANG_INTRO10
+	{SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12, 0}, // S_FANG_INTRO11
+	{SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1, 0}, // S_FANG_INTRO12
+
+	{SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2, 0}, // S_FANG_CLONE1
+	{SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3, 0}, // S_FANG_INTRO2
+	{SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4, 0}, // S_FANG_CLONE3
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4, 0}, // S_FANG_CLONE4
+
+	{SPR_FANG, 0,  0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1, 0}, // S_FANG_IDLE0
+	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2, 0}, // S_FANG_IDLE1
+	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3, 0}, // S_FANG_IDLE2
+	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4, 0}, // S_FANG_IDLE3
+	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE5, 0}, // S_FANG_IDLE4
+	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE6, 0}, // S_FANG_IDLE5
+	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE7, 0}, // S_FANG_IDLE6
+	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE8, 0}, // S_FANG_IDLE7
+	{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE1, 0}, // S_FANG_IDLE8
+
+	{SPR_FANG, 14, 0, {A_DoNPCPain}, FRACUNIT, 0, S_FANG_PAIN2, 0}, // S_FANG_PAIN1
+	{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART1, S_FANG_PINCHPATHINGSTART1, S_FANG_PAIN2, 0}, // S_FANG_PAIN2
+
+	{SPR_FANG,  8, 0, {A_Boss5ExtraRepeat}, 5, 4, S_FANG_PATHINGSTART2, 0}, // S_FANG_PATHINGSTART1
+	{SPR_FANG,  8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHING, 0}, // S_FANG_PATHINGSTART2
+	{SPR_FANG,  8, 0, {A_Boss5FindWaypoint}, 0, 0, S_FANG_BOUNCE1, 0}, // S_FANG_PATHING
+
+	{SPR_FANG,  8, 2, {A_Thrust}, 0, 1, S_FANG_BOUNCE2, 0}, // S_FANG_BOUNCE1
+	{SPR_FANG,  9, 2, {NULL}, 0, 0, S_FANG_BOUNCE3, 0}, // S_FANG_BOUNCE2
+	{SPR_FANG, 10, 1, {A_Boss5Jump}, 0, 0, S_FANG_BOUNCE4, 0}, // S_FANG_BOUNCE3
+	{SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_CHECKPATH1, S_FANG_FALL1, S_FANG_BOUNCE4, 0}, // S_FANG_BOUNCE4
+
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL2, 0}, // S_FANG_FALL1
+	{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL1, 0}, // S_FANG_FALL2
+
+	{SPR_FANG,  8, 0, {A_Boss5Calm}, 0, 0, S_FANG_CHECKPATH2, 0}, // S_FANG_CHECKPATH1
+	{SPR_FANG,  8, 0, {A_Repeat}, 0, S_FANG_PATHINGCONT1, S_FANG_SKID1, 0}, // S_FANG_CHECKPATH2
+
+	{SPR_FANG,  9, 0, {A_Boss5PinchShot}, MT_FBOMB, -16, S_FANG_PATHINGCONT2, 0}, // S_FANG_PATHINGCONT1
+	{SPR_FANG,  9, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHINGCONT3, 0}, // S_FANG_PATHINGCONT2
+	{SPR_FANG,  9, 2, {A_Thrust}, 0, 1, S_FANG_PATHING, 0}, // S_FANG_PATHINGCONT3
+
+	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_SKID2, 0}, // S_FANG_SKID1
+	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2, 0}, // S_FANG_SKID2
+	{SPR_FANG,  4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK, 0}, // S_FANG_SKID3
+
+	{SPR_FANG,  0, 0, {A_RandomState}, S_FANG_LOBSHOT0, S_FANG_FIRESTART1, S_NULL, 0}, // S_FANG_CHOOSEATTACK
+
+	{SPR_FANG,  5,  0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2, 0}, // S_FANG_FIRESTART1 // Reset loop
+	{SPR_FANG,  5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1, 0}, // S_FANG_FIRESTART2
+	{SPR_FANG,  5,  5, {A_FireShot}, MT_CORK, -16, S_FANG_FIRE2, 0}, // S_FANG_FIRE1 // Start of loop
+	{SPR_FANG,  6,  5, {NULL}, 0, 0, S_FANG_FIRE3, 0}, // S_FANG_FIRE2
+	{SPR_FANG,  7,  5, {NULL}, 0, 0, S_FANG_FIRE4, 0}, // S_FANG_FIRE3
+	{SPR_FANG,  5,  5, {NULL}, 2, 0, S_FANG_FIREREPEAT, 0}, // S_FANG_FIRE4
+	{SPR_FANG,  5,  0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1, 0}, // S_FANG_FIREREPEAT // End of loop
+
+	{SPR_FANG, 18, 16, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT1, 0}, // S_FANG_LOBSHOT0
+	{SPR_FANG, 19,  2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2, 0}, // S_FANG_LOBSHOT1
+	{SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1, 0}, // S_FANG_LOBSHOT2
+
+	{SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2, 0}, // S_FANG_WAIT1
+	{SPR_FANG,             0, 35, {A_Look}, 1, 0, S_FANG_IDLE1, 0}, // S_FANG_WAIT2
+
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART2, S_FANG_PINCHPATHINGSTART1, S_FANG_WALLHIT, 0}, // S_FANG_WALLHIT
+
+	{SPR_FANG,  8,  0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2, 0}, // S_FANG_PINCHPATHINGSTART1
+	{SPR_FANG,  8,  0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING, 0}, // S_FANG_PINCHPATHINGSTART2
+	{SPR_FANG,  8,  0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE0, 0}, // S_FANG_PINCHPATHING
+	{SPR_FANG,  8,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_FANG_PINCHBOUNCE1, 0}, // S_FANG_PINCHBOUNCE0
+	{SPR_FANG,  8,  2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2, 0}, // S_FANG_PINCHBOUNCE1
+	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3, 0}, // S_FANG_PINCHBOUNCE2
+	{SPR_FANG, 10,  2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4, 0}, // S_FANG_PINCHBOUNCE3
+	{SPR_FANG, 10,  1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL0, S_FANG_PINCHBOUNCE4, 0}, // S_FANG_PINCHBOUNCE4
+	{SPR_FANG, 12,  0, {A_SetObjectFlags}, MF_NOCLIP|MF_NOCLIPHEIGHT, 1, S_FANG_PINCHFALL1, 0}, // S_FANG_PINCHFALL0
+	{SPR_FANG, 12,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2, 0}, // S_FANG_PINCHFALL1
+	{SPR_FANG, 13,  1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1, 0}, // S_FANG_PINCHFALL2
+	{SPR_FANG,  4,  0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2, 0}, // S_FANG_PINCHSKID1
+	{SPR_FANG,  4,  1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT0, 0, S_FANG_PINCHSKID2, 0}, // S_FANG_PINCHSKID2
+	{SPR_FANG, 18, 16, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT1, 0}, // S_FANG_PINCHLOBSHOT0
+	{SPR_FANG, 19,  2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2, 0}, // S_FANG_PINCHLOBSHOT1
+	{SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3, 0}, // S_FANG_PINCHLOBSHOT2
+	{SPR_FANG, 20, 18, {A_LinedefExecuteFromArg}, 4, 0, S_FANG_PINCHLOBSHOT4, 0}, // S_FANG_PINCHLOBSHOT3
+	{SPR_FANG,  0,  0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1, 0}, // S_FANG_PINCHLOBSHOT4
+
+	{SPR_FANG, 21, 0, {A_DoNPCPain},                    0, 0, S_FANG_DIE2, 0}, // S_FANG_DIE1
+	{SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2, 0}, // S_FANG_DIE2
+
+	{SPR_FANG, 22,  0, {A_Scream}, 0, 0, S_FANG_DIE4, 0}, // S_FANG_DIE3
+	{SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5, 0}, // S_FANG_DIE4
+
+	{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6, 0}, // S_FANG_DIE5
+	{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7, 0}, // S_FANG_DIE6
+	{SPR_FANG, 11, 1, {A_Boss5CheckFalling}, S_FANG_FLEEPATHING1, S_FANG_DIE8, S_FANG_DIE7, 0}, // S_FANG_DIE7
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_FLEEPATHING1, 0, S_FANG_DIE8, 0}, // S_FANG_DIE8
+
+	{SPR_FANG,  9,  0, {A_PlayActiveSound}, 0, 0, S_FANG_FLEEPATHING2, 0}, // S_FANG_FLEEPATHING1
+	{SPR_FANG,  8,  2, {A_Boss5FindWaypoint}, 2, 0, S_FANG_FLEEBOUNCE1, 0}, // S_FANG_FLEEPATHING2
+	{SPR_FANG,  9,  2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2, 0}, // S_FANG_FLEEBOUNCE1
+	{SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL, 0}, // S_FANG_FLEEBOUNCE2
+
+	{SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL, 0}, // S_FANG_KO
+
+	{SPR_NULL, 0, -1, {A_RandomStateRange}, S_BROKENROBOTA, S_BROKENROBOTF, S_NULL, 0}, // S_BROKENROBOTRANDOM
+	{SPR_BRKN,    FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTA
+	{SPR_BRKN,  4|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTB
+	{SPR_BRKN,  8|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTC
+	{SPR_BRKN, 12|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTD
+	{SPR_BRKN, 16|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTE
+	{SPR_BRKN, 20|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL, 0}, // S_BROKENROBOTF
+
+	{SPR_WHAT,   FF_ANIMATE|FF_FULLBRIGHT,  4, {NULL}, 1, 2, S_ALART2, 0}, // S_ALART1
+	{SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL, 0},   // S_ALART2
+
+	{SPR_VWRE,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_VWREF
+	{SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_VWREB
+
+	{SPR_PROJ,   FF_TRANS20|FF_FULLBRIGHT,  4, {NULL}, 0, 0, S_PROJECTORLIGHT2, 0}, // S_PROJECTORLIGHT1
+	{SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT3, 0}, // S_PROJECTORLIGHT2
+	{SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT4, 0}, // S_PROJECTORLIGHT3
+	{SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT,  2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5, 0}, // S_PROJECTORLIGHT4
+	{SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT,  2, {NULL}, 0, 0, S_NULL, 0}, // S_PROJECTORLIGHT5
+
+	{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2, 0}, // S_FBOMB1
+	{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1, 0}, // S_FBOMB2
+	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2, 0}, // S_FBOMB_EXPL1
+	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_Boss5BombExplode}, MT_TNTDUST, 0, S_FBOMB_EXPL3, 0}, // S_FBOMB_EXPL2
+	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_FBOMB_EXPL4, 0}, // S_FBOMB_EXPL3
+	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL5, 0}, // S_FBOMB_EXPL4
+	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL6, 0}, // S_FBOMB_EXPL5
+	{SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL, 0}, // S_FBOMB_EXPL6
+	{SPR_BARD, 0|FF_TRANS90, 2, {NULL}, 0, 0, S_TNTDUST_2, 0}, // S_TNTDUST_1
+	{SPR_BARD, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_TNTDUST_3, 0}, // S_TNTDUST_2
+	{SPR_BARD, 0|FF_TRANS40, 10, {NULL}, 0, 0, S_TNTDUST_4, 0}, // S_TNTDUST_3
+	{SPR_BARD, 0|FF_TRANS50, 10, {NULL}, 0, 0, S_TNTDUST_5, 0}, // S_TNTDUST_4
+	{SPR_BARD, 0|FF_TRANS60, 10, {NULL}, 0, 0, S_TNTDUST_6, 0}, // S_TNTDUST_5
+	{SPR_BARD, 0|FF_TRANS70, 10, {NULL}, 0, 0, S_TNTDUST_7, 0}, // S_TNTDUST_6
+	{SPR_BARD, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_TNTDUST_8, 0}, // S_TNTDUST_7
+	{SPR_BARD, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL, 0}, // S_TNTDUST_8
+	{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGNA
+	{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGNB
+	{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGNC
+	{SPR_FSGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FSGND
 
 	// Black Eggman (Boss 7)
-	{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND
-	{SPR_BRAK, 0, 7, {A_Look}, 1, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND2
-	{SPR_BRAK, 1, 7, {NULL}, 0, 0, S_BLACKEGG_WALK2}, // S_BLACKEGG_WALK1
-	{SPR_BRAK, 2, 7, {NULL}, 0, 0, S_BLACKEGG_WALK3}, // S_BLACKEGG_WALK2
-	{SPR_BRAK, 3, 7, {A_PlaySound}, sfx_bestep, 0, S_BLACKEGG_WALK4}, // S_BLACKEGG_WALK3
-	{SPR_BRAK, 4, 7, {NULL}, 0, 0, S_BLACKEGG_WALK5}, // S_BLACKEGG_WALK4
-	{SPR_BRAK, 5, 7, {NULL}, 0, 0, S_BLACKEGG_WALK6}, // S_BLACKEGG_WALK5
-	{SPR_BRAK, 6, 7, {A_PlaySound}, sfx_bestp2, 0, S_BLACKEGG_WALK1}, // S_BLACKEGG_WALK6
-	{SPR_BRAK, 7, 3, {NULL}, 0, 0, S_BLACKEGG_SHOOT2}, // S_BLACKEGG_SHOOT1
-	{SPR_BRAK, 24, 1, {A_PlaySound}, sfx_befire, 0, S_BLACKEGG_SHOOT1}, // S_BLACKEGG_SHOOT2
-
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN2}, // S_BLACKEGG_PAIN1
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN3}, // S_BLACKEGG_PAIN2
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN4}, // S_BLACKEGG_PAIN3
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN5}, // S_BLACKEGG_PAIN4
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN6}, // S_BLACKEGG_PAIN5
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN7}, // S_BLACKEGG_PAIN6
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN8}, // S_BLACKEGG_PAIN7
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN9}, // S_BLACKEGG_PAIN8
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN10}, // S_BLACKEGG_PAIN9
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN11}, // S_BLACKEGG_PAIN10
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN12}, // S_BLACKEGG_PAIN11
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN13}, // S_BLACKEGG_PAIN12
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN14}, // S_BLACKEGG_PAIN13
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN15}, // S_BLACKEGG_PAIN14
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN16}, // S_BLACKEGG_PAIN15
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN17}, // S_BLACKEGG_PAIN16
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN18}, // S_BLACKEGG_PAIN17
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN19}, // S_BLACKEGG_PAIN18
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN20}, // S_BLACKEGG_PAIN19
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN21}, // S_BLACKEGG_PAIN20
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN22}, // S_BLACKEGG_PAIN21
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN23}, // S_BLACKEGG_PAIN22
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN24}, // S_BLACKEGG_PAIN23
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN25}, // S_BLACKEGG_PAIN24
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN26}, // S_BLACKEGG_PAIN25
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN27}, // S_BLACKEGG_PAIN26
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN28}, // S_BLACKEGG_PAIN27
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN29}, // S_BLACKEGG_PAIN28
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN30}, // S_BLACKEGG_PAIN29
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN31}, // S_BLACKEGG_PAIN30
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN32}, // S_BLACKEGG_PAIN31
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN33}, // S_BLACKEGG_PAIN32
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN34}, // S_BLACKEGG_PAIN33
-	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN35}, // S_BLACKEGG_PAIN34
-	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_WALK1}, // S_BLACKEGG_PAIN35
-
-	{SPR_BRAK, 9, 20, {NULL}, 0, 0, S_BLACKEGG_HITFACE2}, // S_BLACKEGG_HITFACE1
-	{SPR_BRAK, 10, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE3}, // S_BLACKEGG_HITFACE2
-	{SPR_BRAK, 11, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE4}, // S_BLACKEGG_HITFACE3
-	{SPR_BRAK, 12,14, {NULL}, 0, 0, S_BLACKEGG_PAIN1}, // S_BLACKEGG_HITFACE4
-
-	{SPR_BRAK, 13, 14, {NULL}, 0, 0, S_BLACKEGG_DIE2}, // S_BLACKEGG_DIE1
-	{SPR_BRAK, 14, 7, {NULL}, 0, 0, S_BLACKEGG_DIE3}, // S_BLACKEGG_DIE2
-	{SPR_BRAK, 15, 5, {NULL}, 0, 0, S_BLACKEGG_DIE4}, // S_BLACKEGG_DIE3
-	{SPR_BRAK, 16, 3, {A_PlaySound}, sfx_bgxpld, 0, S_BLACKEGG_DIE5}, // S_BLACKEGG_DIE4
-	{SPR_BRAK, 17, -1, {NULL}, 0, 0, S_BLACKEGG_DIE5}, // S_BLACKEGG_DIE5
-
-	{SPR_BRAK, 18, 14, {NULL}, 0, 0, S_BLACKEGG_MISSILE2}, // S_BLACKEGG_MISSILE1
-	{SPR_BRAK, 19, 5, {NULL}, 0, 0, S_BLACKEGG_MISSILE3}, // S_BLACKEGG_MISSILE2
-	{SPR_BRAK, 20, 35, {A_Boss7FireMissiles}, MT_BLACKEGGMAN_MISSILE, sfx_beshot, S_BLACKEGG_JUMP1}, // S_BLACKEGG_MISSILE3
-
-	{SPR_BRAK, 21, -1, {NULL}, 0, 0, S_BLACKEGG_STND}, // S_BLACKEGG_GOOP
-
-	{SPR_BRAK, 22, 14, {A_PlaySound}, sfx_belnch, 0, S_BLACKEGG_JUMP2}, // S_BLACKEGG_JUMP1
-	{SPR_BRAK, 23, -1, {NULL}, 0, 0, S_BLACKEGG_WALK1}, // S_BLACKEGG_JUMP2
-
-	{SPR_BRAK, 21, 3*TICRATE, {NULL}, 0, 0, S_BLACKEGG_DESTROYPLAT2}, // S_BLACKEGG_DESTROYPLAT1
-	{SPR_BRAK, 21, 1, {A_PlaySound}, sfx_s3k54, 0, S_BLACKEGG_DESTROYPLAT3}, // S_BLACKEGG_DESTROYPLAT2
-	{SPR_BRAK, 21, 14, {A_LinedefExecuteFromArg}, 5, 0, S_BLACKEGG_STND}, // S_BLACKEGG_DESTROYPLAT3
-
-	{SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER}, // S_BLACKEGG_HELPER
-
-	{SPR_BGOO, FF_TRANS50  , 2, {NULL}, 0, 0, S_BLACKEGG_GOOP2}, // S_BLACKEGG_GOOP1
-	{SPR_BGOO, FF_TRANS50|1, 2, {NULL}, 0, 0, S_BLACKEGG_GOOP1}, // S_BLACKEGG_GOOP2
-	{SPR_BGOO, FF_TRANS50|2, 6*TICRATE, {A_GoopSplat}, 0, 0, S_BLACKEGG_GOOP4}, // S_BLACKEGG_GOOP3
-	{SPR_BGOO, FF_TRANS60|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP5}, // S_BLACKEGG_GOOP4
-	{SPR_BGOO, FF_TRANS70|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP6}, // S_BLACKEGG_GOOP5
-	{SPR_BGOO, FF_TRANS80|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP7}, // S_BLACKEGG_GOOP6
-	{SPR_BGOO, FF_TRANS90|2, 4, {NULL}, 0, 0, S_NULL}, // S_BLACKEGG_GOOP7
-
-	{SPR_BMSL, 0, 1, {NULL}, 0, 0, S_BLACKEGG_MISSILE}, // S_BLACKEGG_MISSILE
+	{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2, 0}, // S_BLACKEGG_STND
+	{SPR_BRAK, 0, 7, {A_Look}, 1, 0, S_BLACKEGG_STND2, 0}, // S_BLACKEGG_STND2
+	{SPR_BRAK, 1, 7, {NULL}, 0, 0, S_BLACKEGG_WALK2, 0}, // S_BLACKEGG_WALK1
+	{SPR_BRAK, 2, 7, {NULL}, 0, 0, S_BLACKEGG_WALK3, 0}, // S_BLACKEGG_WALK2
+	{SPR_BRAK, 3, 7, {A_PlaySound}, sfx_bestep, 0, S_BLACKEGG_WALK4, 0}, // S_BLACKEGG_WALK3
+	{SPR_BRAK, 4, 7, {NULL}, 0, 0, S_BLACKEGG_WALK5, 0}, // S_BLACKEGG_WALK4
+	{SPR_BRAK, 5, 7, {NULL}, 0, 0, S_BLACKEGG_WALK6, 0}, // S_BLACKEGG_WALK5
+	{SPR_BRAK, 6, 7, {A_PlaySound}, sfx_bestp2, 0, S_BLACKEGG_WALK1, 0}, // S_BLACKEGG_WALK6
+	{SPR_BRAK, 7, 3, {NULL}, 0, 0, S_BLACKEGG_SHOOT2, 0}, // S_BLACKEGG_SHOOT1
+	{SPR_BRAK, 24, 1, {A_PlaySound}, sfx_befire, 0, S_BLACKEGG_SHOOT1, 0}, // S_BLACKEGG_SHOOT2
+
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN2, 0}, // S_BLACKEGG_PAIN1
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN3, 0}, // S_BLACKEGG_PAIN2
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN4, 0}, // S_BLACKEGG_PAIN3
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN5, 0}, // S_BLACKEGG_PAIN4
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN6, 0}, // S_BLACKEGG_PAIN5
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN7, 0}, // S_BLACKEGG_PAIN6
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN8, 0}, // S_BLACKEGG_PAIN7
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN9, 0}, // S_BLACKEGG_PAIN8
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN10, 0}, // S_BLACKEGG_PAIN9
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN11, 0}, // S_BLACKEGG_PAIN10
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN12, 0}, // S_BLACKEGG_PAIN11
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN13, 0}, // S_BLACKEGG_PAIN12
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN14, 0}, // S_BLACKEGG_PAIN13
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN15, 0}, // S_BLACKEGG_PAIN14
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN16, 0}, // S_BLACKEGG_PAIN15
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN17, 0}, // S_BLACKEGG_PAIN16
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN18, 0}, // S_BLACKEGG_PAIN17
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN19, 0}, // S_BLACKEGG_PAIN18
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN20, 0}, // S_BLACKEGG_PAIN19
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN21, 0}, // S_BLACKEGG_PAIN20
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN22, 0}, // S_BLACKEGG_PAIN21
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN23, 0}, // S_BLACKEGG_PAIN22
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN24, 0}, // S_BLACKEGG_PAIN23
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN25, 0}, // S_BLACKEGG_PAIN24
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN26, 0}, // S_BLACKEGG_PAIN25
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN27, 0}, // S_BLACKEGG_PAIN26
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN28, 0}, // S_BLACKEGG_PAIN27
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN29, 0}, // S_BLACKEGG_PAIN28
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN30, 0}, // S_BLACKEGG_PAIN29
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN31, 0}, // S_BLACKEGG_PAIN30
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN32, 0}, // S_BLACKEGG_PAIN31
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN33, 0}, // S_BLACKEGG_PAIN32
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN34, 0}, // S_BLACKEGG_PAIN33
+	{SPR_BRAK, 25, 1, {NULL}, 0, 0, S_BLACKEGG_PAIN35, 0}, // S_BLACKEGG_PAIN34
+	{SPR_BRAK, 8, 1, {NULL}, 0, 0, S_BLACKEGG_WALK1, 0}, // S_BLACKEGG_PAIN35
+
+	{SPR_BRAK, 9, 20, {NULL}, 0, 0, S_BLACKEGG_HITFACE2, 0}, // S_BLACKEGG_HITFACE1
+	{SPR_BRAK, 10, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE3, 0}, // S_BLACKEGG_HITFACE2
+	{SPR_BRAK, 11, 2, {NULL}, 0, 0, S_BLACKEGG_HITFACE4, 0}, // S_BLACKEGG_HITFACE3
+	{SPR_BRAK, 12,14, {NULL}, 0, 0, S_BLACKEGG_PAIN1, 0}, // S_BLACKEGG_HITFACE4
+
+	{SPR_BRAK, 13, 14, {NULL}, 0, 0, S_BLACKEGG_DIE2, 0}, // S_BLACKEGG_DIE1
+	{SPR_BRAK, 14, 7, {NULL}, 0, 0, S_BLACKEGG_DIE3, 0}, // S_BLACKEGG_DIE2
+	{SPR_BRAK, 15, 5, {NULL}, 0, 0, S_BLACKEGG_DIE4, 0}, // S_BLACKEGG_DIE3
+	{SPR_BRAK, 16, 3, {A_PlaySound}, sfx_bgxpld, 0, S_BLACKEGG_DIE5, 0}, // S_BLACKEGG_DIE4
+	{SPR_BRAK, 17, -1, {NULL}, 0, 0, S_BLACKEGG_DIE5, 0}, // S_BLACKEGG_DIE5
+
+	{SPR_BRAK, 18, 14, {NULL}, 0, 0, S_BLACKEGG_MISSILE2, 0}, // S_BLACKEGG_MISSILE1
+	{SPR_BRAK, 19, 5, {NULL}, 0, 0, S_BLACKEGG_MISSILE3, 0}, // S_BLACKEGG_MISSILE2
+	{SPR_BRAK, 20, 35, {A_Boss7FireMissiles}, MT_BLACKEGGMAN_MISSILE, sfx_beshot, S_BLACKEGG_JUMP1, 0}, // S_BLACKEGG_MISSILE3
+
+	{SPR_BRAK, 21, -1, {NULL}, 0, 0, S_BLACKEGG_STND, 0}, // S_BLACKEGG_GOOP
+
+	{SPR_BRAK, 22, 14, {A_PlaySound}, sfx_belnch, 0, S_BLACKEGG_JUMP2, 0}, // S_BLACKEGG_JUMP1
+	{SPR_BRAK, 23, -1, {NULL}, 0, 0, S_BLACKEGG_WALK1, 0}, // S_BLACKEGG_JUMP2
+
+	{SPR_BRAK, 21, 3*TICRATE, {NULL}, 0, 0, S_BLACKEGG_DESTROYPLAT2, 0}, // S_BLACKEGG_DESTROYPLAT1
+	{SPR_BRAK, 21, 1, {A_PlaySound}, sfx_s3k54, 0, S_BLACKEGG_DESTROYPLAT3, 0}, // S_BLACKEGG_DESTROYPLAT2
+	{SPR_BRAK, 21, 14, {A_LinedefExecuteFromArg}, 5, 0, S_BLACKEGG_STND, 0}, // S_BLACKEGG_DESTROYPLAT3
+
+	{SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER, 0}, // S_BLACKEGG_HELPER
+
+	{SPR_BGOO, FF_TRANS50  , 2, {NULL}, 0, 0, S_BLACKEGG_GOOP2, 0}, // S_BLACKEGG_GOOP1
+	{SPR_BGOO, FF_TRANS50|1, 2, {NULL}, 0, 0, S_BLACKEGG_GOOP1, 0}, // S_BLACKEGG_GOOP2
+	{SPR_BGOO, FF_TRANS50|2, 6*TICRATE, {A_GoopSplat}, 0, 0, S_BLACKEGG_GOOP4, 0}, // S_BLACKEGG_GOOP3
+	{SPR_BGOO, FF_TRANS60|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP5, 0}, // S_BLACKEGG_GOOP4
+	{SPR_BGOO, FF_TRANS70|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP6, 0}, // S_BLACKEGG_GOOP5
+	{SPR_BGOO, FF_TRANS80|2, 4, {NULL}, 0, 0, S_BLACKEGG_GOOP7, 0}, // S_BLACKEGG_GOOP6
+	{SPR_BGOO, FF_TRANS90|2, 4, {NULL}, 0, 0, S_NULL, 0}, // S_BLACKEGG_GOOP7
+
+	{SPR_BMSL, 0, 1, {NULL}, 0, 0, S_BLACKEGG_MISSILE, 0}, // S_BLACKEGG_MISSILE
 
 	// New Very-Last-Minute 2.1 Brak Eggman (Cy-Brak-demon)
-	{SPR_BRAK, 0, 10, {A_Look}, 0, 0, S_CYBRAKDEMON_IDLE}, // S_CYBRAKDEMON_IDLE
-	{SPR_BRAK, 1, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK2}, // S_CYBRAKDEMON_WALK1
-	{SPR_BRAK, 2, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK3}, // S_CYBRAKDEMON_WALK2
-	{SPR_BRAK, 3, 8, {A_BrakChase}, 3, sfx_bestep, S_CYBRAKDEMON_WALK4}, // S_CYBRAKDEMON_WALK3
-	{SPR_BRAK, 4, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK5}, // S_CYBRAKDEMON_WALK4
-	{SPR_BRAK, 5, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK6}, // S_CYBRAKDEMON_WALK5
-	{SPR_BRAK, 6, 8, {A_BrakChase}, 3, sfx_bestp2, S_CYBRAKDEMON_WALK1}, // S_CYBRAKDEMON_WALK6
-	{SPR_BRAK, 7, 6, {A_RandomState}, S_CYBRAKDEMON_MISSILE_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1}, // S_CYBRAKDEMON_CHOOSE_ATTACK1
-	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK2}, // S_CYBRAKDEMON_MISSILE_ATTACK1 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK3}, // S_CYBRAKDEMON_MISSILE_ATTACK2 // Fire
-	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK4}, // S_CYBRAKDEMON_MISSILE_ATTACK3 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK5}, // S_CYBRAKDEMON_MISSILE_ATTACK4 // Fire
-	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK6}, // S_CYBRAKDEMON_MISSILE_ATTACK5 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_MISSILE_ATTACK6 // Fire
-	{SPR_BRAK, 7, 1, {A_Repeat}, 1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK2}, // S_CYBRAKDEMON_FLAME_ATTACK1 // Reset
-	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FLAME_ATTACK3}, // S_CYBRAKDEMON_FLAME_ATTACK2 // Aim
-	{SPR_BRAK, 26 + FF_FULLBRIGHT, 2, {A_BrakFireShot}, MT_CYBRAKDEMON_FLAMESHOT, 128, S_CYBRAKDEMON_FLAME_ATTACK4}, // S_CYBRAKDEMON_FLAME_ATTACK3 // Fire
-	{SPR_BRAK, 7, 1, {A_Repeat}, 30, S_CYBRAKDEMON_FLAME_ATTACK3, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_FLAME_ATTACK4 // Loop
-	{SPR_BRAK, 0, 6, {A_RandomState}, S_CYBRAKDEMON_VILE_ATTACK1, S_CYBRAKDEMON_NAPALM_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1}, // S_CYBRAKDEMON_CHOOSE_ATTACK2
-	{SPR_BRAK, 20, 0, {A_LinedefExecuteFromArg}, 5, 0, S_CYBRAKDEMON_VILE_ATTACK2}, // S_CYBRAKDEMON_VILE_ATTACK1
-	{SPR_BRAK, 20, 24, {A_VileTarget}, MT_CYBRAKDEMON_TARGET_RETICULE, 1, S_CYBRAKDEMON_VILE_ATTACK3}, // S_CYBRAKDEMON_VILE_ATTACK2
-	{SPR_BRAK, 19, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK4}, // S_CYBRAKDEMON_VILE_ATTACK3
-	{SPR_BRAK, 18, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK5}, // S_CYBRAKDEMON_VILE_ATTACK4
-	{SPR_BRAK, 8, 32, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK6}, // S_CYBRAKDEMON_VILE_ATTACK5
-	{SPR_BRAK, 20 + FF_FULLBRIGHT, 28, {A_VileAttack}, sfx_brakrx, MT_CYBRAKDEMON_VILE_EXPLOSION + (1<<16), S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_VILE_ATTACK6
-	{SPR_BRAK, 0, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_NAPALM_ATTACK2}, // S_CYBRAKDEMON_NAPALM_ATTACK1
-	{SPR_BRAK, 21 + FF_FULLBRIGHT, 8, {A_BrakLobShot}, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, 96, S_CYBRAKDEMON_NAPALM_ATTACK3}, // S_CYBRAKDEMON_NAPALM_ATTACK2
-	{SPR_BRAK, 0, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_NAPALM_ATTACK3
-	{SPR_BRAK, 0, 0, {A_SetObjectFlags2}, MF2_FRET, 1, S_CYBRAKDEMON_FINISH_ATTACK2}, // S_CYBRAKDEMON_FINISH_ATTACK1 // If just attacked, remove MF2_FRET w/out going back to spawnstate
-	{SPR_BRAK, 0, 0, {A_SetReactionTime}, 0, 0, S_CYBRAKDEMON_WALK1}, // S_CYBRAKDEMON_FINISH_ATTACK2 // If just attacked, remove MF2_FRET w/out going back to spawnstate
-	{SPR_BRAK, 18, 24, {A_Pain}, 0, 0, S_CYBRAKDEMON_PAIN2}, // S_CYBRAKDEMON_PAIN1
-	{SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN2
-	{SPR_BRAK, 18, 0, {A_LinedefExecuteFromArg}, 4, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN3
-	{SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2}, // S_CYBRAKDEMON_DIE1
-	{SPR_BRAK, 18, 2, {A_BossScream}, 2, 0, S_CYBRAKDEMON_DIE3}, // S_CYBRAKDEMON_DIE2
-	{SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4}, // S_CYBRAKDEMON_DIE3
-	{SPR_BRAK, 13, 34, {A_BossDeath}, 0, 0, S_CYBRAKDEMON_DIE5}, // S_CYBRAKDEMON_DIE4
-	{SPR_BRAK, 14, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE6}, // S_CYBRAKDEMON_DIE5
-	{SPR_BRAK, 15, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE7}, // S_CYBRAKDEMON_DIE6
-	{SPR_BRAK, 16, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE8}, // S_CYBRAKDEMON_DIE7
-	{SPR_BRAK, 17, 34, {NULL}, sfx_befall, 0, S_CYBRAKDEMON_DIE8}, // S_CYBRAKDEMON_DIE8
-	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 2, S_CYBRAKDEMON_IDLE}, // S_CYBRAKDEMON_DEINVINCIBLERIZE
-	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 1, S_CYBRAKDEMON_IDLE}, // S_CYBRAKDEMON_INVINCIBLERIZE
-
-	{SPR_RCKT, 0 + FF_FULLBRIGHT, 1, {A_SetObjectFlags2}, MF2_RAILRING, 2, S_CYBRAKDEMONMISSILE}, // S_CYBRAKDEMONMISSILE
-	{SPR_RCKT, 1 + FF_FULLBRIGHT, 8, {A_Explode}, 0, 0, S_CYBRAKDEMONMISSILE_EXPLODE2}, // S_CYBRAKDEMONMISSILE_EXPLODE1 //TODO: set missile mobj's "damage" to an appropriate radius
-	{SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3}, // S_CYBRAKDEMONMISSILE_EXPLODE2
-	{SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONMISSILE_EXPLODE3
-
-	{SPR_FLME, FF_FULLBRIGHT  , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1
-	{SPR_FLME, FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2
-	{SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3
-	{SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE
-
-	{SPR_FLAM, FF_FULLBRIGHT, 1, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST
-
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER1}, // S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER2}, // S_CYBRAKDEMONELECTRICBARRIER1
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER3}, // S_CYBRAKDEMONELECTRICBARRIER2
-	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER4}, // S_CYBRAKDEMONELECTRICBARRIER3
-	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER5}, // S_CYBRAKDEMONELECTRICBARRIER4
-	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER6}, // S_CYBRAKDEMONELECTRICBARRIER5
-	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER7}, // S_CYBRAKDEMONELECTRICBARRIER6
-	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER8}, // S_CYBRAKDEMONELECTRICBARRIER7
-	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER9}, // S_CYBRAKDEMONELECTRICBARRIER8
-	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER10}, // S_CYBRAKDEMONELECTRICBARRIER9
-	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER11}, // S_CYBRAKDEMONELECTRICBARRIER10
-	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER12}, // S_CYBRAKDEMONELECTRICBARRIER11
-	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER13}, // S_CYBRAKDEMONELECTRICBARRIER12
-	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER14}, // S_CYBRAKDEMONELECTRICBARRIER13
-	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER15}, // S_CYBRAKDEMONELECTRICBARRIER14
-	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER16}, // S_CYBRAKDEMONELECTRICBARRIER15
-	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER17}, // S_CYBRAKDEMONELECTRICBARRIER16
-	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER18}, // S_CYBRAKDEMONELECTRICBARRIER17
-	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER19}, // S_CYBRAKDEMONELECTRICBARRIER18
-	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER20}, // S_CYBRAKDEMONELECTRICBARRIER19
-	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER21}, // S_CYBRAKDEMONELECTRICBARRIER20
-	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER22}, // S_CYBRAKDEMONELECTRICBARRIER21
-	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER23}, // S_CYBRAKDEMONELECTRICBARRIER22
-	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER24}, // S_CYBRAKDEMONELECTRICBARRIER23
-	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER24
-	{SPR_NULL, 0, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_DEINVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_DIE2}, // S_CYBRAKDEMONELECTRICBARRIER_DIE1
-	{SPR_NULL, 0, 0, {A_SetObjectFlags}, MF_PUSHABLE|MF_FIRE|MF_PAIN, 1, S_CYBRAKDEMONELECTRICBARRIER_DIE3}, // S_CYBRAKDEMONELECTRICBARRIER_DIE2
-	{SPR_NULL, 0, 20*TICRATE, {A_Scream}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS}, // S_CYBRAKDEMONELECTRICBARRIER_DIE3
-	{SPR_NULL, 0, 0, {A_CheckRandom}, 10, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK,
-	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS,
-	{SPR_NULL, 0, 0, {A_RandomStateRange}, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE,
-	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1,
-	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM2,
-	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM3,
-	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM4,
-	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM5,
-	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM6,
-	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM7,
-	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM8,
-	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM9,
-	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM10,
-	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM11,
-	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12,
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL,
-	{SPR_NULL, 0, 0, {A_Repeat}, 5*TICRATE, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK, S_CYBRAKDEMONELECTRICBARRIER_REVIVE1}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP,
-	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE2}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE1
-	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE3}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE2
-	{SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE3
-
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|1, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|2, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|3, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|4, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|5, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13
-	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL}, // S_CYBRAKDEMONTARGETRETICULE14
-
-	{SPR_HOOP, FF_TRANS50|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONTARGETDOT
-
-	{SPR_NPLM, 0, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1,
-	{SPR_NPLM, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
-	{SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
-	{SPR_NPLM, 3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4,
-	{SPR_NPLM, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE1, // Explode
-	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (6<<16), 256 + (48<<16), S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2, // Outer ring
-	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (1<<16), 32<<16, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3, // Center
-	{SPR_NULL, 0, 81, {A_Scream}, 0, 0, S_NULL}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4, // Sound
-
-	{SPR_MNPL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL}, //S_CYBRAKDEMONNAPALMBOMBSMALL,
-	{SPR_MNPL, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE1, // Explode
-	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (12<<16), 128 + (40<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2, // Outer ring
-	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (8<<16), 64 + (32<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3, // Inner ring
-	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (1<<16), 24<<16, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4, // Center
-	{SPR_NULL, 0, 24, {A_Scream}, 0, 0, S_NULL}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5, // Sound
-
-	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY2}, //S_CYBRAKDEMONNAPALMFLAME_FLY1,
-	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY3}, //S_CYBRAKDEMONNAPALMFLAME_FLY2,
-	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY4}, //S_CYBRAKDEMONNAPALMFLAME_FLY3,
-	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY5}, //S_CYBRAKDEMONNAPALMFLAME_FLY4,
-	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY6}, //S_CYBRAKDEMONNAPALMFLAME_FLY5,
-	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY1}, //S_CYBRAKDEMONNAPALMFLAME_FLY6,
-	{SPR_SFLM, FF_FULLBRIGHT,   0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, //S_CYBRAKDEMONNAPALMFLAME_DIE,
-
-	{SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2}, //S_CYBRAKDEMONVILEEXPLOSION1,
-	{SPR_NULL, 0, 0, {A_ScoreRise}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION3}, //S_CYBRAKDEMONVILEEXPLOSION2,
-	{SPR_NULL, 0, 1, {A_BossScream}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION1}, //S_CYBRAKDEMONVILEEXPLOSION3,
+	{SPR_BRAK, 0, 10, {A_Look}, 0, 0, S_CYBRAKDEMON_IDLE, 0}, // S_CYBRAKDEMON_IDLE
+	{SPR_BRAK, 1, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK2, 0}, // S_CYBRAKDEMON_WALK1
+	{SPR_BRAK, 2, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK3, 0}, // S_CYBRAKDEMON_WALK2
+	{SPR_BRAK, 3, 8, {A_BrakChase}, 3, sfx_bestep, S_CYBRAKDEMON_WALK4, 0}, // S_CYBRAKDEMON_WALK3
+	{SPR_BRAK, 4, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK5, 0}, // S_CYBRAKDEMON_WALK4
+	{SPR_BRAK, 5, 8, {A_BrakChase}, 3, 0, S_CYBRAKDEMON_WALK6, 0}, // S_CYBRAKDEMON_WALK5
+	{SPR_BRAK, 6, 8, {A_BrakChase}, 3, sfx_bestp2, S_CYBRAKDEMON_WALK1, 0}, // S_CYBRAKDEMON_WALK6
+	{SPR_BRAK, 7, 6, {A_RandomState}, S_CYBRAKDEMON_MISSILE_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1, 0}, // S_CYBRAKDEMON_CHOOSE_ATTACK1
+	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK2, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK1 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK3, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK2 // Fire
+	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK4, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK3 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_MISSILE_ATTACK5, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK4 // Fire
+	{SPR_BRAK, 7, 12, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_MISSILE_ATTACK6, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK5 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 12, {A_BrakFireShot}, MT_CYBRAKDEMON_MISSILE, 128, S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_MISSILE_ATTACK6 // Fire
+	{SPR_BRAK, 7, 1, {A_Repeat}, 1, S_CYBRAKDEMON_FLAME_ATTACK1, S_CYBRAKDEMON_FLAME_ATTACK2, 0}, // S_CYBRAKDEMON_FLAME_ATTACK1 // Reset
+	{SPR_BRAK, 7, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FLAME_ATTACK3, 0}, // S_CYBRAKDEMON_FLAME_ATTACK2 // Aim
+	{SPR_BRAK, 26 + FF_FULLBRIGHT, 2, {A_BrakFireShot}, MT_CYBRAKDEMON_FLAMESHOT, 128, S_CYBRAKDEMON_FLAME_ATTACK4, 0}, // S_CYBRAKDEMON_FLAME_ATTACK3 // Fire
+	{SPR_BRAK, 7, 1, {A_Repeat}, 30, S_CYBRAKDEMON_FLAME_ATTACK3, S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_FLAME_ATTACK4 // Loop
+	{SPR_BRAK, 0, 6, {A_RandomState}, S_CYBRAKDEMON_VILE_ATTACK1, S_CYBRAKDEMON_NAPALM_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1, 0}, // S_CYBRAKDEMON_CHOOSE_ATTACK2
+	{SPR_BRAK, 20, 0, {A_LinedefExecuteFromArg}, 5, 0, S_CYBRAKDEMON_VILE_ATTACK2, 0}, // S_CYBRAKDEMON_VILE_ATTACK1
+	{SPR_BRAK, 20, 24, {A_VileTarget}, MT_CYBRAKDEMON_TARGET_RETICULE, 1, S_CYBRAKDEMON_VILE_ATTACK3, 0}, // S_CYBRAKDEMON_VILE_ATTACK2
+	{SPR_BRAK, 19, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK4, 0}, // S_CYBRAKDEMON_VILE_ATTACK3
+	{SPR_BRAK, 18, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK5, 0}, // S_CYBRAKDEMON_VILE_ATTACK4
+	{SPR_BRAK, 8, 32, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK6, 0}, // S_CYBRAKDEMON_VILE_ATTACK5
+	{SPR_BRAK, 20 + FF_FULLBRIGHT, 28, {A_VileAttack}, sfx_brakrx, MT_CYBRAKDEMON_VILE_EXPLOSION + (1<<16), S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_VILE_ATTACK6
+	{SPR_BRAK, 0, 6, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_NAPALM_ATTACK2, 0}, // S_CYBRAKDEMON_NAPALM_ATTACK1
+	{SPR_BRAK, 21 + FF_FULLBRIGHT, 8, {A_BrakLobShot}, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, 96, S_CYBRAKDEMON_NAPALM_ATTACK3, 0}, // S_CYBRAKDEMON_NAPALM_ATTACK2
+	{SPR_BRAK, 0, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_FINISH_ATTACK1, 0}, // S_CYBRAKDEMON_NAPALM_ATTACK3
+	{SPR_BRAK, 0, 0, {A_SetObjectFlags2}, MF2_FRET, 1, S_CYBRAKDEMON_FINISH_ATTACK2, 0}, // S_CYBRAKDEMON_FINISH_ATTACK1 // If just attacked, remove MF2_FRET w/out going back to spawnstate
+	{SPR_BRAK, 0, 0, {A_SetReactionTime}, 0, 0, S_CYBRAKDEMON_WALK1, 0}, // S_CYBRAKDEMON_FINISH_ATTACK2 // If just attacked, remove MF2_FRET w/out going back to spawnstate
+	{SPR_BRAK, 18, 24, {A_Pain}, 0, 0, S_CYBRAKDEMON_PAIN2, 0}, // S_CYBRAKDEMON_PAIN1
+	{SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1, 0}, // S_CYBRAKDEMON_PAIN2
+	{SPR_BRAK, 18, 0, {A_LinedefExecuteFromArg}, 4, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1, 0}, // S_CYBRAKDEMON_PAIN3
+	{SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2, 0}, // S_CYBRAKDEMON_DIE1
+	{SPR_BRAK, 18, 2, {A_BossScream}, 2, 0, S_CYBRAKDEMON_DIE3, 0}, // S_CYBRAKDEMON_DIE2
+	{SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4, 0}, // S_CYBRAKDEMON_DIE3
+	{SPR_BRAK, 13, 34, {A_BossDeath}, 0, 0, S_CYBRAKDEMON_DIE5, 0}, // S_CYBRAKDEMON_DIE4
+	{SPR_BRAK, 14, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE6, 0}, // S_CYBRAKDEMON_DIE5
+	{SPR_BRAK, 15, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE7, 0}, // S_CYBRAKDEMON_DIE6
+	{SPR_BRAK, 16, 34, {NULL}, 0, 0, S_CYBRAKDEMON_DIE8, 0}, // S_CYBRAKDEMON_DIE7
+	{SPR_BRAK, 17, 34, {NULL}, sfx_befall, 0, S_CYBRAKDEMON_DIE8, 0}, // S_CYBRAKDEMON_DIE8
+	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 2, S_CYBRAKDEMON_IDLE, 0}, // S_CYBRAKDEMON_DEINVINCIBLERIZE
+	{SPR_BRAK, 0, 0, {A_SetObjectFlags}, MF_SPECIAL|MF_SHOOTABLE, 1, S_CYBRAKDEMON_IDLE, 0}, // S_CYBRAKDEMON_INVINCIBLERIZE
+
+	{SPR_RCKT, 0 + FF_FULLBRIGHT, 1, {A_SetObjectFlags2}, MF2_RAILRING, 2, S_CYBRAKDEMONMISSILE, 0}, // S_CYBRAKDEMONMISSILE
+	{SPR_RCKT, 1 + FF_FULLBRIGHT, 8, {A_Explode}, 0, 0, S_CYBRAKDEMONMISSILE_EXPLODE2, 0}, // S_CYBRAKDEMONMISSILE_EXPLODE1 //TODO: set missile mobj's "damage" to an appropriate radius
+	{SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3, 0}, // S_CYBRAKDEMONMISSILE_EXPLODE2
+	{SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL, 0}, // S_CYBRAKDEMONMISSILE_EXPLODE3
+
+	{SPR_FLME, FF_FULLBRIGHT  , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2, 0}, // S_CYBRAKDEMONFLAMESHOT_FLY1
+	{SPR_FLME, FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3, 0}, // S_CYBRAKDEMONFLAMESHOT_FLY2
+	{SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3, 0}, // S_CYBRAKDEMONFLAMESHOT_FLY3
+	{SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL, 0}, // S_CYBRAKDEMONFLAMESHOT_DIE
+
+	{SPR_FLAM, FF_FULLBRIGHT, 1, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST, 0}, // S_CYBRAKDEMONFLAMEREST
+
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2, 0}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND, 0}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER1, 0}, // S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER2, 0}, // S_CYBRAKDEMONELECTRICBARRIER1
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER3, 0}, // S_CYBRAKDEMONELECTRICBARRIER2
+	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER4, 0}, // S_CYBRAKDEMONELECTRICBARRIER3
+	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER5, 0}, // S_CYBRAKDEMONELECTRICBARRIER4
+	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER6, 0}, // S_CYBRAKDEMONELECTRICBARRIER5
+	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER7, 0}, // S_CYBRAKDEMONELECTRICBARRIER6
+	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER8, 0}, // S_CYBRAKDEMONELECTRICBARRIER7
+	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER9, 0}, // S_CYBRAKDEMONELECTRICBARRIER8
+	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER10, 0}, // S_CYBRAKDEMONELECTRICBARRIER9
+	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER11, 0}, // S_CYBRAKDEMONELECTRICBARRIER10
+	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER12, 0}, // S_CYBRAKDEMONELECTRICBARRIER11
+	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER13, 0}, // S_CYBRAKDEMONELECTRICBARRIER12
+	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER14, 0}, // S_CYBRAKDEMONELECTRICBARRIER13
+	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER15, 0}, // S_CYBRAKDEMONELECTRICBARRIER14
+	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER16, 0}, // S_CYBRAKDEMONELECTRICBARRIER15
+	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER17, 0}, // S_CYBRAKDEMONELECTRICBARRIER16
+	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER18, 0}, // S_CYBRAKDEMONELECTRICBARRIER17
+	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER19, 0}, // S_CYBRAKDEMONELECTRICBARRIER18
+	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER20, 0}, // S_CYBRAKDEMONELECTRICBARRIER19
+	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER21, 0}, // S_CYBRAKDEMONELECTRICBARRIER20
+	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER22, 0}, // S_CYBRAKDEMONELECTRICBARRIER21
+	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER23, 0}, // S_CYBRAKDEMONELECTRICBARRIER22
+	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER24, 0}, // S_CYBRAKDEMONELECTRICBARRIER23
+	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND, 0}, // S_CYBRAKDEMONELECTRICBARRIER24
+	{SPR_NULL, 0, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_DEINVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_DIE2, 0}, // S_CYBRAKDEMONELECTRICBARRIER_DIE1
+	{SPR_NULL, 0, 0, {A_SetObjectFlags}, MF_PUSHABLE|MF_FIRE|MF_PAIN, 1, S_CYBRAKDEMONELECTRICBARRIER_DIE3, 0}, // S_CYBRAKDEMONELECTRICBARRIER_DIE2
+	{SPR_NULL, 0, 20*TICRATE, {A_Scream}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS, 0}, // S_CYBRAKDEMONELECTRICBARRIER_DIE3
+	{SPR_NULL, 0, 0, {A_CheckRandom}, 10, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK,
+	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS,
+	{SPR_NULL, 0, 0, {A_RandomStateRange}, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE,
+	{SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1,
+	{SPR_ELEC, 1 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM2,
+	{SPR_ELEC, 2 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM3,
+	{SPR_ELEC, 3 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM4,
+	{SPR_ELEC, 4 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM5,
+	{SPR_ELEC, 5 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM6,
+	{SPR_ELEC, 6 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM7,
+	{SPR_ELEC, 7 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM8,
+	{SPR_ELEC, 8 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM9,
+	{SPR_ELEC, 9 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM10,
+	{SPR_ELEC, 10 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM11,
+	{SPR_ELEC, 11 + FF_FULLBRIGHT, 1, {A_PlaySound}, sfx_s3k5c, 1, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12,
+	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL,
+	{SPR_NULL, 0, 0, {A_Repeat}, 5*TICRATE, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK, S_CYBRAKDEMONELECTRICBARRIER_REVIVE1, 0}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP,
+	{SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE2, 0}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE1
+	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE3, 0}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE2
+	{SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL, 0}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE3
+
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2, 0}, // S_CYBRAKDEMONTARGETRETICULE1
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3, 0}, // S_CYBRAKDEMONTARGETRETICULE2
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|1, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4, 0}, // S_CYBRAKDEMONTARGETRETICULE3
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5, 0}, // S_CYBRAKDEMONTARGETRETICULE4
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|2, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6, 0}, // S_CYBRAKDEMONTARGETRETICULE5
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7, 0}, // S_CYBRAKDEMONTARGETRETICULE6
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|3, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8, 0}, // S_CYBRAKDEMONTARGETRETICULE7
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9, 0}, // S_CYBRAKDEMONTARGETRETICULE8
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|4, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10, 0}, // S_CYBRAKDEMONTARGETRETICULE9
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11, 0}, // S_CYBRAKDEMONTARGETRETICULE10
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|5, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12, 0}, // S_CYBRAKDEMONTARGETRETICULE11
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13, 0}, // S_CYBRAKDEMONTARGETRETICULE12
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT  , 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14, 0}, // S_CYBRAKDEMONTARGETRETICULE13
+	{SPR_TARG, FF_TRANS50|FF_FULLBRIGHT|6, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL, 0}, // S_CYBRAKDEMONTARGETRETICULE14
+
+	{SPR_HOOP, FF_TRANS50|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_CYBRAKDEMONTARGETDOT
+
+	{SPR_NPLM, 0, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1,
+	{SPR_NPLM, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
+	{SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
+	{SPR_NPLM, 3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4,
+	{SPR_NPLM, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE1, // Explode
+	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (6<<16), 256 + (48<<16), S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2, // Outer ring
+	{SPR_NPLM, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL + (1<<16), 32<<16, S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3, // Center
+	{SPR_NULL, 0, 81, {A_Scream}, 0, 0, S_NULL, 0}, //S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4, // Sound
+
+	{SPR_MNPL, 0, 1, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL,
+	{SPR_MNPL, 0, 1, {A_Explode}, 0, 0, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE1, // Explode
+	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (12<<16), 128 + (40<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2, // Outer ring
+	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (8<<16), 64 + (32<<16), S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3, // Inner ring
+	{SPR_MNPL, 0, 1, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (1<<16), 24<<16, S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4, // Center
+	{SPR_NULL, 0, 24, {A_Scream}, 0, 0, S_NULL, 0}, //S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5, // Sound
+
+	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY2, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY1,
+	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY3, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY2,
+	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY4, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY3,
+	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY5, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY4,
+	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY6, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY5,
+	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMFLAME_FLY1, 0}, //S_CYBRAKDEMONNAPALMFLAME_FLY6,
+	{SPR_SFLM, FF_FULLBRIGHT,   0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL, 0}, //S_CYBRAKDEMONNAPALMFLAME_DIE,
+
+	{SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2, 0}, //S_CYBRAKDEMONVILEEXPLOSION1,
+	{SPR_NULL, 0, 0, {A_ScoreRise}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION3, 0}, //S_CYBRAKDEMONVILEEXPLOSION2,
+	{SPR_NULL, 0, 1, {A_BossScream}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION1, 0}, //S_CYBRAKDEMONVILEEXPLOSION3,
 
 	// Metal Sonic
-	{SPR_PLAY, SPR2_STND, -1, {NULL}, 0, 0, S_METALSONIC_RACE}, // S_METALSONIC_RACE
-
-	{SPR_METL,  4, -1, {NULL},         0, 0, S_METALSONIC_FLOAT},             // S_METALSONIC_FLOAT
-	{SPR_METL, 16|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
-	{SPR_METL, 15, -1, {NULL},         0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
-	{SPR_METL, 17, 20, {NULL},         0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
-	{SPR_METL, 18, -1, {NULL},         0, 0, S_METALSONIC_FLOAT},             // S_METALSONIC_GATHER
-	{SPR_METL,  6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH
-	{SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_FLOAT},             // S_METALSONIC_BOUNCE
-	{SPR_METL, 14, -1, {NULL},         0, 0, S_METALSONIC_FLOAT},             // S_METALSONIC_BADBOUNCE
-	{SPR_METL, 17, -1, {NULL},         0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
-	{SPR_METL, 15, 40, {A_Pain},       0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
-	{SPR_METL, 17,  2, {A_Fall},       0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
-	{SPR_METL, 17,  4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
-	{SPR_METL, 17,  0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
-	{SPR_METL, 17, -1, {A_BossDeath},  0, 0, S_NULL},             // S_METALSONIC_DEATH4
-	{SPR_METL, 15,  1, {A_BossScream},         0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
-	{SPR_METL, 15,  7, {NULL},                 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE2
-
-	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL},  // S_MSSHIELD_F1
-	{SPR_MSCF, FF_FULLBRIGHT|FF_ANIMATE|12, -1, {NULL}, 8, 2, S_NULL},  // S_MSSHIELD_F2
+	{SPR_PLAY, SPR2_STND, -1, {NULL}, 0, 0, S_METALSONIC_RACE, 0}, // S_METALSONIC_RACE
+
+	{SPR_METL,  4, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_FLOAT
+	{SPR_METL, 16|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN, 0}, // S_METALSONIC_VECTOR
+	{SPR_METL, 15, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_STUN
+	{SPR_METL, 17, 20, {NULL},         0, 0, S_METALSONIC_GATHER, 0},// S_METALSONIC_RAISE
+	{SPR_METL, 18, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_GATHER
+	{SPR_METL,  6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE, 0},// S_METALSONIC_DASH
+	{SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_BOUNCE
+	{SPR_METL, 14, -1, {NULL},         0, 0, S_METALSONIC_FLOAT, 0},             // S_METALSONIC_BADBOUNCE
+	{SPR_METL, 17, -1, {NULL},         0, 0, S_METALSONIC_GATHER, 0},// S_METALSONIC_SHOOT
+	{SPR_METL, 15, 40, {A_Pain},       0, 0, S_METALSONIC_FLOAT, 0}, // S_METALSONIC_PAIN
+	{SPR_METL, 17,  2, {A_Fall},       0, 0, S_METALSONIC_DEATH2, 0},// S_METALSONIC_DEATH1
+	{SPR_METL, 17,  4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3, 0},// S_METALSONIC_DEATH2
+	{SPR_METL, 17,  0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4, 0}, // S_METALSONIC_DEATH3
+	{SPR_METL, 17, -1, {A_BossDeath},  0, 0, S_NULL, 0},             // S_METALSONIC_DEATH4
+	{SPR_METL, 15,  1, {A_BossScream},         0, 0, S_METALSONIC_FLEE2, 0}, // S_METALSONIC_FLEE1
+	{SPR_METL, 15,  7, {NULL},                 0, 0, S_METALSONIC_FLEE1, 0}, // S_METALSONIC_FLEE2
+
+	{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL, 0},  // S_MSSHIELD_F1
+	{SPR_MSCF, FF_FULLBRIGHT|FF_ANIMATE|12, -1, {NULL}, 8, 2, S_NULL, 0},  // S_MSSHIELD_F2
 
 	// Ring
-	{SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING}, // S_RING
+	{SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING, 0}, // S_RING
 
 	// Blue Sphere for special stages
-	{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE
+	{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUESPHERE
 	{SPR_SPHR, FF_FULLBRIGHT
 #ifdef MANIASPHERES
 							|FF_ANIMATE|FF_RANDOMANIM
 #endif
-													, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS
-	{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK
+													, -1, {NULL}, 1, 4, S_NULL, 0}, // S_BLUESPHEREBONUS
+	{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL, 0}, // S_BLUESPHERESPARK
 
 	// Bomb Sphere
-	{SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1
-	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2
-	{SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3
-	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4
+	{SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2, 0}, // S_BOMBSPHERE1
+	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3, 0}, // S_BOMBSPHERE2
+	{SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4, 0}, // S_BOMBSPHERE3
+	{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1, 0}, // S_BOMBSPHERE4
 
 	// NiGHTS Chip
-	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE,    -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIP
-	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIPBONUS
+	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE,    -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIP
+	{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIPBONUS
 
 	// NiGHTS Star
-	{SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_NIGHTSSTAR
-	{SPR_NSTR, 15, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSTARXMAS
+	{SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL, 0}, // S_NIGHTSSTAR
+	{SPR_NSTR, 15, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSSTARXMAS
 
 	// Gravity Well sprites for Egg Rock's Special Stage
-	{SPR_GWLG, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_GRAVWELLGREEN
-	{SPR_GWLR, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_GRAVWELLRED
+	{SPR_GWLG, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_GRAVWELLGREEN
+	{SPR_GWLR, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_GRAVWELLRED
 
 	// Individual Team Rings (now with shield attracting action! =P)
-	{SPR_TRNG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_TEAMRING},  // S_TEAMRING
+	{SPR_TRNG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_TEAMRING, 0},  // S_TEAMRING
 
 	// Special Stage Token
-	{SPR_TOKE, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_TOKEN}, // S_TOKEN
+	{SPR_TOKE, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_TOKEN, 0}, // S_TOKEN
 
 	// CTF Flags
-	{SPR_RFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REDFLAG
-	{SPR_BFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEFLAG
+	{SPR_RFLG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_REDFLAG
+	{SPR_BFLG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUEFLAG
 
 	// Emblem
-	{SPR_EMBM,  0, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM1
-	{SPR_EMBM,  1, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM2
-	{SPR_EMBM,  2, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM3
-	{SPR_EMBM,  3, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM4
-	{SPR_EMBM,  4, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM5
-	{SPR_EMBM,  5, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM6
-	{SPR_EMBM,  6, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM7
-	{SPR_EMBM,  7, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM8
-	{SPR_EMBM,  8, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM9
-	{SPR_EMBM,  9, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM10
-	{SPR_EMBM, 10, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM11
-	{SPR_EMBM, 11, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM12
-	{SPR_EMBM, 12, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM13
-	{SPR_EMBM, 13, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM14
-	{SPR_EMBM, 14, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM15
-	{SPR_EMBM, 15, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM16
-	{SPR_EMBM, 16, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM17
-	{SPR_EMBM, 17, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM18
-	{SPR_EMBM, 18, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM19
-	{SPR_EMBM, 19, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM20
-	{SPR_EMBM, 20, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM21
-	{SPR_EMBM, 21, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM22
-	{SPR_EMBM, 22, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM23
-	{SPR_EMBM, 23, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM24
-	{SPR_EMBM, 24, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM25
-	{SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM26
+	{SPR_EMBM,  0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM1
+	{SPR_EMBM,  1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM2
+	{SPR_EMBM,  2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM3
+	{SPR_EMBM,  3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM4
+	{SPR_EMBM,  4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM5
+	{SPR_EMBM,  5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM6
+	{SPR_EMBM,  6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM7
+	{SPR_EMBM,  7, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM8
+	{SPR_EMBM,  8, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM9
+	{SPR_EMBM,  9, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM10
+	{SPR_EMBM, 10, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM11
+	{SPR_EMBM, 11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM12
+	{SPR_EMBM, 12, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM13
+	{SPR_EMBM, 13, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM14
+	{SPR_EMBM, 14, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM15
+	{SPR_EMBM, 15, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM16
+	{SPR_EMBM, 16, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM17
+	{SPR_EMBM, 17, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM18
+	{SPR_EMBM, 18, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM19
+	{SPR_EMBM, 19, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM20
+	{SPR_EMBM, 20, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM21
+	{SPR_EMBM, 21, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM22
+	{SPR_EMBM, 22, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM23
+	{SPR_EMBM, 23, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM24
+	{SPR_EMBM, 24, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM25
+	{SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EMBLEM26
 
 	// Chaos Emeralds
-	{SPR_CEMG, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL}, // S_CEMG1
-	{SPR_CEMG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG2
-	{SPR_CEMG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG3
-	{SPR_CEMG, FF_FULLBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG4
-	{SPR_CEMG, FF_FULLBRIGHT|4, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG5
-	{SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG6
-	{SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG7
+	{SPR_CEMG, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG1
+	{SPR_CEMG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG2
+	{SPR_CEMG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG3
+	{SPR_CEMG, FF_FULLBRIGHT|3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG4
+	{SPR_CEMG, FF_FULLBRIGHT|4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG5
+	{SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG6
+	{SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG7
 
 	// Emerald hunt shards
-	{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1
-	{SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD2
-	{SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD3
+	{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD1
+	{SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD2
+	{SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD3
 
 	// Bubble Source
-	{SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2}, // S_BUBBLES1
-	{SPR_BBLS, 1, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES3}, // S_BUBBLES2
-	{SPR_BBLS, 2, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES4}, // S_BUBBLES3
-	{SPR_BBLS, 3, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES1}, // S_BUBBLES4
+	{SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2, 0}, // S_BUBBLES1
+	{SPR_BBLS, 1, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES3, 0}, // S_BUBBLES2
+	{SPR_BBLS, 2, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES4, 0}, // S_BUBBLES3
+	{SPR_BBLS, 3, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES1, 0}, // S_BUBBLES4
 
 	// Level End Sign
-	{SPR_SIGN,                 0, -1, {A_SignPlayer}, -3, 0, S_NULL},                // S_SIGN
-	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN2},           // S_SIGNSPIN1
-	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN1, S_SIGNSPIN3}, // S_SIGNSPIN2
-	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -2, 0, S_SIGNSPIN4},           // S_SIGNSPIN3
-	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN5},           // S_SIGNSPIN4
-	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN4, S_SIGNSPIN6}, // S_SIGNSPIN5
-	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -3, 0, S_SIGNSPIN1},           // S_SIGNSPIN6
-	{SPR_SIGN,                 0,  1, {A_SignPlayer}, -1, 0, S_SIGNSLOW},            // S_SIGNPLAYER
-	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSLOW},            // S_SIGNSLOW
-	{SPR_SIGN,                 0, -1,         {NULL},  0, 0, S_NULL},                // S_SIGNSTOP
-	{SPR_SIGN, FF_PAPERSPRITE| 2, -1,         {NULL},  0, 0, S_NULL},                // S_SIGNBOARD
-	{SPR_SIGN, FF_PAPERSPRITE| 1, -1,         {NULL},  0, 29, S_NULL},               // S_EGGMANSIGN
-	{SPR_SIGN, FF_PAPERSPRITE|18, -1,         {NULL},  0, 29, S_NULL},               // S_CLEARSIGN
+	{SPR_SIGN,                 0, -1, {A_SignPlayer}, -3, 0, S_NULL, 0},                // S_SIGN
+	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN2, 0},           // S_SIGNSPIN1
+	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN1, S_SIGNSPIN3, 0}, // S_SIGNSPIN2
+	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -2, 0, S_SIGNSPIN4, 0},           // S_SIGNSPIN3
+	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSPIN5, 0},           // S_SIGNSPIN4
+	{SPR_SIGN,                 0,  0,     {A_Repeat},  4, S_SIGNSPIN4, S_SIGNSPIN6, 0}, // S_SIGNSPIN5
+	{SPR_SIGN,                 0,  0, {A_SignPlayer}, -3, 0, S_SIGNSPIN1, 0},           // S_SIGNSPIN6
+	{SPR_SIGN,                 0,  1, {A_SignPlayer}, -1, 0, S_SIGNSLOW, 0},            // S_SIGNPLAYER
+	{SPR_SIGN,                 0,  1,   {A_SignSpin}, 30, 0, S_SIGNSLOW, 0},            // S_SIGNSLOW
+	{SPR_SIGN,                 0, -1,         {NULL},  0, 0, S_NULL, 0},                // S_SIGNSTOP
+	{SPR_SIGN, FF_PAPERSPRITE| 2, -1,         {NULL},  0, 0, S_NULL, 0},                // S_SIGNBOARD
+	{SPR_SIGN, FF_PAPERSPRITE| 1, -1,         {NULL},  0, 29, S_NULL, 0},               // S_EGGMANSIGN
+	{SPR_SIGN, FF_PAPERSPRITE|18, -1,         {NULL},  0, 29, S_NULL, 0},               // S_CLEARSIGN
 
 	// Spike Ball
-	{SPR_SPIK, 0, 1, {NULL}, 0, 0, S_SPIKEBALL2}, // S_SPIKEBALL1
-	{SPR_SPIK, 1, 1, {NULL}, 0, 0, S_SPIKEBALL3}, // S_SPIKEBALL2
-	{SPR_SPIK, 2, 1, {NULL}, 0, 0, S_SPIKEBALL4}, // S_SPIKEBALL3
-	{SPR_SPIK, 3, 1, {NULL}, 0, 0, S_SPIKEBALL5}, // S_SPIKEBALL4
-	{SPR_SPIK, 4, 1, {NULL}, 0, 0, S_SPIKEBALL6}, // S_SPIKEBALL5
-	{SPR_SPIK, 5, 1, {NULL}, 0, 0, S_SPIKEBALL7}, // S_SPIKEBALL6
-	{SPR_SPIK, 6, 1, {NULL}, 0, 0, S_SPIKEBALL8}, // S_SPIKEBALL7
-	{SPR_SPIK, 7, 1, {NULL}, 0, 0, S_SPIKEBALL1}, // S_SPIKEBALL8
+	{SPR_SPIK, 0, 1, {NULL}, 0, 0, S_SPIKEBALL2, 0}, // S_SPIKEBALL1
+	{SPR_SPIK, 1, 1, {NULL}, 0, 0, S_SPIKEBALL3, 0}, // S_SPIKEBALL2
+	{SPR_SPIK, 2, 1, {NULL}, 0, 0, S_SPIKEBALL4, 0}, // S_SPIKEBALL3
+	{SPR_SPIK, 3, 1, {NULL}, 0, 0, S_SPIKEBALL5, 0}, // S_SPIKEBALL4
+	{SPR_SPIK, 4, 1, {NULL}, 0, 0, S_SPIKEBALL6, 0}, // S_SPIKEBALL5
+	{SPR_SPIK, 5, 1, {NULL}, 0, 0, S_SPIKEBALL7, 0}, // S_SPIKEBALL6
+	{SPR_SPIK, 6, 1, {NULL}, 0, 0, S_SPIKEBALL8, 0}, // S_SPIKEBALL7
+	{SPR_SPIK, 7, 1, {NULL}, 0, 0, S_SPIKEBALL1, 0}, // S_SPIKEBALL8
 
 	// Elemental Shield's Spawn
-	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_SPINFIRE2}, // S_SPINFIRE1
-	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_SPINFIRE3}, // S_SPINFIRE2
-	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SPINFIRE4}, // S_SPINFIRE3
-	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SPINFIRE5}, // S_SPINFIRE4
-	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_SPINFIRE6}, // S_SPINFIRE5
-	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_SPINFIRE1}, // S_SPINFIRE6
-
-	{SPR_TFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_TEAM_SPINFIRE2}, // S_TEAM_SPINFIRE1
-	{SPR_TFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE3}, // S_TEAM_SPINFIRE2
-	{SPR_TFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE4}, // S_TEAM_SPINFIRE3
-	{SPR_TFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE5}, // S_TEAM_SPINFIRE4
-	{SPR_TFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE6}, // S_TEAM_SPINFIRE5
-	{SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1}, // S_TEAM_SPINFIRE6
+	{SPR_SFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_SPINFIRE2, 0}, // S_SPINFIRE1
+	{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_SPINFIRE3, 0}, // S_SPINFIRE2
+	{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SPINFIRE4, 0}, // S_SPINFIRE3
+	{SPR_SFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_SPINFIRE5, 0}, // S_SPINFIRE4
+	{SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_SPINFIRE6, 0}, // S_SPINFIRE5
+	{SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_SPINFIRE1, 0}, // S_SPINFIRE6
+
+	{SPR_TFLM, FF_FULLBRIGHT,   2, {NULL}, 0, 0, S_TEAM_SPINFIRE2, 0}, // S_TEAM_SPINFIRE1
+	{SPR_TFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE3, 0}, // S_TEAM_SPINFIRE2
+	{SPR_TFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE4, 0}, // S_TEAM_SPINFIRE3
+	{SPR_TFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE5, 0}, // S_TEAM_SPINFIRE4
+	{SPR_TFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE6, 0}, // S_TEAM_SPINFIRE5
+	{SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1, 0}, // S_TEAM_SPINFIRE6
 
 	// Floor Spike
-	{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended
-	{SPR_USPK, 1, 2, {A_Pain},         0, 0, S_SPIKE3}, // S_SPIKE2
-	{SPR_USPK, 2, 2, {NULL},           0, 0, S_SPIKE4}, // S_SPIKE3
-	{SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5}, // S_SPIKE4 -- Fully retracted
-	{SPR_USPK, 2, 2, {A_Pain},         0, 0, S_SPIKE6}, // S_SPIKE5
-	{SPR_USPK, 1, 2, {NULL},           0, 0, S_SPIKE1}, // S_SPIKE6
-	{SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles
-	{SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
+	{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2, 0}, // S_SPIKE1 -- Fully extended
+	{SPR_USPK, 1, 2, {A_Pain},         0, 0, S_SPIKE3, 0}, // S_SPIKE2
+	{SPR_USPK, 2, 2, {NULL},           0, 0, S_SPIKE4, 0}, // S_SPIKE3
+	{SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5, 0}, // S_SPIKE4 -- Fully retracted
+	{SPR_USPK, 2, 2, {A_Pain},         0, 0, S_SPIKE6, 0}, // S_SPIKE5
+	{SPR_USPK, 1, 2, {NULL},           0, 0, S_SPIKE1, 0}, // S_SPIKE6
+	{SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL, 0}, // S_SPIKED1 -- Busted spike particles
+	{SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL, 0}, // S_SPIKED2
 
 	// Wall Spike
-	{SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2}, // S_WALLSPIKE1 -- Fully extended
-	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE3}, // S_WALLSPIKE2
-	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE4}, // S_WALLSPIKE3
-	{SPR_WSPK, 3|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 0, 0, S_WALLSPIKE5}, // S_WALLSPIKE4 -- Fully retracted
-	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE6}, // S_WALLSPIKE5
-	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE1}, // S_WALLSPIKE6
-	{SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKEBASE -- Base
-	{SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED1 -- Busted spike particles
-	{SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED2
+	{SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2, 0}, // S_WALLSPIKE1 -- Fully extended
+	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE3, 0}, // S_WALLSPIKE2
+	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE4, 0}, // S_WALLSPIKE3
+	{SPR_WSPK, 3|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 0, 0, S_WALLSPIKE5, 0}, // S_WALLSPIKE4 -- Fully retracted
+	{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain},         0, 0, S_WALLSPIKE6, 0}, // S_WALLSPIKE5
+	{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL},           0, 0, S_WALLSPIKE1, 0}, // S_WALLSPIKE6
+	{SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLSPIKEBASE -- Base
+	{SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLSPIKED1 -- Busted spike particles
+	{SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLSPIKED2
 
 	// Starpost
-	{SPR_STPT, 0            , -1, {NULL},  0, 0, S_NULL},           // S_STARPOST_IDLE
-	{SPR_STPT, FF_ANIMATE|17, -1, {NULL},  5, 1, S_NULL},           // S_STARPOST_FLASH
-	{SPR_STPT, FF_ANIMATE|13,  2, {NULL},  1, 1, S_STARPOST_SPIN},  // S_STARPOST_STARTSPIN
-	{SPR_STPT, FF_ANIMATE|1 , 23, {NULL}, 11, 1, S_STARPOST_ENDSPIN}, // S_STARPOST_SPIN
-	{SPR_STPT, FF_ANIMATE|15,  2, {NULL},  1, 1, S_STARPOST_FLASH}, // S_STARPOST_ENDSPIN
+	{SPR_STPT, 0            , -1, {NULL},  0, 0, S_NULL, 0},           // S_STARPOST_IDLE
+	{SPR_STPT, FF_ANIMATE|17, -1, {NULL},  5, 1, S_NULL, 0},           // S_STARPOST_FLASH
+	{SPR_STPT, FF_ANIMATE|13,  2, {NULL},  1, 1, S_STARPOST_SPIN, 0},  // S_STARPOST_STARTSPIN
+	{SPR_STPT, FF_ANIMATE|1 , 23, {NULL}, 11, 1, S_STARPOST_ENDSPIN, 0}, // S_STARPOST_SPIN
+	{SPR_STPT, FF_ANIMATE|15,  2, {NULL},  1, 1, S_STARPOST_FLASH, 0}, // S_STARPOST_ENDSPIN
 
 	// Big floating mine
-	{SPR_BMNE, 0,  2, {A_Look},      ((224<<FRACBITS)|1), 0, S_BIGMINE_IDLE},   // S_BIGMINE_IDLE
-	{SPR_BMNE, 1,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT2}, // S_BIGMINE_ALERT1
-	{SPR_BMNE, 2,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT3}, // S_BIGMINE_ALERT2
-	{SPR_BMNE, 0,  1, {A_Look},      ((224<<FRACBITS)|1), 1, S_BIGMINE_IDLE},   // S_BIGMINE_ALERT3
-	{SPR_BMNE, 3, 25, {A_Pain},           0,            0, S_BIGMINE_SET2},   // S_BIGMINE_SET1
-	{SPR_BMNE, 3, 10, {A_SetObjectFlags}, MF_SHOOTABLE, 1, S_BIGMINE_SET3},   // S_BIGMINE_SET1
-	{SPR_BMNE, 3,  1, {A_MineExplode},    0,            0, S_BIGMINE_BLAST1}, // S_BIGMINE_SET3
-	{SPR_BMNB,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST2}, // S_BIGMINE_BLAST1
-	{SPR_BMNB, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST3}, // S_BIGMINE_BLAST2
-	{SPR_BMNB, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST4}, // S_BIGMINE_BLAST3
-	{SPR_BMNB, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST5}, // S_BIGMINE_BLAST4
-	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BIGMINE_BLAST5
+	{SPR_BMNE, 0,  2, {A_Look},      ((224<<FRACBITS)|1), 0, S_BIGMINE_IDLE, 0},   // S_BIGMINE_IDLE
+	{SPR_BMNE, 1,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT2, 0}, // S_BIGMINE_ALERT1
+	{SPR_BMNE, 2,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT3, 0}, // S_BIGMINE_ALERT2
+	{SPR_BMNE, 0,  1, {A_Look},      ((224<<FRACBITS)|1), 1, S_BIGMINE_IDLE, 0},   // S_BIGMINE_ALERT3
+	{SPR_BMNE, 3, 25, {A_Pain},           0,            0, S_BIGMINE_SET2, 0},   // S_BIGMINE_SET1
+	{SPR_BMNE, 3, 10, {A_SetObjectFlags}, MF_SHOOTABLE, 1, S_BIGMINE_SET3, 0},   // S_BIGMINE_SET1
+	{SPR_BMNE, 3,  1, {A_MineExplode},    0,            0, S_BIGMINE_BLAST1, 0}, // S_BIGMINE_SET3
+	{SPR_BMNB,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST2, 0}, // S_BIGMINE_BLAST1
+	{SPR_BMNB, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST3, 0}, // S_BIGMINE_BLAST2
+	{SPR_BMNB, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST4, 0}, // S_BIGMINE_BLAST3
+	{SPR_BMNB, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST5, 0}, // S_BIGMINE_BLAST4
+	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_BIGMINE_BLAST5
 
 	// Cannon launcher
-	{SPR_NULL, 0, 1,    {A_FindTarget},     MT_PLAYER,         0, S_CANNONLAUNCHER2}, // S_CANNONLAUNCHER1
-	{SPR_NULL, 0, 1,       {A_LobShot}, MT_CANNONBALL, 4*TICRATE, S_CANNONLAUNCHER3}, // S_CANNONLAUNCHER2
-	{SPR_NULL, 0, 2, {A_SetRandomTics},     TICRATE/2, 3*TICRATE, S_CANNONLAUNCHER1}, // S_CANNONLAUNCHER3
+	{SPR_NULL, 0, 1,    {A_FindTarget},     MT_PLAYER,         0, S_CANNONLAUNCHER2, 0}, // S_CANNONLAUNCHER1
+	{SPR_NULL, 0, 1,       {A_LobShot}, MT_CANNONBALL, 4*TICRATE, S_CANNONLAUNCHER3, 0}, // S_CANNONLAUNCHER2
+	{SPR_NULL, 0, 2, {A_SetRandomTics},     TICRATE/2, 3*TICRATE, S_CANNONLAUNCHER1, 0}, // S_CANNONLAUNCHER3
 
 	// Monitor Miscellany
-	{SPR_NSPK, 0, 16, {NULL}, 0, 0, S_BOXSPARKLE2}, // S_BOXSPARKLE1
-	{SPR_NSPK, 1, 12, {NULL}, 0, 0, S_BOXSPARKLE3}, // S_BOXSPARKLE2
-	{SPR_NSPK, 2,  8, {NULL}, 0, 0, S_BOXSPARKLE4}, // S_BOXSPARKLE3
-	{SPR_NSPK, 3,  4, {NULL}, 0, 0, S_NULL},        // S_BOXSPARKLE4
-
-	{SPR_MSTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE},  // S_BOX_FLICKER
-	{SPR_MSTV, 0,  4, {A_MonitorPop}, 0, 0, S_BOX_POP2}, // S_BOX_POP1
-	{SPR_MSTV, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BOX_POP2
-
-	{SPR_XLTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE},  // S_GOLDBOX_FLICKER
-	{SPR_XLTV, 1, 89, {A_GoldMonitorPop}, 0, 0, S_GOLDBOX_OFF2}, // S_GOLDBOX_OFF1
-	{SPR_XLTV, 2,  4, {A_PlayAttackSound}, 0, 0, S_GOLDBOX_OFF3}, // S_GOLDBOX_OFF2
-	{SPR_XLTV, 3,  4, {NULL}, 0, 0, S_GOLDBOX_OFF4}, // S_GOLDBOX_OFF3
-	{SPR_XLTV, 4,  4, {NULL}, 0, 0, S_GOLDBOX_OFF5}, // S_GOLDBOX_OFF4
-	{SPR_XLTV, 5,  2, {NULL}, 0, 0, S_GOLDBOX_OFF6}, // S_GOLDBOX_OFF5
-	{SPR_XLTV, 6,  2, {NULL}, 0, 0, S_GOLDBOX_OFF7}, // S_GOLDBOX_OFF6
-	{SPR_XLTV, 6,  0, {A_GoldMonitorRestore}, 0, 0, S_SPAWNSTATE}, // S_GOLDBOX_OFF7
+	{SPR_NSPK, 0, 16, {NULL}, 0, 0, S_BOXSPARKLE2, 0}, // S_BOXSPARKLE1
+	{SPR_NSPK, 1, 12, {NULL}, 0, 0, S_BOXSPARKLE3, 0}, // S_BOXSPARKLE2
+	{SPR_NSPK, 2,  8, {NULL}, 0, 0, S_BOXSPARKLE4, 0}, // S_BOXSPARKLE3
+	{SPR_NSPK, 3,  4, {NULL}, 0, 0, S_NULL, 0},        // S_BOXSPARKLE4
+
+	{SPR_MSTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE, 0},  // S_BOX_FLICKER
+	{SPR_MSTV, 0,  4, {A_MonitorPop}, 0, 0, S_BOX_POP2, 0}, // S_BOX_POP1
+	{SPR_MSTV, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BOX_POP2
+
+	{SPR_XLTV, 0,  1, {NULL}, 0, 0, S_SPAWNSTATE, 0},  // S_GOLDBOX_FLICKER
+	{SPR_XLTV, 1, 89, {A_GoldMonitorPop}, 0, 0, S_GOLDBOX_OFF2, 0}, // S_GOLDBOX_OFF1
+	{SPR_XLTV, 2,  4, {A_PlayAttackSound}, 0, 0, S_GOLDBOX_OFF3, 0}, // S_GOLDBOX_OFF2
+	{SPR_XLTV, 3,  4, {NULL}, 0, 0, S_GOLDBOX_OFF4, 0}, // S_GOLDBOX_OFF3
+	{SPR_XLTV, 4,  4, {NULL}, 0, 0, S_GOLDBOX_OFF5, 0}, // S_GOLDBOX_OFF4
+	{SPR_XLTV, 5,  2, {NULL}, 0, 0, S_GOLDBOX_OFF6, 0}, // S_GOLDBOX_OFF5
+	{SPR_XLTV, 6,  2, {NULL}, 0, 0, S_GOLDBOX_OFF7, 0}, // S_GOLDBOX_OFF6
+	{SPR_XLTV, 6,  0, {A_GoldMonitorRestore}, 0, 0, S_SPAWNSTATE, 0}, // S_GOLDBOX_OFF7
 
 	// Monitor States (one per box)
-	{SPR_TVMY, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_MYSTERY_BOX
-	{SPR_TVRI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_RING_BOX
-	{SPR_TVPI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_PITY_BOX
-	{SPR_TVAT, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_ATTRACT_BOX
-	{SPR_TVFO, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_FORCE_BOX
-	{SPR_TVAR, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_ARMAGEDDON_BOX
-	{SPR_TVWW, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_WHIRLWIND_BOX
-	{SPR_TVEL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_ELEMENTAL_BOX
-	{SPR_TVSS, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SNEAKERS_BOX
-	{SPR_TVIV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_INVULN_BOX
-	{SPR_TV1U, 0, 2, {A_1upThinker}, 0, 0, S_BOX_FLICKER}, // S_1UP_BOX
-	{SPR_TVEG, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_EGGMAN_BOX
-	{SPR_TVMX, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_MIXUP_BOX
-	{SPR_TVGV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_GRAVITY_BOX
-	{SPR_TVRC, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_RECYCLER_BOX
-	{SPR_TV1K, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SCORE1K_BOX
-	{SPR_TVTK, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SCORE10K_BOX
-	{SPR_TVFL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_FLAMEAURA_BOX
-	{SPR_TVBB, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_BUBBLEWRAP_BOX
-	{SPR_TVZP, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_THUNDERCOIN_BOX
+	{SPR_TVMY, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_MYSTERY_BOX
+	{SPR_TVRI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_RING_BOX
+	{SPR_TVPI, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_PITY_BOX
+	{SPR_TVAT, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_ATTRACT_BOX
+	{SPR_TVFO, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_FORCE_BOX
+	{SPR_TVAR, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_ARMAGEDDON_BOX
+	{SPR_TVWW, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_WHIRLWIND_BOX
+	{SPR_TVEL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_ELEMENTAL_BOX
+	{SPR_TVSS, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_SNEAKERS_BOX
+	{SPR_TVIV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_INVULN_BOX
+	{SPR_TV1U, 0, 2, {A_1upThinker}, 0, 0, S_BOX_FLICKER, 0}, // S_1UP_BOX
+	{SPR_TVEG, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_EGGMAN_BOX
+	{SPR_TVMX, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_MIXUP_BOX
+	{SPR_TVGV, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_GRAVITY_BOX
+	{SPR_TVRC, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_RECYCLER_BOX
+	{SPR_TV1K, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_SCORE1K_BOX
+	{SPR_TVTK, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_SCORE10K_BOX
+	{SPR_TVFL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_FLAMEAURA_BOX
+	{SPR_TVBB, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_BUBBLEWRAP_BOX
+	{SPR_TVZP, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER, 0}, // S_THUNDERCOIN_BOX
 
 	// Gold Repeat Monitor States (one per box)
-	{SPR_TVPI, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_PITY_GOLDBOX
-	{SPR_TVAT, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_ATTRACT_GOLDBOX
-	{SPR_TVFO, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_FORCE_GOLDBOX
-	{SPR_TVAR, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_ARMAGEDDON_GOLDBOX
-	{SPR_TVWW, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_WHIRLWIND_GOLDBOX
-	{SPR_TVEL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_ELEMENTAL_GOLDBOX
-	{SPR_TVSS, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_SNEAKERS_GOLDBOX
-	{SPR_TVIV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_INVULN_GOLDBOX
-	{SPR_TVEG, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_EGGMAN_GOLDBOX
-	{SPR_TVGV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_GRAVITY_GOLDBOX
-	{SPR_TVFL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_FLAMEAURA_GOLDBOX
-	{SPR_TVBB, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_BUBBLEWRAP_GOLDBOX
-	{SPR_TVZP, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_THUNDERCOIN_GOLDBOX
+	{SPR_TVPI, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_PITY_GOLDBOX
+	{SPR_TVAT, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_ATTRACT_GOLDBOX
+	{SPR_TVFO, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_FORCE_GOLDBOX
+	{SPR_TVAR, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_ARMAGEDDON_GOLDBOX
+	{SPR_TVWW, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_WHIRLWIND_GOLDBOX
+	{SPR_TVEL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_ELEMENTAL_GOLDBOX
+	{SPR_TVSS, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_SNEAKERS_GOLDBOX
+	{SPR_TVIV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_INVULN_GOLDBOX
+	{SPR_TVEG, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_EGGMAN_GOLDBOX
+	{SPR_TVGV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_GRAVITY_GOLDBOX
+	{SPR_TVFL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_FLAMEAURA_GOLDBOX
+	{SPR_TVBB, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_BUBBLEWRAP_GOLDBOX
+	{SPR_TVZP, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER, 0}, // S_THUNDERCOIN_GOLDBOX
 
 	// Team Ring Boxes (these are special)
-	{SPR_TRRI, 0, 2, {NULL}, 0, 0, S_RING_REDBOX2}, // S_RING_REDBOX1
-	{SPR_TRRI, 1, 1, {NULL}, 0, 0, S_RING_REDBOX1}, // S_RING_REDBOX2
-	{SPR_TRRI, 1, 4, {A_MonitorPop}, 0, 0, S_REDBOX_POP2},  // S_REDBOX_POP1
-	{SPR_TRRI, 2, -1, {NULL}, 0, 0, S_NULL},        // S_REDBOX_POP2
+	{SPR_TRRI, 0, 2, {NULL}, 0, 0, S_RING_REDBOX2, 0}, // S_RING_REDBOX1
+	{SPR_TRRI, 1, 1, {NULL}, 0, 0, S_RING_REDBOX1, 0}, // S_RING_REDBOX2
+	{SPR_TRRI, 1, 4, {A_MonitorPop}, 0, 0, S_REDBOX_POP2, 0},  // S_REDBOX_POP1
+	{SPR_TRRI, 2, -1, {NULL}, 0, 0, S_NULL, 0},        // S_REDBOX_POP2
 
-	{SPR_TBRI, 0, 2, {NULL}, 0, 0, S_RING_BLUEBOX2}, // S_RING_BLUEBOX1
-	{SPR_TBRI, 1, 1, {NULL}, 0, 0, S_RING_BLUEBOX1}, // S_RING_BLUEBOX2
-	{SPR_TBRI, 1, 4, {A_MonitorPop}, 0, 0, S_BLUEBOX_POP2},  // S_BLUEBOX_POP1
-	{SPR_TBRI, 2, -1, {NULL}, 0, 0, S_NULL},         // S_BLUEBOX_POP2
+	{SPR_TBRI, 0, 2, {NULL}, 0, 0, S_RING_BLUEBOX2, 0}, // S_RING_BLUEBOX1
+	{SPR_TBRI, 1, 1, {NULL}, 0, 0, S_RING_BLUEBOX1, 0}, // S_RING_BLUEBOX2
+	{SPR_TBRI, 1, 4, {A_MonitorPop}, 0, 0, S_BLUEBOX_POP2, 0},  // S_BLUEBOX_POP1
+	{SPR_TBRI, 2, -1, {NULL}, 0, 0, S_NULL, 0},         // S_BLUEBOX_POP2
 
 	// Box Icons -- 2 states each, animation and action
-	{SPR_TVRI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RING_ICON2}, // S_RING_ICON1
-	{SPR_TVRI, 2, 18, {A_RingBox}, 0, 0, S_NULL}, // S_RING_ICON2
+	{SPR_TVRI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RING_ICON2, 0}, // S_RING_ICON1
+	{SPR_TVRI, 2, 18, {A_RingBox}, 0, 0, S_NULL, 0}, // S_RING_ICON2
 
-	{SPR_TVPI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_PITY_ICON2}, // S_PITY_ICON1
-	{SPR_TVPI, 2, 18, {A_GiveShield}, SH_PITY, 0, S_NULL},  // S_PITY_ICON2
+	{SPR_TVPI, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_PITY_ICON2, 0}, // S_PITY_ICON1
+	{SPR_TVPI, 2, 18, {A_GiveShield}, SH_PITY, 0, S_NULL, 0},  // S_PITY_ICON2
 
-	{SPR_TVAT, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ATTRACT_ICON2}, // S_ATTRACT_ICON1
-	{SPR_TVAT, 2, 18, {A_GiveShield}, SH_ATTRACT, 0, S_NULL}, // S_ATTRACT_ICON2
+	{SPR_TVAT, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ATTRACT_ICON2, 0}, // S_ATTRACT_ICON1
+	{SPR_TVAT, 2, 18, {A_GiveShield}, SH_ATTRACT, 0, S_NULL, 0}, // S_ATTRACT_ICON2
 
-	{SPR_TVFO, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FORCE_ICON2}, // S_FORCE_ICON1
-	{SPR_TVFO, 2, 18, {A_GiveShield}, SH_FORCE|1, 0, S_NULL}, // S_FORCE_ICON2
+	{SPR_TVFO, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FORCE_ICON2, 0}, // S_FORCE_ICON1
+	{SPR_TVFO, 2, 18, {A_GiveShield}, SH_FORCE|1, 0, S_NULL, 0}, // S_FORCE_ICON2
 
-	{SPR_TVAR, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ARMAGEDDON_ICON2}, // S_ARMAGEDDON_ICON1
-	{SPR_TVAR, 2, 18, {A_GiveShield}, SH_ARMAGEDDON, 0, S_NULL}, // S_ARMAGEDDON_ICON2
+	{SPR_TVAR, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ARMAGEDDON_ICON2, 0}, // S_ARMAGEDDON_ICON1
+	{SPR_TVAR, 2, 18, {A_GiveShield}, SH_ARMAGEDDON, 0, S_NULL, 0}, // S_ARMAGEDDON_ICON2
 
-	{SPR_TVWW, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_WHIRLWIND_ICON2}, // S_WHIRLWIND_ICON1
-	{SPR_TVWW, 2, 18, {A_GiveShield}, SH_WHIRLWIND, 0, S_NULL}, // S_WHIRLWIND_ICON2
+	{SPR_TVWW, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_WHIRLWIND_ICON2, 0}, // S_WHIRLWIND_ICON1
+	{SPR_TVWW, 2, 18, {A_GiveShield}, SH_WHIRLWIND, 0, S_NULL, 0}, // S_WHIRLWIND_ICON2
 
-	{SPR_TVEL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ELEMENTAL_ICON2}, // S_ELEMENTAL_ICON1
-	{SPR_TVEL, 2, 18, {A_GiveShield}, SH_ELEMENTAL, 0, S_NULL}, // S_ELEMENTAL_ICON2
+	{SPR_TVEL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ELEMENTAL_ICON2, 0}, // S_ELEMENTAL_ICON1
+	{SPR_TVEL, 2, 18, {A_GiveShield}, SH_ELEMENTAL, 0, S_NULL, 0}, // S_ELEMENTAL_ICON2
 
-	{SPR_TVSS, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SNEAKERS_ICON2}, // S_SNEAKERS_ICON1
-	{SPR_TVSS, 2, 18, {A_SuperSneakers}, 0, 0, S_NULL}, // S_SNEAKERS_ICON2
+	{SPR_TVSS, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SNEAKERS_ICON2, 0}, // S_SNEAKERS_ICON1
+	{SPR_TVSS, 2, 18, {A_SuperSneakers}, 0, 0, S_NULL, 0}, // S_SNEAKERS_ICON2
 
-	{SPR_TVIV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_INVULN_ICON2}, // S_INVULN_ICON1
-	{SPR_TVIV, 2, 18, {A_Invincibility}, 0, 0, S_NULL}, // S_INVULN_ICON2
+	{SPR_TVIV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_INVULN_ICON2, 0}, // S_INVULN_ICON1
+	{SPR_TVIV, 2, 18, {A_Invincibility}, 0, 0, S_NULL, 0}, // S_INVULN_ICON2
 
-	{SPR_TV1U, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_1UP_ICON2}, // S_1UP_ICON1
-	{SPR_TV1U, 2, 18, {A_ExtraLife},  0, 0, S_NULL},  // S_1UP_ICON2
+	{SPR_TV1U, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_1UP_ICON2, 0}, // S_1UP_ICON1
+	{SPR_TV1U, 2, 18, {A_ExtraLife},  0, 0, S_NULL, 0},  // S_1UP_ICON2
 
-	{SPR_TVEG, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_EGGMAN_ICON2}, // S_EGGMAN_ICON1
-	{SPR_TVEG, 2, 18, {A_EggmanBox}, 0, 0, S_NULL}, // S_EGGMAN_ICON2
+	{SPR_TVEG, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_EGGMAN_ICON2, 0}, // S_EGGMAN_ICON1
+	{SPR_TVEG, 2, 18, {A_EggmanBox}, 0, 0, S_NULL, 0}, // S_EGGMAN_ICON2
 
-	{SPR_TVMX, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_MIXUP_ICON2}, // S_MIXUP_ICON1
-	{SPR_TVMX, 2, 18, {A_MixUp}, 0, 0, S_NULL}, // S_MIXUP_ICON2
+	{SPR_TVMX, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_MIXUP_ICON2, 0}, // S_MIXUP_ICON1
+	{SPR_TVMX, 2, 18, {A_MixUp}, 0, 0, S_NULL, 0}, // S_MIXUP_ICON2
 
-	{SPR_TVGV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_GRAVITY_ICON2}, // S_GRAVITY_ICON1
-	{SPR_TVGV, 2, 18, {A_GravityBox}, 0, 0, S_NULL}, // S_GRAVITY_ICON2
+	{SPR_TVGV, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_GRAVITY_ICON2, 0}, // S_GRAVITY_ICON1
+	{SPR_TVGV, 2, 18, {A_GravityBox}, 0, 0, S_NULL, 0}, // S_GRAVITY_ICON2
 
-	{SPR_TVRC, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RECYCLER_ICON2}, // S_RECYCLER_ICON1
-	{SPR_TVRC, 2, 18, {A_RecyclePowers}, 0, 0, S_NULL}, // S_RECYCLER_ICON2
+	{SPR_TVRC, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_RECYCLER_ICON2, 0}, // S_RECYCLER_ICON1
+	{SPR_TVRC, 2, 18, {A_RecyclePowers}, 0, 0, S_NULL, 0}, // S_RECYCLER_ICON2
 
-	{SPR_TV1K, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE1K_ICON2}, // S_SCORE1K_ICON1
-	{SPR_TV1K, 2, 18, {A_AwardScore}, 0, 0, S_NULL}, // S_SCORE1K_ICON2
+	{SPR_TV1K, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE1K_ICON2, 0}, // S_SCORE1K_ICON1
+	{SPR_TV1K, 2, 18, {A_AwardScore}, 0, 0, S_NULL, 0}, // S_SCORE1K_ICON2
 
-	{SPR_TVTK, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE10K_ICON2}, // S_SCORE10K_ICON1
-	{SPR_TVTK, 2, 18, {A_AwardScore}, 0, 0, S_NULL}, // S_SCORE10K_ICON2
+	{SPR_TVTK, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE10K_ICON2, 0}, // S_SCORE10K_ICON1
+	{SPR_TVTK, 2, 18, {A_AwardScore}, 0, 0, S_NULL, 0}, // S_SCORE10K_ICON2
 
-	{SPR_TVFL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FLAMEAURA_ICON2}, // S_FLAMEAURA_ICON1
-	{SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL}, // S_FLAMEAURA_ICON2
+	{SPR_TVFL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FLAMEAURA_ICON2, 0}, // S_FLAMEAURA_ICON1
+	{SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL, 0}, // S_FLAMEAURA_ICON2
 
-	{SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2}, // S_BUBBLEWRAP_ICON1
-	{SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLEWRAP_ICON2
+	{SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2, 0}, // S_BUBBLEWRAP_ICON1
+	{SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL, 0}, // S_BUBBLEWRAP_ICON2
 
-	{SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2}, // S_THUNDERCOIN_ICON1
-	{SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL}, // S_THUNDERCOIN_ICON2
+	{SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2, 0}, // S_THUNDERCOIN_ICON1
+	{SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL, 0}, // S_THUNDERCOIN_ICON2
 
 	// ---
 
-	{SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET}, // S_ROCKET
+	{SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET, 0}, // S_ROCKET
 
-	{SPR_LASR, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_NULL}, // S_LASER
-	{SPR_LASR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_LASER2
-	{SPR_LASR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL}, // S_LASERFLASH
+	{SPR_LASR, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LASER
+	{SPR_LASR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LASER2
+	{SPR_LASR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LASERFLASH
 
-	{SPR_LASF,                           FF_FULLBRIGHT|0,       2,           {NULL}, 0, 0, S_LASERFLAME2}, // S_LASERFLAME1
-	{SPR_LASF,                           FF_FULLBRIGHT|1,       1, {A_ChangeHeight}, 156*FRACUNIT, 3, S_LASERFLAME3}, // S_LASERFLAME2
-	{SPR_LASF,                           FF_FULLBRIGHT|2,       0, {A_ChangeHeight}, 32*FRACUNIT, 3, S_LASERFLAME4}, // S_LASERFLAME3
-	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|2,       4,           {NULL}, 1, 2, S_LASERFLAME5}, // S_LASERFLAME4
-	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|4,      28,           {NULL}, 2, 2, S_NULL}, // S_LASERFLAME5
+	{SPR_LASF,                           FF_FULLBRIGHT|0,       2,           {NULL}, 0, 0, S_LASERFLAME2, 0}, // S_LASERFLAME1
+	{SPR_LASF,                           FF_FULLBRIGHT|1,       1, {A_ChangeHeight}, 156*FRACUNIT, 3, S_LASERFLAME3, 0}, // S_LASERFLAME2
+	{SPR_LASF,                           FF_FULLBRIGHT|2,       0, {A_ChangeHeight}, 32*FRACUNIT, 3, S_LASERFLAME4, 0}, // S_LASERFLAME3
+	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|2,       4,           {NULL}, 1, 2, S_LASERFLAME5, 0}, // S_LASERFLAME4
+	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|4,      28,           {NULL}, 2, 2, S_NULL, 0}, // S_LASERFLAME5
 
-	{SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO}, // S_TORPEDO
+	{SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO, 0}, // S_TORPEDO
 
-	{SPR_ENRG, FF_FULLBRIGHT|FF_TRANS30, 1, {NULL}, 0, 0, S_ENERGYBALL2}, // S_ENERGYBALL1
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ENERGYBALL1}, // S_ENERGYBALL2
+	{SPR_ENRG, FF_FULLBRIGHT|FF_TRANS30, 1, {NULL}, 0, 0, S_ENERGYBALL2, 0}, // S_ENERGYBALL1
+	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ENERGYBALL1, 0}, // S_ENERGYBALL2
 
 	// Skim Mine (also dropped by Jetty-Syn bomber)
-	{SPR_MINE, 0, -1, {NULL}, 0, 0, S_NULL},           // S_MINE1
-	{SPR_MINE, 1, 1, {A_Fall}, 0, 0, S_MINE_BOOM2},    // S_MINE_BOOM1
-	{SPR_MINE, 2, 3, {A_Scream}, 0, 0, S_MINE_BOOM3},  // S_MINE_BOOM2
-	{SPR_MINE, 3, 3, {A_Explode}, 0, 0, S_MINE_BOOM4}, // S_MINE_BOOM3
-	{SPR_MINE, 4, 3, {NULL}, 0, 0, S_NULL},            // S_MINE_BOOM4
+	{SPR_MINE, 0, -1, {NULL}, 0, 0, S_NULL, 0},           // S_MINE1
+	{SPR_MINE, 1, 1, {A_Fall}, 0, 0, S_MINE_BOOM2, 0},    // S_MINE_BOOM1
+	{SPR_MINE, 2, 3, {A_Scream}, 0, 0, S_MINE_BOOM3, 0},  // S_MINE_BOOM2
+	{SPR_MINE, 3, 3, {A_Explode}, 0, 0, S_MINE_BOOM4, 0}, // S_MINE_BOOM3
+	{SPR_MINE, 4, 3, {NULL}, 0, 0, S_NULL, 0},            // S_MINE_BOOM4
 
 	// Jetty-Syn Bullet
-	{SPR_JBUL, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_JETBULLET2}, // S_JETBULLET1
-	{SPR_JBUL, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETBULLET1}, // S_JETBULLET2
+	{SPR_JBUL, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_JETBULLET2, 0}, // S_JETBULLET1
+	{SPR_JBUL, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETBULLET1, 0}, // S_JETBULLET2
 
-	{SPR_TRLS, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_TURRETLASER},          // S_TURRETLASER
-	{SPR_TRLS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TURRETLASEREXPLODE2},  // S_TURRETLASEREXPLODE1
-	{SPR_TRLS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL},                 // S_TURRETLASEREXPLODE2
+	{SPR_TRLS, FF_FULLBRIGHT,   1, {NULL}, 0, 0, S_TURRETLASER, 0},          // S_TURRETLASER
+	{SPR_TRLS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TURRETLASEREXPLODE2, 0},  // S_TURRETLASEREXPLODE1
+	{SPR_TRLS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL, 0},                 // S_TURRETLASEREXPLODE2
 
-	{SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANNONBALL1
+	{SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANNONBALL1
 
-	{SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ARROW
-	{SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL}, // S_ARROWBONK
+	{SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARROW
+	{SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL, 0}, // S_ARROWBONK
 
-	{SPR_CFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 5, 2, S_NULL}, // S_DEMONFIRE
+	{SPR_CFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 5, 2, S_NULL, 0}, // S_DEMONFIRE
 
-	{SPR_LETR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_LETTER
+	{SPR_LETR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LETTER
 
 	// Tutorial scenery
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF2}, // S_TUTORIALLEAF1
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF3}, // S_TUTORIALLEAF2
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF4}, // S_TUTORIALLEAF3
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF5}, // S_TUTORIALLEAF4
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF6}, // S_TUTORIALLEAF5
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF7}, // S_TUTORIALLEAF6
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF8}, // S_TUTORIALLEAF7
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF9}, // S_TUTORIALLEAF8
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF10}, // S_TUTORIALLEAF9
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF11}, // S_TUTORIALLEAF10
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF12}, // S_TUTORIALLEAF11
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF13}, // S_TUTORIALLEAF12
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF14}, // S_TUTORIALLEAF13
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF15}, // S_TUTORIALLEAF14
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF16}, // S_TUTORIALLEAF15
-	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF1}, // S_TUTORIALLEAF16
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER2}, // S_TUTORIALFLOWER1
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER3}, // S_TUTORIALFLOWER2
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER4}, // S_TUTORIALFLOWER3
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER5}, // S_TUTORIALFLOWER4
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER6}, // S_TUTORIALFLOWER5
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER7}, // S_TUTORIALFLOWER6
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER8}, // S_TUTORIALFLOWER7
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER9}, // S_TUTORIALFLOWER8
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER10}, // S_TUTORIALFLOWER9
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER11}, // S_TUTORIALFLOWER10
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER12}, // S_TUTORIALFLOWER11
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER13}, // S_TUTORIALFLOWER12
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER14}, // S_TUTORIALFLOWER13
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER15}, // S_TUTORIALFLOWER14
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER16}, // S_TUTORIALFLOWER15
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER1}, // S_TUTORIALFLOWER16
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF2}, // S_TUTORIALFLOWERF1
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF3}, // S_TUTORIALFLOWERF2
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF4}, // S_TUTORIALFLOWERF3
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF5}, // S_TUTORIALFLOWERF4
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF6}, // S_TUTORIALFLOWERF5
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF7}, // S_TUTORIALFLOWERF6
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF8}, // S_TUTORIALFLOWERF7
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF9}, // S_TUTORIALFLOWERF8
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF10}, // S_TUTORIALFLOWERF9
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF11}, // S_TUTORIALFLOWERF10
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF12}, // S_TUTORIALFLOWERF11
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF13}, // S_TUTORIALFLOWERF12
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF14}, // S_TUTORIALFLOWERF13
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF15}, // S_TUTORIALFLOWERF14
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF16}, // S_TUTORIALFLOWERF15
-	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF1}, // S_TUTORIALFLOWERF16
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF2, 0}, // S_TUTORIALLEAF1
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF3, 0}, // S_TUTORIALLEAF2
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF4, 0}, // S_TUTORIALLEAF3
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF5, 0}, // S_TUTORIALLEAF4
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF6, 0}, // S_TUTORIALLEAF5
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF7, 0}, // S_TUTORIALLEAF6
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF8, 0}, // S_TUTORIALLEAF7
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF9, 0}, // S_TUTORIALLEAF8
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF10, 0}, // S_TUTORIALLEAF9
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF11, 0}, // S_TUTORIALLEAF10
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF12, 0}, // S_TUTORIALLEAF11
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF13, 0}, // S_TUTORIALLEAF12
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF14, 0}, // S_TUTORIALLEAF13
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF15, 0}, // S_TUTORIALLEAF14
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF16, 0}, // S_TUTORIALLEAF15
+	{SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF1, 0}, // S_TUTORIALLEAF16
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER2, 0}, // S_TUTORIALFLOWER1
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER3, 0}, // S_TUTORIALFLOWER2
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER4, 0}, // S_TUTORIALFLOWER3
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER5, 0}, // S_TUTORIALFLOWER4
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER6, 0}, // S_TUTORIALFLOWER5
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER7, 0}, // S_TUTORIALFLOWER6
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER8, 0}, // S_TUTORIALFLOWER7
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER9, 0}, // S_TUTORIALFLOWER8
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER10, 0}, // S_TUTORIALFLOWER9
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER11, 0}, // S_TUTORIALFLOWER10
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER12, 0}, // S_TUTORIALFLOWER11
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER13, 0}, // S_TUTORIALFLOWER12
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER14, 0}, // S_TUTORIALFLOWER13
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER15, 0}, // S_TUTORIALFLOWER14
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER16, 0}, // S_TUTORIALFLOWER15
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER1, 0}, // S_TUTORIALFLOWER16
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF2, 0}, // S_TUTORIALFLOWERF1
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF3, 0}, // S_TUTORIALFLOWERF2
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF4, 0}, // S_TUTORIALFLOWERF3
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF5, 0}, // S_TUTORIALFLOWERF4
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF6, 0}, // S_TUTORIALFLOWERF5
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF7, 0}, // S_TUTORIALFLOWERF6
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF8, 0}, // S_TUTORIALFLOWERF7
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF9, 0}, // S_TUTORIALFLOWERF8
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF10, 0}, // S_TUTORIALFLOWERF9
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF11, 0}, // S_TUTORIALFLOWERF10
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF12, 0}, // S_TUTORIALFLOWERF11
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF13, 0}, // S_TUTORIALFLOWERF12
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF14, 0}, // S_TUTORIALFLOWERF13
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF15, 0}, // S_TUTORIALFLOWERF14
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF16, 0}, // S_TUTORIALFLOWERF15
+	{SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF1, 0}, // S_TUTORIALFLOWERF16
 
 	// GFZ flowers
-	{SPR_FWR1, FF_ANIMATE, -1, {NULL},  7, 3, S_NULL}, // S_GFZFLOWERA
-	{SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL}, // S_GFZFLOWERB
-	{SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_GFZFLOWERC
+	{SPR_FWR1, FF_ANIMATE, -1, {NULL},  7, 3, S_NULL, 0}, // S_GFZFLOWERA
+	{SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL, 0}, // S_GFZFLOWERB
+	{SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_GFZFLOWERC
 
-	{SPR_BUS3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEBERRYBUSH
-	{SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH
-	{SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH
+	{SPR_BUS3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUEBERRYBUSH
+	{SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BERRYBUSH
+	{SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUSH
 
 	// Trees
-	{SPR_TRE1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GFZTREE
-	{SPR_TRE1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_GFZBERRYTREE
-	{SPR_TRE1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_GFZCHERRYTREE
-	{SPR_TRE2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CHECKERTREE
-	{SPR_TRE2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CHECKERSUNSETTREE
-	{SPR_TRE3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZTREE
-	{SPR_TRE3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZPINKTREE
-	{SPR_TRE4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POLYGONTREE
-	{SPR_TRE5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHTREE
-	{SPR_TRE5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHREDTREE
-	{SPR_TRE6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPRINGTREE
+	{SPR_TRE1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_GFZTREE
+	{SPR_TRE1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_GFZBERRYTREE
+	{SPR_TRE1, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_GFZCHERRYTREE
+	{SPR_TRE2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CHECKERTREE
+	{SPR_TRE2, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CHECKERSUNSETTREE
+	{SPR_TRE3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZTREE
+	{SPR_TRE3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZPINKTREE
+	{SPR_TRE4, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_POLYGONTREE
+	{SPR_TRE5, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUSHTREE
+	{SPR_TRE5, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUSHREDTREE
+	{SPR_TRE6, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SPRINGTREE
 
 	// THZ flowers
-	{SPR_THZP, FF_ANIMATE, -1, {NULL},  7, 4, S_NULL}, // S_THZFLOWERA
-	{SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB
-	{SPR_FWR6, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERC
+	{SPR_THZP, FF_ANIMATE, -1, {NULL},  7, 4, S_NULL, 0}, // S_THZFLOWERA
+	{SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL, 0}, // S_THZFLOWERB
+	{SPR_FWR6, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL, 0}, // S_THZFLOWERC
 
 	// THZ Steam Whistle tree/bush
-	{SPR_THZT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_THZTREE
-	{SPR_THZT,  1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2}, // S_THZTREEBRANCH1
-	{SPR_THZT,  2|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH3}, // S_THZTREEBRANCH2
-	{SPR_THZT,  3|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH4}, // S_THZTREEBRANCH3
-	{SPR_THZT,  4|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH5}, // S_THZTREEBRANCH4
-	{SPR_THZT,  5|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH6}, // S_THZTREEBRANCH5
-	{SPR_THZT,  6|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH7}, // S_THZTREEBRANCH6
-	{SPR_THZT,  7|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH8}, // S_THZTREEBRANCH7
-	{SPR_THZT,  8|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH9}, // S_THZTREEBRANCH8
-	{SPR_THZT,  9|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH10}, // S_THZTREEBRANCH9
-	{SPR_THZT, 10|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH11}, // S_THZTREEBRANCH10
-	{SPR_THZT, 11|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH12}, // S_THZTREEBRANCH11
-	{SPR_THZT, 12|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH13}, // S_THZTREEBRANCH12
-	{SPR_THZT, 13|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH1}, // S_THZTREEBRANCH13
+	{SPR_THZT, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_THZTREE
+	{SPR_THZT,  1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2, 0}, // S_THZTREEBRANCH1
+	{SPR_THZT,  2|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH3, 0}, // S_THZTREEBRANCH2
+	{SPR_THZT,  3|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH4, 0}, // S_THZTREEBRANCH3
+	{SPR_THZT,  4|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH5, 0}, // S_THZTREEBRANCH4
+	{SPR_THZT,  5|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH6, 0}, // S_THZTREEBRANCH5
+	{SPR_THZT,  6|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH7, 0}, // S_THZTREEBRANCH6
+	{SPR_THZT,  7|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH8, 0}, // S_THZTREEBRANCH7
+	{SPR_THZT,  8|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH9, 0}, // S_THZTREEBRANCH8
+	{SPR_THZT,  9|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH10, 0}, // S_THZTREEBRANCH9
+	{SPR_THZT, 10|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH11, 0}, // S_THZTREEBRANCH10
+	{SPR_THZT, 11|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH12, 0}, // S_THZTREEBRANCH11
+	{SPR_THZT, 12|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH13, 0}, // S_THZTREEBRANCH12
+	{SPR_THZT, 13|FF_PAPERSPRITE,  4, {NULL}, 0, 0, S_THZTREEBRANCH1, 0}, // S_THZTREEBRANCH13
 
 	// THZ Alarm
-	{SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1
+	{SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1, 0}, // S_ALARM1
 
 	// Deep Sea Gargoyle
-	{SPR_GARG, 0, -1, {NULL}, 0, 0, S_NULL},  // S_GARGOYLE
-	{SPR_GARG, 1, -1, {NULL}, 0, 0, S_NULL},  // S_BIGGARGOYLE
+	{SPR_GARG, 0, -1, {NULL}, 0, 0, S_NULL, 0},  // S_GARGOYLE
+	{SPR_GARG, 1, -1, {NULL}, 0, 0, S_NULL, 0},  // S_BIGGARGOYLE
 
 	// DSZ Seaweed
-	{SPR_SEWE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 26, 3, S_SEAWEED1}, // S_SEAWEED1
-	{SPR_SEWE, 1, 5, {NULL}, 0, 0, S_SEAWEED3}, // S_SEAWEED2
-	{SPR_SEWE, 2, 5, {NULL}, 0, 0, S_SEAWEED4}, // S_SEAWEED3
-	{SPR_SEWE, 3, 5, {NULL}, 0, 0, S_SEAWEED5}, // S_SEAWEED4
-	{SPR_SEWE, 4, 5, {NULL}, 0, 0, S_SEAWEED6}, // S_SEAWEED5
-	{SPR_SEWE, 5, 5, {NULL}, 0, 0, S_SEAWEED1}, // S_SEAWEED6
+	{SPR_SEWE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 26, 3, S_SEAWEED1, 0}, // S_SEAWEED1
+	{SPR_SEWE, 1, 5, {NULL}, 0, 0, S_SEAWEED3, 0}, // S_SEAWEED2
+	{SPR_SEWE, 2, 5, {NULL}, 0, 0, S_SEAWEED4, 0}, // S_SEAWEED3
+	{SPR_SEWE, 3, 5, {NULL}, 0, 0, S_SEAWEED5, 0}, // S_SEAWEED4
+	{SPR_SEWE, 4, 5, {NULL}, 0, 0, S_SEAWEED6, 0}, // S_SEAWEED5
+	{SPR_SEWE, 5, 5, {NULL}, 0, 0, S_SEAWEED1, 0}, // S_SEAWEED6
 
 	// Dripping water
-	{SPR_NULL, FF_TRANS30  , 3*TICRATE, {NULL},                  0, 0, S_DRIPA2}, // S_DRIPA1
-	{SPR_DRIP, FF_TRANS30  ,         2, {NULL},                  0, 0, S_DRIPA3}, // S_DRIPA2
-	{SPR_DRIP, FF_TRANS30|1,         2, {NULL},                  0, 0, S_DRIPA4}, // S_DRIPA3
-	{SPR_DRIP, FF_TRANS30|2,         2, {A_SpawnObjectRelative}, 0, MT_WATERDROP, S_DRIPA1}, // S_DRIPA4
-	{SPR_DRIP, FF_TRANS30|3,        -1, {NULL},                  0, 0, S_DRIPB1}, // S_DRIPB1
-	{SPR_DRIP, FF_TRANS30|4,         1, {NULL},                  0, 0, S_DRIPC2}, // S_DRIPC1
-	{SPR_DRIP, FF_TRANS30|5,         1, {NULL},                  0, 0,   S_NULL}, // S_DRIPC2
+	{SPR_NULL, FF_TRANS30  , 3*TICRATE, {NULL},                  0, 0, S_DRIPA2, 0}, // S_DRIPA1
+	{SPR_DRIP, FF_TRANS30  ,         2, {NULL},                  0, 0, S_DRIPA3, 0}, // S_DRIPA2
+	{SPR_DRIP, FF_TRANS30|1,         2, {NULL},                  0, 0, S_DRIPA4, 0}, // S_DRIPA3
+	{SPR_DRIP, FF_TRANS30|2,         2, {A_SpawnObjectRelative}, 0, MT_WATERDROP, S_DRIPA1, 0}, // S_DRIPA4
+	{SPR_DRIP, FF_TRANS30|3,        -1, {NULL},                  0, 0, S_DRIPB1, 0}, // S_DRIPB1
+	{SPR_DRIP, FF_TRANS30|4,         1, {NULL},                  0, 0, S_DRIPC2, 0}, // S_DRIPC1
+	{SPR_DRIP, FF_TRANS30|5,         1, {NULL},                  0, 0,   S_NULL, 0}, // S_DRIPC2
 
 	// Coral
-	{SPR_CORL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1
-	{SPR_CORL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL2
-	{SPR_CORL, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3
-	{SPR_CORL, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL4
-	{SPR_CORL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL5
+	{SPR_CORL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL1
+	{SPR_CORL, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL2
+	{SPR_CORL, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL3
+	{SPR_CORL, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL4
+	{SPR_CORL, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORAL5
 
 	// Blue Crystal
-	{SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1
+	{SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUECRYSTAL1
 
 	// Kelp
-	{SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KELP
+	{SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_KELP
 
 	// Animated algae
-	{SPR_ALGA, 0, 1, {A_ConnectToGround}, MT_ANIMALGAESEG, 0, S_ANIMALGAETOP2}, // S_ANIMALGAETOP1
-	{SPR_ALGA, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL},          // S_ANIMALGAETOP2
-	{SPR_ALGB, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL},          // S_ANIMALGAESEG
+	{SPR_ALGA, 0, 1, {A_ConnectToGround}, MT_ANIMALGAESEG, 0, S_ANIMALGAETOP2, 0}, // S_ANIMALGAETOP1
+	{SPR_ALGA, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL, 0},          // S_ANIMALGAETOP2
+	{SPR_ALGB, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL, 0},          // S_ANIMALGAESEG
 
 	// DSZ Stalagmites
-	{SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DSZSTALAGMITE
-	{SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE
+	{SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_DSZSTALAGMITE
+	{SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_DSZ2STALAGMITE
 
 	// DSZ Light beam
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM3},  // S_LIGHTBEAM2
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM4},  // S_LIGHTBEAM3
-	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5},  // S_LIGHTBEAM4
-	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6},  // S_LIGHTBEAM5
-	{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM7},  // S_LIGHTBEAM6
-	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8},  // S_LIGHTBEAM7
-	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9},  // S_LIGHTBEAM8
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11
-	{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM12
+	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2, 0}, // S_LIGHTBEAM1
+	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM3, 0},  // S_LIGHTBEAM2
+	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM4, 0},  // S_LIGHTBEAM3
+	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5, 0},  // S_LIGHTBEAM4
+	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6, 0},  // S_LIGHTBEAM5
+	{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM7, 0},  // S_LIGHTBEAM6
+	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8, 0},  // S_LIGHTBEAM7
+	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9, 0},  // S_LIGHTBEAM8
+	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM10, 0}, // S_LIGHTBEAM9
+	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM11, 0}, // S_LIGHTBEAM10
+	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM12, 0}, // S_LIGHTBEAM11
+	{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1, 0}, // S_LIGHTBEAM12
 
 	// CEZ Chain
-	{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN
+	{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZCHAIN
 
 	// Flame
-	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,       3*8, {A_FlameParticle}, 7, 3, S_FLAME}, // S_FLAME
-	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE|8, TICRATE,            {NULL}, 3, 3, S_NULL},  // S_FLAMEPARTICLE
-	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,        -1,            {NULL}, 7, 3, S_NULL},  // S_FLAMEREST
+	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,       3*8, {A_FlameParticle}, 7, 3, S_FLAME, 0}, // S_FLAME
+	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE|8, TICRATE,            {NULL}, 3, 3, S_NULL, 0},  // S_FLAMEPARTICLE
+	{SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE,        -1,            {NULL}, 7, 3, S_NULL, 0},  // S_FLAMEREST
 
 	// Eggman statue
-	{SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE1
+	{SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGSTATUE1
 
 	// Hidden sling appears
-	{SPR_NULL, 0, -1, {NULL},          0, 0, S_SLING2}, // S_SLING1
-	{SPR_NULL, 0, -1, {A_SlingAppear}, 0, 0, S_NULL},   // S_SLING2
+	{SPR_NULL, 0, -1, {NULL},          0, 0, S_SLING2, 0}, // S_SLING1
+	{SPR_NULL, 0, -1, {A_SlingAppear}, 0, 0, S_NULL, 0},   // S_SLING2
 
 	// CEZ maces and chains
-	{SPR_SMCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLMACECHAIN
-	{SPR_BMCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGMACECHAIN
-	{SPR_SMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLMACE
-	{SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGMACE
-	{SPR_SMCH, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLGRABCHAIN
-	{SPR_BMCH, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGGRABCHAIN
+	{SPR_SMCH, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SMALLMACECHAIN
+	{SPR_BMCH, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGMACECHAIN
+	{SPR_SMCE, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SMALLMACE
+	{SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGMACE
+	{SPR_SMCH, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SMALLGRABCHAIN
+	{SPR_BMCH, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGGRABCHAIN
 
 	// Blue spring on a ball
-	{SPR_BSPB, 0, -1, {NULL},   0, 0, S_NULL},            // S_BLUESPRINGBALL
-	{SPR_BSPB, 4,  4, {A_Pain}, 0, 0, S_BLUESPRINGBALL3}, // S_BLUESPRINGBALL2
-	{SPR_BSPB, 3,  1, {NULL},   0, 0, S_BLUESPRINGBALL4}, // S_BLUESPRINGBALL3
-	{SPR_BSPB, 2,  1, {NULL},   0, 0, S_BLUESPRINGBALL5}, // S_BLUESPRINGBALL4
-	{SPR_BSPB, 1,  1, {NULL},   0, 0, S_BLUESPRINGBALL},  // S_BLUESPRINGBALL5
+	{SPR_BSPB, 0, -1, {NULL},   0, 0, S_NULL, 0},            // S_BLUESPRINGBALL
+	{SPR_BSPB, 4,  4, {A_Pain}, 0, 0, S_BLUESPRINGBALL3, 0}, // S_BLUESPRINGBALL2
+	{SPR_BSPB, 3,  1, {NULL},   0, 0, S_BLUESPRINGBALL4, 0}, // S_BLUESPRINGBALL3
+	{SPR_BSPB, 2,  1, {NULL},   0, 0, S_BLUESPRINGBALL5, 0}, // S_BLUESPRINGBALL4
+	{SPR_BSPB, 1,  1, {NULL},   0, 0, S_BLUESPRINGBALL, 0},  // S_BLUESPRINGBALL5
 
 	// Yellow spring on a ball
-	{SPR_YSPB, 0, -1, {NULL},   0, 0, S_NULL},              // S_YELLOWSPRINGBALL
-	{SPR_YSPB, 4,  4, {A_Pain}, 0, 0, S_YELLOWSPRINGBALL3}, // S_YELLOWSPRINGBALL2
-	{SPR_YSPB, 3,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL4}, // S_YELLOWSPRINGBALL3
-	{SPR_YSPB, 2,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL5}, // S_YELLOWSPRINGBALL4
-	{SPR_YSPB, 1,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL},  // S_YELLOWSPRINGBALL5
+	{SPR_YSPB, 0, -1, {NULL},   0, 0, S_NULL, 0},              // S_YELLOWSPRINGBALL
+	{SPR_YSPB, 4,  4, {A_Pain}, 0, 0, S_YELLOWSPRINGBALL3, 0}, // S_YELLOWSPRINGBALL2
+	{SPR_YSPB, 3,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL4, 0}, // S_YELLOWSPRINGBALL3
+	{SPR_YSPB, 2,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL5, 0}, // S_YELLOWSPRINGBALL4
+	{SPR_YSPB, 1,  1, {NULL},   0, 0, S_YELLOWSPRINGBALL, 0},  // S_YELLOWSPRINGBALL5
 
 	// Red spring on a ball
-	{SPR_RSPB, 0, -1, {NULL},   0, 0, S_NULL},           // S_REDSPRINGBALL
-	{SPR_RSPB, 4,  4, {A_Pain}, 0, 0, S_REDSPRINGBALL3}, // S_REDSPRINGBALL2
-	{SPR_RSPB, 3,  1, {NULL},   0, 0, S_REDSPRINGBALL4}, // S_REDSPRINGBALL3
-	{SPR_RSPB, 2,  1, {NULL},   0, 0, S_REDSPRINGBALL5}, // S_REDSPRINGBALL4
-	{SPR_RSPB, 1,  1, {NULL},   0, 0, S_REDSPRINGBALL},  // S_REDSPRINGBALL5
+	{SPR_RSPB, 0, -1, {NULL},   0, 0, S_NULL, 0},           // S_REDSPRINGBALL
+	{SPR_RSPB, 4,  4, {A_Pain}, 0, 0, S_REDSPRINGBALL3, 0}, // S_REDSPRINGBALL2
+	{SPR_RSPB, 3,  1, {NULL},   0, 0, S_REDSPRINGBALL4, 0}, // S_REDSPRINGBALL3
+	{SPR_RSPB, 2,  1, {NULL},   0, 0, S_REDSPRINGBALL5, 0}, // S_REDSPRINGBALL4
+	{SPR_RSPB, 1,  1, {NULL},   0, 0, S_REDSPRINGBALL, 0},  // S_REDSPRINGBALL5
 
 	// Small Firebar
-	{SPR_SFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_SMALLFIREBAR2},  // S_SMALLFIREBAR1
-	{SPR_SFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_SMALLFIREBAR3},  // S_SMALLFIREBAR2
-	{SPR_SFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR4},  // S_SMALLFIREBAR3
-	{SPR_SFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_SMALLFIREBAR5},  // S_SMALLFIREBAR4
-	{SPR_SFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_SMALLFIREBAR6},  // S_SMALLFIREBAR5
-	{SPR_SFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_SMALLFIREBAR7},  // S_SMALLFIREBAR6
-	{SPR_SFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR8},  // S_SMALLFIREBAR7
-	{SPR_SFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_SMALLFIREBAR9},  // S_SMALLFIREBAR8
-	{SPR_SFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_SMALLFIREBAR10}, // S_SMALLFIREBAR9
-	{SPR_SFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_SMALLFIREBAR11}, // S_SMALLFIREBAR10
-	{SPR_SFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR12}, // S_SMALLFIREBAR11
-	{SPR_SFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_SMALLFIREBAR13}, // S_SMALLFIREBAR12
-	{SPR_SFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_SMALLFIREBAR14}, // S_SMALLFIREBAR13
-	{SPR_SFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_SMALLFIREBAR15}, // S_SMALLFIREBAR14
-	{SPR_SFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR16}, // S_SMALLFIREBAR15
-	{SPR_SFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_SMALLFIREBAR1},  // S_SMALLFIREBAR16
+	{SPR_SFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_SMALLFIREBAR2, 0},  // S_SMALLFIREBAR1
+	{SPR_SFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_SMALLFIREBAR3, 0},  // S_SMALLFIREBAR2
+	{SPR_SFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR4, 0},  // S_SMALLFIREBAR3
+	{SPR_SFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_SMALLFIREBAR5, 0},  // S_SMALLFIREBAR4
+	{SPR_SFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_SMALLFIREBAR6, 0},  // S_SMALLFIREBAR5
+	{SPR_SFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_SMALLFIREBAR7, 0},  // S_SMALLFIREBAR6
+	{SPR_SFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR8, 0},  // S_SMALLFIREBAR7
+	{SPR_SFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_SMALLFIREBAR9, 0},  // S_SMALLFIREBAR8
+	{SPR_SFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_SMALLFIREBAR10, 0}, // S_SMALLFIREBAR9
+	{SPR_SFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_SMALLFIREBAR11, 0}, // S_SMALLFIREBAR10
+	{SPR_SFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR12, 0}, // S_SMALLFIREBAR11
+	{SPR_SFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_SMALLFIREBAR13, 0}, // S_SMALLFIREBAR12
+	{SPR_SFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_SMALLFIREBAR14, 0}, // S_SMALLFIREBAR13
+	{SPR_SFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_SMALLFIREBAR15, 0}, // S_SMALLFIREBAR14
+	{SPR_SFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR16, 0}, // S_SMALLFIREBAR15
+	{SPR_SFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_SMALLFIREBAR1, 0},  // S_SMALLFIREBAR16
 
 	// Big Firebar
-	{SPR_BFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_BIGFIREBAR2},  // S_BIGFIREBAR1
-	{SPR_BFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_BIGFIREBAR3},  // S_BIGFIREBAR2
-	{SPR_BFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR4},  // S_BIGFIREBAR3
-	{SPR_BFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_BIGFIREBAR5},  // S_BIGFIREBAR4
-	{SPR_BFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_BIGFIREBAR6},  // S_BIGFIREBAR5
-	{SPR_BFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_BIGFIREBAR7},  // S_BIGFIREBAR6
-	{SPR_BFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR8},  // S_BIGFIREBAR7
-	{SPR_BFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_BIGFIREBAR9},  // S_BIGFIREBAR8
-	{SPR_BFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_BIGFIREBAR10}, // S_BIGFIREBAR9
-	{SPR_BFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_BIGFIREBAR11}, // S_BIGFIREBAR10
-	{SPR_BFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR12}, // S_BIGFIREBAR11
-	{SPR_BFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_BIGFIREBAR13}, // S_BIGFIREBAR12
-	{SPR_BFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_BIGFIREBAR14}, // S_BIGFIREBAR13
-	{SPR_BFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_BIGFIREBAR15}, // S_BIGFIREBAR14
-	{SPR_BFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR16}, // S_BIGFIREBAR15
-	{SPR_BFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_BIGFIREBAR1},  // S_BIGFIREBAR16
+	{SPR_BFBR, FF_FULLBRIGHT,     1, {NULL},            0, 0, S_BIGFIREBAR2, 0},  // S_BIGFIREBAR1
+	{SPR_BFBR, FF_FULLBRIGHT| 1,  1, {NULL},            0, 0, S_BIGFIREBAR3, 0},  // S_BIGFIREBAR2
+	{SPR_BFBR, FF_FULLBRIGHT| 2,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR4, 0},  // S_BIGFIREBAR3
+	{SPR_BFBR, FF_FULLBRIGHT| 3,  1, {NULL},            0, 0, S_BIGFIREBAR5, 0},  // S_BIGFIREBAR4
+	{SPR_BFBR, FF_FULLBRIGHT| 4,  1, {NULL},            0, 0, S_BIGFIREBAR6, 0},  // S_BIGFIREBAR5
+	{SPR_BFBR, FF_FULLBRIGHT| 5,  1, {NULL},            0, 0, S_BIGFIREBAR7, 0},  // S_BIGFIREBAR6
+	{SPR_BFBR, FF_FULLBRIGHT| 6,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR8, 0},  // S_BIGFIREBAR7
+	{SPR_BFBR, FF_FULLBRIGHT| 7,  1, {NULL},            0, 0, S_BIGFIREBAR9, 0},  // S_BIGFIREBAR8
+	{SPR_BFBR, FF_FULLBRIGHT| 8,  1, {NULL},            0, 0, S_BIGFIREBAR10, 0}, // S_BIGFIREBAR9
+	{SPR_BFBR, FF_FULLBRIGHT| 9,  1, {NULL},            0, 0, S_BIGFIREBAR11, 0}, // S_BIGFIREBAR10
+	{SPR_BFBR, FF_FULLBRIGHT|10,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR12, 0}, // S_BIGFIREBAR11
+	{SPR_BFBR, FF_FULLBRIGHT|11,  1, {NULL},            0, 0, S_BIGFIREBAR13, 0}, // S_BIGFIREBAR12
+	{SPR_BFBR, FF_FULLBRIGHT|12,  1, {NULL},            0, 0, S_BIGFIREBAR14, 0}, // S_BIGFIREBAR13
+	{SPR_BFBR, FF_FULLBRIGHT|13,  1, {NULL},            0, 0, S_BIGFIREBAR15, 0}, // S_BIGFIREBAR14
+	{SPR_BFBR, FF_FULLBRIGHT|14,  1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR16, 0}, // S_BIGFIREBAR15
+	{SPR_BFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_BIGFIREBAR1, 0},  // S_BIGFIREBAR16
 
-	{SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER
-	{SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE
+	{SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZFLOWER
+	{SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZPOLE
 
-	{SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER1
-	{SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER2
+	{SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBANNER1
+	{SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBANNER2
 
-	{SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE
-	{SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1
-	{SPR_CEZB, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH2
+	{SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_PINETREE
+	{SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBUSH1
+	{SPR_CEZB, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEZBUSH2
 
-	{SPR_CNDL, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL}, // S_CANDLE
-	{SPR_CNDL, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CANDLEPRICKET
+	{SPR_CNDL, FF_FULLBRIGHT,   -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANDLE
+	{SPR_CNDL, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANDLEPRICKET
 
-	{SPR_FLMH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FLAMEHOLDER
+	{SPR_FLMH, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FLAMEHOLDER
 
-	{SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH
+	{SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH, 0}, // S_FIRETORCH
 
-	{SPR_CFLG,                0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG
-	{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG1
-	{SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG2
+	{SPR_CFLG,                0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WAVINGFLAG
+	{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WAVINGFLAGSEG1
+	{SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WAVINGFLAGSEG2
 
-	{SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE
+	{SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CRAWLASTATUE
 
-	{SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSTATUE
+	{SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FACESTABBERSTATUE
 
-	{SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT},   // S_SUSPICIOUSFACESTABBERSTATUE_WAIT
-	{SPR_CBBS, FF_ANIMATE, 23, {NULL},    6, 1, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1
-	{SPR_NULL, 0, 40, {A_StatueBurst}, MT_FACESTABBER, S_FACESTABBER_CHARGE2, S_NULL}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2
+	{SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT, 0},   // S_SUSPICIOUSFACESTABBERSTATUE_WAIT
+	{SPR_CBBS, FF_ANIMATE, 23, {NULL},    6, 1, S_SUSPICIOUSFACESTABBERSTATUE_BURST2, 0}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1
+	{SPR_NULL, 0, 40, {A_StatueBurst}, MT_FACESTABBER, S_FACESTABBER_CHARGE2, S_NULL, 0}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2
 
-	{SPR_CABR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BRAMBLES
+	{SPR_CABR, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BRAMBLES
 
 	// Big Tumbleweed
-	{SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL},                // S_BIGTUMBLEWEED
-	{SPR_BTBL, 0,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL2}, // S_BIGTUMBLEWEED_ROLL1
-	{SPR_BTBL, 1,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL3}, // S_BIGTUMBLEWEED_ROLL2
-	{SPR_BTBL, 2,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL4}, // S_BIGTUMBLEWEED_ROLL3
-	{SPR_BTBL, 3,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL5}, // S_BIGTUMBLEWEED_ROLL4
-	{SPR_BTBL, 4,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL6}, // S_BIGTUMBLEWEED_ROLL5
-	{SPR_BTBL, 5,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL7}, // S_BIGTUMBLEWEED_ROLL6
-	{SPR_BTBL, 6,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL8}, // S_BIGTUMBLEWEED_ROLL7
-	{SPR_BTBL, 7,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL1}, // S_BIGTUMBLEWEED_ROLL8
+	{SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL, 0},                // S_BIGTUMBLEWEED
+	{SPR_BTBL, 0,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL2, 0}, // S_BIGTUMBLEWEED_ROLL1
+	{SPR_BTBL, 1,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL3, 0}, // S_BIGTUMBLEWEED_ROLL2
+	{SPR_BTBL, 2,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL4, 0}, // S_BIGTUMBLEWEED_ROLL3
+	{SPR_BTBL, 3,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL5, 0}, // S_BIGTUMBLEWEED_ROLL4
+	{SPR_BTBL, 4,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL6, 0}, // S_BIGTUMBLEWEED_ROLL5
+	{SPR_BTBL, 5,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL7, 0}, // S_BIGTUMBLEWEED_ROLL6
+	{SPR_BTBL, 6,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL8, 0}, // S_BIGTUMBLEWEED_ROLL7
+	{SPR_BTBL, 7,  5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL1, 0}, // S_BIGTUMBLEWEED_ROLL8
 
 	// Little Tumbleweed
-	{SPR_STBL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LITTLETUMBLEWEED
-	{SPR_STBL, 0, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL2}, // S_LITTLETUMBLEWEED_ROLL1
-	{SPR_STBL, 1, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL3}, // S_LITTLETUMBLEWEED_ROLL2
-	{SPR_STBL, 2, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL4}, // S_LITTLETUMBLEWEED_ROLL3
-	{SPR_STBL, 3, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL5}, // S_LITTLETUMBLEWEED_ROLL4
-	{SPR_STBL, 4, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL6}, // S_LITTLETUMBLEWEED_ROLL5
-	{SPR_STBL, 5, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL7}, // S_LITTLETUMBLEWEED_ROLL6
-	{SPR_STBL, 6, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL8}, // S_LITTLETUMBLEWEED_ROLL7
-	{SPR_STBL, 7, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL1}, // S_LITTLETUMBLEWEED_ROLL8
+	{SPR_STBL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LITTLETUMBLEWEED
+	{SPR_STBL, 0, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL2, 0}, // S_LITTLETUMBLEWEED_ROLL1
+	{SPR_STBL, 1, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL3, 0}, // S_LITTLETUMBLEWEED_ROLL2
+	{SPR_STBL, 2, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL4, 0}, // S_LITTLETUMBLEWEED_ROLL3
+	{SPR_STBL, 3, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL5, 0}, // S_LITTLETUMBLEWEED_ROLL4
+	{SPR_STBL, 4, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL6, 0}, // S_LITTLETUMBLEWEED_ROLL5
+	{SPR_STBL, 5, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL7, 0}, // S_LITTLETUMBLEWEED_ROLL6
+	{SPR_STBL, 6, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL8, 0}, // S_LITTLETUMBLEWEED_ROLL7
+	{SPR_STBL, 7, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL1, 0}, // S_LITTLETUMBLEWEED_ROLL8
 
 	// Cacti
-	{SPR_CACT, 0, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI1
-	{SPR_CACT, 1, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI2
-	{SPR_CACT, 2, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI3
-	{SPR_CACT, 3, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI4
-	{SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI5
-	{SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI6
-	{SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI7
-	{SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI8
-	{SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI9
-	{SPR_CACT, 9, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI10
-	{SPR_CACT, 10, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI11
-	{SPR_CACT, 11, -1, {NULL}, 0, 0, S_NULL}, // S_CACTITINYSEG
-	{SPR_CACT, 12, -1, {NULL}, 0, 0, S_NULL}, // S_CACTISMALLSEG
+	{SPR_CACT, 0, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL, 0}, // S_CACTI1
+	{SPR_CACT, 1, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL, 0}, // S_CACTI2
+	{SPR_CACT, 2, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL, 0}, // S_CACTI3
+	{SPR_CACT, 3, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL, 0}, // S_CACTI4
+	{SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI5
+	{SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI6
+	{SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI7
+	{SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI8
+	{SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTI9
+	{SPR_CACT, 9, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL, 0}, // S_CACTI10
+	{SPR_CACT, 10, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL, 0}, // S_CACTI11
+	{SPR_CACT, 11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTITINYSEG
+	{SPR_CACT, 12, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CACTISMALLSEG
 
 	// Warning Signs
-	{SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CAUTION
-	{SPR_WWS2, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CACTI
-	{SPR_WWS3, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_SHARPTURN
+	{SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARIDSIGN_CAUTION
+	{SPR_WWS2, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARIDSIGN_CACTI
+	{SPR_WWS3, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ARIDSIGN_SHARPTURN
 
 	// Oil lamp
-	{SPR_OILL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_OILLAMP
-	{SPR_OILF, FF_TRANS90|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_OILLAMPFLARE
+	{SPR_OILL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_OILLAMP
+	{SPR_OILF, FF_TRANS90|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_OILLAMPFLARE
 
 	// TNT barrel
-	{SPR_BARR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_STND1
-	{SPR_BARX, 0, 0, {A_RollAngle}, 0, 1, S_TNTBARREL_EXPL2}, // S_TNTBARREL_EXPL1
-	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_TNTBARREL_EXPL3}, // S_TNTBARREL_EXPL2
-	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_TNTExplode}, MT_TNTDUST, 0, S_TNTBARREL_EXPL4}, // S_TNTBARREL_EXPL3
-	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_TNTBARREL_EXPL5}, // S_TNTBARREL_EXPL4
-	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL6}, // S_TNTBARREL_EXPL5
-	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL7}, // S_TNTBARREL_EXPL6
-	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_EXPL7
+	{SPR_BARR, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TNTBARREL_STND1
+	{SPR_BARX, 0, 0, {A_RollAngle}, 0, 1, S_TNTBARREL_EXPL2, 0}, // S_TNTBARREL_EXPL1
+	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_TNTBARREL_EXPL3, 0}, // S_TNTBARREL_EXPL2
+	{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_TNTExplode}, MT_TNTDUST, 0, S_TNTBARREL_EXPL4, 0}, // S_TNTBARREL_EXPL3
+	{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_TNTBARREL_EXPL5, 0}, // S_TNTBARREL_EXPL4
+	{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL6, 0}, // S_TNTBARREL_EXPL5
+	{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL7, 0}, // S_TNTBARREL_EXPL6
+	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL, 0}, // S_TNTBARREL_EXPL7
 #ifndef ROTSPRITE
-	{SPR_BARR, 1|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_TNTBARREL_FLYING
+	{SPR_BARR, 1|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL, 0}, // S_TNTBARREL_FLYING
 #else
-	{SPR_BARR, 1, 1, {A_RollAngle}, 14, 0, S_TNTBARREL_FLYING}, // S_TNTBARREL_FLYING
+	{SPR_BARR, 1, 1, {A_RollAngle}, 14, 0, S_TNTBARREL_FLYING, 0}, // S_TNTBARREL_FLYING
 #endif
 
 	// TNT proximity shell
-	{SPR_REMT, 0, 10, {A_Look}, 33554433, 0, S_PROXIMITY_TNT}, // S_PROXIMITY_TNT
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER2}, // S_PROXIMITY_TNT_TRIGGER1
-	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER3}, // S_PROXIMITY_TNT_TRIGGER2
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER4}, // S_PROXIMITY_TNT_TRIGGER3
-	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER5}, // S_PROXIMITY_TNT_TRIGGER4
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER6}, // S_PROXIMITY_TNT_TRIGGER5
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER7}, // S_PROXIMITY_TNT_TRIGGER6
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER8}, // S_PROXIMITY_TNT_TRIGGER7
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER9}, // S_PROXIMITY_TNT_TRIGGER8
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER10}, // S_PROXIMITY_TNT_TRIGGER9
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER11}, // S_PROXIMITY_TNT_TRIGGER10
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER12}, // S_PROXIMITY_TNT_TRIGGER11
-	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER13}, // S_PROXIMITY_TNT_TRIGGER12
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER14}, // S_PROXIMITY_TNT_TRIGGER13
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER15}, // S_PROXIMITY_TNT_TRIGGER14
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER16}, // S_PROXIMITY_TNT_TRIGGER15
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER17}, // S_PROXIMITY_TNT_TRIGGER16
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER18}, // S_PROXIMITY_TNT_TRIGGER17
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER19}, // S_PROXIMITY_TNT_TRIGGER18
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER20}, // S_PROXIMITY_TNT_TRIGGER19
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER21}, // S_PROXIMITY_TNT_TRIGGER20
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER22}, // S_PROXIMITY_TNT_TRIGGER21
-	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER23}, // S_PROXIMITY_TNT_TRIGGER22
-	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_TNTBARREL_EXPL1}, // S_PROXIMITY_TNT_TRIGGER23
+	{SPR_REMT, 0, 10, {A_Look}, 33554433, 0, S_PROXIMITY_TNT, 0}, // S_PROXIMITY_TNT
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER2, 0}, // S_PROXIMITY_TNT_TRIGGER1
+	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER3, 0}, // S_PROXIMITY_TNT_TRIGGER2
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER4, 0}, // S_PROXIMITY_TNT_TRIGGER3
+	{SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER5, 0}, // S_PROXIMITY_TNT_TRIGGER4
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER6, 0}, // S_PROXIMITY_TNT_TRIGGER5
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER7, 0}, // S_PROXIMITY_TNT_TRIGGER6
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER8, 0}, // S_PROXIMITY_TNT_TRIGGER7
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER9, 0}, // S_PROXIMITY_TNT_TRIGGER8
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER10, 0}, // S_PROXIMITY_TNT_TRIGGER9
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER11, 0}, // S_PROXIMITY_TNT_TRIGGER10
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER12, 0}, // S_PROXIMITY_TNT_TRIGGER11
+	{SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER13, 0}, // S_PROXIMITY_TNT_TRIGGER12
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER14, 0}, // S_PROXIMITY_TNT_TRIGGER13
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER15, 0}, // S_PROXIMITY_TNT_TRIGGER14
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER16, 0}, // S_PROXIMITY_TNT_TRIGGER15
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER17, 0}, // S_PROXIMITY_TNT_TRIGGER16
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER18, 0}, // S_PROXIMITY_TNT_TRIGGER17
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER19, 0}, // S_PROXIMITY_TNT_TRIGGER18
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER20, 0}, // S_PROXIMITY_TNT_TRIGGER19
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER21, 0}, // S_PROXIMITY_TNT_TRIGGER20
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER22, 0}, // S_PROXIMITY_TNT_TRIGGER21
+	{SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER23, 0}, // S_PROXIMITY_TNT_TRIGGER22
+	{SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_TNTBARREL_EXPL1, 0}, // S_PROXIMITY_TNT_TRIGGER23
 
 	// Dust devil
-	{SPR_NULL, 0, 1, {A_DustDevilThink}, 0, 0, S_DUSTDEVIL}, //S_DUSTDEVIL
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 2 * TICRATE, {NULL}, 0, 0, S_DUSTLAYER2}, // S_DUSTLAYER1
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 5, {NULL}, 0, 0, S_DUSTLAYER3}, // S_DUSTLAYER2
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER4}, // S_DUSTLAYER3
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER5}, // S_DUSTLAYER4
-	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS90, 5, {NULL}, 0, 0, S_NULL}, // S_DUSTLAYER5
-	{SPR_ADST, 0|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST1
-	{SPR_ADST, 3|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST2
-	{SPR_ADST, 6|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST3
+	{SPR_NULL, 0, 1, {A_DustDevilThink}, 0, 0, S_DUSTDEVIL, 0}, //S_DUSTDEVIL
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 2 * TICRATE, {NULL}, 0, 0, S_DUSTLAYER2, 0}, // S_DUSTLAYER1
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 5, {NULL}, 0, 0, S_DUSTLAYER3, 0}, // S_DUSTLAYER2
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER4, 0}, // S_DUSTLAYER3
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER5, 0}, // S_DUSTLAYER4
+	{SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS90, 5, {NULL}, 0, 0, S_NULL, 0}, // S_DUSTLAYER5
+	{SPR_ADST, 0|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL, 0}, // S_ARIDDUST1
+	{SPR_ADST, 3|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL, 0}, // S_ARIDDUST2
+	{SPR_ADST, 6|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL, 0}, // S_ARIDDUST3
 
 	// Minecart
-	{SPR_NULL, 0,                            1, {NULL},                 0, 0, S_MINECART_IDLE},   // S_MINECART_IDLE
-	{SPR_NULL, 0,                            0, {A_KillSegments},       0, 0, S_TNTBARREL_EXPL4}, // S_MINECART_DTH1
-	{SPR_MCRT, 8|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL},            // S_MINECARTEND
-	{SPR_MCRT, 0|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL},            // S_MINECARTSEG_FRONT
-	{SPR_MCRT, 1|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL},            // S_MINECARTSEG_BACK
-	{SPR_MCRT, 2|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL},            // S_MINECARTSEG_LEFT
-	{SPR_MCRT, 5|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL},            // S_MINECARTSEG_RIGHT
-	{SPR_LCKN, 2|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL},            // S_MINECARTSIDEMARK1
-	{SPR_LCKN, 0|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL},            // S_MINECARTSIDEMARK2
-	{SPR_MCSP, FF_FULLBRIGHT,                1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK},   // S_MINECARTSPARK
+	{SPR_NULL, 0,                            1, {NULL},                 0, 0, S_MINECART_IDLE, 0},   // S_MINECART_IDLE
+	{SPR_NULL, 0,                            0, {A_KillSegments},       0, 0, S_TNTBARREL_EXPL4, 0}, // S_MINECART_DTH1
+	{SPR_MCRT, 8|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTEND
+	{SPR_MCRT, 0|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSEG_FRONT
+	{SPR_MCRT, 1|FF_PAPERSPRITE,            -1, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSEG_BACK
+	{SPR_MCRT, 2|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL, 0},            // S_MINECARTSEG_LEFT
+	{SPR_MCRT, 5|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL},                 2, 3, S_NULL, 0},            // S_MINECARTSEG_RIGHT
+	{SPR_LCKN, 2|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSIDEMARK1
+	{SPR_LCKN, 0|FF_FULLBRIGHT,              2, {NULL},                 0, 0, S_NULL, 0},            // S_MINECARTSIDEMARK2
+	{SPR_MCSP, FF_FULLBRIGHT,                1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK, 0},   // S_MINECARTSPARK
 
 	// Saloon door
-	{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR
-	{SPR_NULL, 0, -1, {A_SaloonDoorSpawn}, MT_SALOONDOOR, 48, S_NULL}, // S_SALOONDOORCENTER
+	{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SALOONDOOR
+	{SPR_NULL, 0, -1, {A_SaloonDoorSpawn}, MT_SALOONDOOR, 48, S_NULL, 0}, // S_SALOONDOORCENTER
 
 	// Train cameo
-	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2}, // S_TRAINCAMEOSPAWNER_1
-	{SPR_NULL, 0, 14, {A_TrainCameo}, 20, 18, S_TRAINCAMEOSPAWNER_3}, // S_TRAINCAMEOSPAWNER_2
-	{SPR_NULL, 0, 1, {A_Repeat}, 1, 0, S_TRAINCAMEOSPAWNER_4}, // S_TRAINCAMEOSPAWNER_3
-	{SPR_NULL, 0, 18, {A_TrainCameo2}, 20, 44, S_TRAINCAMEOSPAWNER_5}, // S_TRAINCAMEOSPAWNER_4
-	{SPR_NULL, 0, 1, {A_Repeat}, 5, S_TRAINCAMEOSPAWNER_4, S_NULL}, // S_TRAINCAMEOSPAWNER_5
-	{SPR_NULL, 0, 2, {A_SmokeTrailer}, MT_SMOKE, 0, S_TRAINPUFFMAKER}, // S_TRAINPUFFMAKER
+	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2, 0}, // S_TRAINCAMEOSPAWNER_1
+	{SPR_NULL, 0, 14, {A_TrainCameo}, 20, 18, S_TRAINCAMEOSPAWNER_3, 0}, // S_TRAINCAMEOSPAWNER_2
+	{SPR_NULL, 0, 1, {A_Repeat}, 1, 0, S_TRAINCAMEOSPAWNER_4, 0}, // S_TRAINCAMEOSPAWNER_3
+	{SPR_NULL, 0, 18, {A_TrainCameo2}, 20, 44, S_TRAINCAMEOSPAWNER_5, 0}, // S_TRAINCAMEOSPAWNER_4
+	{SPR_NULL, 0, 1, {A_Repeat}, 5, S_TRAINCAMEOSPAWNER_4, S_NULL, 0}, // S_TRAINCAMEOSPAWNER_5
+	{SPR_NULL, 0, 2, {A_SmokeTrailer}, MT_SMOKE, 0, S_TRAINPUFFMAKER, 0}, // S_TRAINPUFFMAKER
 
-	{SPR_ADST, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_TRAINDUST
-	{SPR_STEA, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_TRAINSTEAM
+	{SPR_ADST, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TRAINDUST
+	{SPR_STEA, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TRAINSTEAM
 
 	// Flame jet
-	{SPR_NULL, 0, 2*TICRATE, {NULL},             0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND
-	{SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTOP}, // S_FLAMEJETSTART
-	{SPR_NULL, 0,         1, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTND}, // S_FLAMEJETSTOP
-	{SPR_FLME, FF_FULLBRIGHT  ,  4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1
-	{SPR_FLME, FF_FULLBRIGHT|1,  5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2
-	{SPR_FLME, FF_FULLBRIGHT|2, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME3
-	{SPR_FLME, FF_FULLBRIGHT|3,  4, {NULL}, 0, 0, S_FLAMEJETFLAME5}, // S_FLAMEJETFLAME4
-	{SPR_FLME, FF_FULLBRIGHT|4,  5, {NULL}, 0, 0, S_FLAMEJETFLAME6}, // S_FLAMEJETFLAME5
-	{SPR_FLME, FF_FULLBRIGHT|5, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME6
-	{SPR_FLME, FF_FULLBRIGHT|6,  4, {NULL}, 0, 0, S_FLAMEJETFLAME8}, // S_FLAMEJETFLAME7
-	{SPR_FLME, FF_FULLBRIGHT|7,  5, {NULL}, 0, 0, S_FLAMEJETFLAME9}, // S_FLAMEJETFLAME8
-	{SPR_FLME, FF_FULLBRIGHT|8, 11, {NULL}, 0, 0,           S_NULL}, // S_FLAMEJETFLAME9
+	{SPR_NULL, 0, 2*TICRATE, {NULL},             0, 0, S_FLAMEJETSTART, 0}, // S_FLAMEJETSTND
+	{SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTOP, 0}, // S_FLAMEJETSTART
+	{SPR_NULL, 0,         1, {A_ToggleFlameJet}, 0, 0,  S_FLAMEJETSTND, 0}, // S_FLAMEJETSTOP
+	{SPR_FLME, FF_FULLBRIGHT  ,  4, {NULL}, 0, 0, S_FLAMEJETFLAME2, 0}, // S_FLAMEJETFLAME1
+	{SPR_FLME, FF_FULLBRIGHT|1,  5, {NULL}, 0, 0, S_FLAMEJETFLAME3, 0}, // S_FLAMEJETFLAME2
+	{SPR_FLME, FF_FULLBRIGHT|2, 11, {NULL}, 0, 0,           S_NULL, 0}, // S_FLAMEJETFLAME3
+	{SPR_FLME, FF_FULLBRIGHT|3,  4, {NULL}, 0, 0, S_FLAMEJETFLAME5, 0}, // S_FLAMEJETFLAME4
+	{SPR_FLME, FF_FULLBRIGHT|4,  5, {NULL}, 0, 0, S_FLAMEJETFLAME6, 0}, // S_FLAMEJETFLAME5
+	{SPR_FLME, FF_FULLBRIGHT|5, 11, {NULL}, 0, 0,           S_NULL, 0}, // S_FLAMEJETFLAME6
+	{SPR_FLME, FF_FULLBRIGHT|6,  4, {NULL}, 0, 0, S_FLAMEJETFLAME8, 0}, // S_FLAMEJETFLAME7
+	{SPR_FLME, FF_FULLBRIGHT|7,  5, {NULL}, 0, 0, S_FLAMEJETFLAME9, 0}, // S_FLAMEJETFLAME8
+	{SPR_FLME, FF_FULLBRIGHT|8, 11, {NULL}, 0, 0,           S_NULL, 0}, // S_FLAMEJETFLAME9
 
 	// Spinning flame jets
 	// A: Counter-clockwise
-	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISA2}, // S_FJSPINAXISA1
-	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                 6,         6, S_FJSPINAXISA1}, // S_FJSPINAXISA2
+	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISA2, 0}, // S_FJSPINAXISA1
+	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                 6,         6, S_FJSPINAXISA1, 0}, // S_FJSPINAXISA2
 
 	// B: Clockwise
-	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISB2}, // S_FJSPINAXISB1
-	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                -6,        -6, S_FJSPINAXISB1}, // S_FJSPINAXISB2
+	{SPR_NULL, 0, 1,            {A_TrapShot}, MT_FLAMEJETFLAMEB, -(16<<16)|(1<<15)|64, S_FJSPINAXISB2, 0}, // S_FJSPINAXISB1
+	{SPR_NULL, 0, 2, {A_ChangeAngleRelative},                -6,        -6, S_FJSPINAXISB1, 0}, // S_FJSPINAXISB2
 
 	// Blade's flame
-	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2}, // S_FLAMEJETFLAMEB1
-	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2
-	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL},  // S_FLAMEJETFLAMEB3
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 5, S_FLAMEJETFLAMEB2, 0}, // S_FLAMEJETFLAMEB1
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3, 0}, // S_FLAMEJETFLAMEB2
+	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL, 0},  // S_FLAMEJETFLAMEB3
 
 	// Lavafall
-	{SPR_LFAL, 5, 1, {NULL}, 0, 0, S_LAVAFALL_DORMANT}, // S_LAVAFALL_DORMANT
-	{SPR_LFAL, 6|FF_ANIMATE, 4, {A_LavafallRocks}, 1, 2, S_LAVAFALL_TELL}, // S_LAVAFALL_TELL
-	{SPR_LFAL, 9|FF_FULLBRIGHT|FF_ANIMATE, 2, {A_LavafallLava}, 1, 1, S_LAVAFALL_SHOOT}, // S_LAVAFALL_SHOOT
-	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA2}, // S_LAVAFALL_LAVA1
-	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA1}, // S_LAVAFALL_LAVA2
-	{SPR_LFAL, 2|FF_FULLBRIGHT|FF_ANIMATE, 9, {NULL}, 2, 3, S_NULL}, // S_LAVAFALL_LAVA3
-	{SPR_LFAL, 11|FF_ANIMATE|FF_RANDOMANIM, 12, {NULL}, 3, 3, S_LAVAFALLROCK}, // S_LAVAFALLROCK
+	{SPR_LFAL, 5, 1, {NULL}, 0, 0, S_LAVAFALL_DORMANT, 0}, // S_LAVAFALL_DORMANT
+	{SPR_LFAL, 6|FF_ANIMATE, 4, {A_LavafallRocks}, 1, 2, S_LAVAFALL_TELL, 0}, // S_LAVAFALL_TELL
+	{SPR_LFAL, 9|FF_FULLBRIGHT|FF_ANIMATE, 2, {A_LavafallLava}, 1, 1, S_LAVAFALL_SHOOT, 0}, // S_LAVAFALL_SHOOT
+	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA2, 0}, // S_LAVAFALL_LAVA1
+	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA1, 0}, // S_LAVAFALL_LAVA2
+	{SPR_LFAL, 2|FF_FULLBRIGHT|FF_ANIMATE, 9, {NULL}, 2, 3, S_NULL, 0}, // S_LAVAFALL_LAVA3
+	{SPR_LFAL, 11|FF_ANIMATE|FF_RANDOMANIM, 12, {NULL}, 3, 3, S_LAVAFALLROCK, 0}, // S_LAVAFALLROCK
 
 	// Rollout Rock
-	{SPR_NULL, 0, 1, {A_RolloutSpawn}, 256*FRACUNIT, MT_ROLLOUTROCK, S_ROLLOUTSPAWN}, // S_ROLLOUTSPAWN
-	{SPR_PUMI, 0, 1, {A_RolloutRock},    63*FRACUNIT/64,  7*FRACUNIT/10,  S_ROLLOUTROCK}, // S_ROLLOUTROCK
+	{SPR_NULL, 0, 1, {A_RolloutSpawn}, 256*FRACUNIT, MT_ROLLOUTROCK, S_ROLLOUTSPAWN, 0}, // S_ROLLOUTSPAWN
+	{SPR_PUMI, 0, 1, {A_RolloutRock},    63*FRACUNIT/64,  7*FRACUNIT/10,  S_ROLLOUTROCK, 0}, // S_ROLLOUTROCK
 
 	// RVZ scenery
-	{SPR_JPLA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERNLEAF
-	{SPR_JPLA, 1, 1, {NULL}, 0, 0, S_BIGFERN2}, // S_BIGFERN1
-	{SPR_JPLA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERN2
-	{SPR_JPLA, 2, -1, {NULL}, 0, 0, S_NULL}, // S_JUNGLEPALM
-	{SPR_TFLO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_TORCHFLOWER}, // S_TORCHFLOWER
-	{SPR_WVIN, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_LONG
-	{SPR_WVIN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_SHORT
+	{SPR_JPLA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGFERNLEAF
+	{SPR_JPLA, 1, 1, {NULL}, 0, 0, S_BIGFERN2, 0}, // S_BIGFERN1
+	{SPR_JPLA, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIGFERN2
+	{SPR_JPLA, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JUNGLEPALM
+	{SPR_TFLO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_TORCHFLOWER, 0}, // S_TORCHFLOWER
+	{SPR_WVIN, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLVINE_LONG
+	{SPR_WVIN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_WALLVINE_SHORT
 
 	// Glaregoyles
-	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLE_CHARGE},  // S_GLAREGOYLE
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLE_BLINK},  // S_GLAREGOYLE_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLE_HOLD}, // S_GLAREGOYLE_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLE_FIRE},  // S_GLAREGOYLE_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLE_LOOP},  // S_GLAREGOYLE_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLE_FIRE, S_GLAREGOYLE_COOLDOWN}, // S_GLAREGOYLE_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLE}, // S_GLAREGOYLE_COOLDOWN
-
-	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEUP_CHARGE},  // S_GLAREGOYLEUP
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEUP_BLINK},  // S_GLAREGOYLEUP_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEUP_HOLD}, // S_GLAREGOYLEUP_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEUP_FIRE},  // S_GLAREGOYLEUP_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_GLAREGOYLEUP_LOOP},  // S_GLAREGOYLEUP_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEUP_FIRE, S_GLAREGOYLEUP_COOLDOWN}, // S_GLAREGOYLEUP_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEUP}, // S_GLAREGOYLEUP_COOLDOWN
-
-	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEDOWN_CHARGE},  // S_GLAREGOYLEDOWN
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEDOWN_BLINK},  // S_GLAREGOYLEDOWN_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEDOWN_HOLD}, // S_GLAREGOYLEDOWN_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEDOWN_FIRE},  // S_GLAREGOYLEDOWN_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_GLAREGOYLEDOWN_LOOP},  // S_GLAREGOYLEDOWN_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEDOWN_FIRE, S_GLAREGOYLEDOWN_COOLDOWN}, // S_GLAREGOYLEDOWN_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEDOWN}, // S_GLAREGOYLEDOWN_COOLDOWN
-
-	{SPR_BGAR,            0, 90, {NULL},       0, 0, S_GLAREGOYLELONG_CHARGE},  // S_GLAREGOYLELONG
-	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLELONG_BLINK},  // S_GLAREGOYLELONG_CHARGE
-	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLELONG_HOLD}, // S_GLAREGOYLELONG_BLINK
-	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLELONG_FIRE},  // S_GLAREGOYLELONG_HOLD
-	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLELONG_LOOP},  // S_GLAREGOYLELONG_FIRE
-	{SPR_BGAR,            1,  0, {A_Repeat},   5, S_GLAREGOYLELONG_FIRE, S_GLAREGOYLELONG_COOLDOWN}, // S_GLAREGOYLELONG_LOOP
-	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLELONG}, // S_GLAREGOYLELONG_COOLDOWN
+	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLE_CHARGE, 0},  // S_GLAREGOYLE
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLE_BLINK, 0},  // S_GLAREGOYLE_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLE_HOLD, 0}, // S_GLAREGOYLE_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLE_FIRE, 0},  // S_GLAREGOYLE_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLE_LOOP, 0},  // S_GLAREGOYLE_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLE_FIRE, S_GLAREGOYLE_COOLDOWN, 0}, // S_GLAREGOYLE_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLE, 0}, // S_GLAREGOYLE_COOLDOWN
+
+	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEUP_CHARGE, 0},  // S_GLAREGOYLEUP
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEUP_BLINK, 0},  // S_GLAREGOYLEUP_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEUP_HOLD, 0}, // S_GLAREGOYLEUP_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEUP_FIRE, 0},  // S_GLAREGOYLEUP_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+45, S_GLAREGOYLEUP_LOOP, 0},  // S_GLAREGOYLEUP_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEUP_FIRE, S_GLAREGOYLEUP_COOLDOWN, 0}, // S_GLAREGOYLEUP_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEUP, 0}, // S_GLAREGOYLEUP_COOLDOWN
+
+	{SPR_BGAR,            0, 22, {NULL},       0, 0, S_GLAREGOYLEDOWN_CHARGE, 0},  // S_GLAREGOYLEDOWN
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLEDOWN_BLINK, 0},  // S_GLAREGOYLEDOWN_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLEDOWN_HOLD, 0}, // S_GLAREGOYLEDOWN_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLEDOWN_FIRE, 0},  // S_GLAREGOYLEDOWN_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16)+315, S_GLAREGOYLEDOWN_LOOP, 0},  // S_GLAREGOYLEDOWN_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   3, S_GLAREGOYLEDOWN_FIRE, S_GLAREGOYLEDOWN_COOLDOWN, 0}, // S_GLAREGOYLEDOWN_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLEDOWN, 0}, // S_GLAREGOYLEDOWN_COOLDOWN
+
+	{SPR_BGAR,            0, 90, {NULL},       0, 0, S_GLAREGOYLELONG_CHARGE, 0},  // S_GLAREGOYLELONG
+	{SPR_BGAR,            2,  6, {NULL},       0, 0, S_GLAREGOYLELONG_BLINK, 0},  // S_GLAREGOYLELONG_CHARGE
+	{SPR_BGAR, FF_ANIMATE|1, 18, {NULL},       1, 3, S_GLAREGOYLELONG_HOLD, 0}, // S_GLAREGOYLELONG_BLINK
+	{SPR_BGAR,            1,  9, {NULL},       0, 0, S_GLAREGOYLELONG_FIRE, 0},  // S_GLAREGOYLELONG_HOLD
+	{SPR_BGAR,            1,  1, {A_TrapShot}, (16<<16)+MT_DEMONFIRE, (30<<16), S_GLAREGOYLELONG_LOOP, 0},  // S_GLAREGOYLELONG_FIRE
+	{SPR_BGAR,            1,  0, {A_Repeat},   5, S_GLAREGOYLELONG_FIRE, S_GLAREGOYLELONG_COOLDOWN, 0}, // S_GLAREGOYLELONG_LOOP
+	{SPR_BGAR, FF_ANIMATE|1, 15, {NULL},       1, 9, S_GLAREGOYLELONG, 0}, // S_GLAREGOYLELONG_COOLDOWN
 
 	// Target/Red Crystal
-	{SPR_RCRY,               0, -1, {NULL},                  0, 0, S_TARGET_IDLE},  // S_TARGET_IDLE
-	{SPR_RCRY, FF_FULLBRIGHT|1,  0, {A_PlaySound},           sfx_ding, 1, S_TARGET_HIT2},  // S_TARGET_HIT1
-	{SPR_RCRY, FF_FULLBRIGHT|1, 45, {A_SetObjectFlags},      MF_PUSHABLE, 2, S_TARGET_RESPAWN},  // S_TARGET_HIT2
-	{SPR_RCRY,               1,  0, {A_SpawnObjectRelative}, 0, MT_TARGET, S_NULL},  // S_TARGET_RESPAWN
-	{SPR_RCRY, FF_FULLBRIGHT|1, -1, {A_SetObjectFlags},      MF_PUSHABLE, 1, S_TARGET_ALLDONE},  // S_TARGET_ALLDONE
+	{SPR_RCRY,               0, -1, {NULL},                  0, 0, S_TARGET_IDLE, 0},  // S_TARGET_IDLE
+	{SPR_RCRY, FF_FULLBRIGHT|1,  0, {A_PlaySound},           sfx_ding, 1, S_TARGET_HIT2, 0},  // S_TARGET_HIT1
+	{SPR_RCRY, FF_FULLBRIGHT|1, 45, {A_SetObjectFlags},      MF_PUSHABLE, 2, S_TARGET_RESPAWN, 0},  // S_TARGET_HIT2
+	{SPR_RCRY,               1,  0, {A_SpawnObjectRelative}, 0, MT_TARGET, S_NULL, 0},  // S_TARGET_RESPAWN
+	{SPR_RCRY, FF_FULLBRIGHT|1, -1, {A_SetObjectFlags},      MF_PUSHABLE, 1, S_TARGET_ALLDONE, 0},  // S_TARGET_ALLDONE
 
 	// Green flame
-	{SPR_CFLM, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 3, S_GREENFLAME}, // S_GREENFLAME
+	{SPR_CFLM, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 3, S_GREENFLAME, 0}, // S_GREENFLAME
 
 	// ATZ Blue Gargoyle
-	{SPR_BGAR, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEGARGOYLE
+	{SPR_BGAR, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUEGARGOYLE
 
 	// Stalagmites
-	{SPR_STLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_STG0
-	{SPR_STLG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_STG1
-	{SPR_STLG, 2, -1, {NULL}, 0, 0, S_NULL}, // S_STG2
-	{SPR_STLG, 3, -1, {NULL}, 0, 0, S_NULL}, // S_STG3
-	{SPR_STLG, 4, -1, {NULL}, 0, 0, S_NULL}, // S_STG4
-	{SPR_STLG, 5, -1, {NULL}, 0, 0, S_NULL}, // S_STG5
-	{SPR_STLG, 6, -1, {NULL}, 0, 0, S_NULL}, // S_STG6
-	{SPR_STLG, 7, -1, {NULL}, 0, 0, S_NULL}, // S_STG7
-	{SPR_STLG, 8, -1, {NULL}, 0, 0, S_NULL}, // S_STG8
-	{SPR_STLG, 9, -1, {NULL}, 0, 0, S_NULL}, // S_STG9
+	{SPR_STLG, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG0
+	{SPR_STLG, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG1
+	{SPR_STLG, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG2
+	{SPR_STLG, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG3
+	{SPR_STLG, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG4
+	{SPR_STLG, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG5
+	{SPR_STLG, 6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG6
+	{SPR_STLG, 7, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG7
+	{SPR_STLG, 8, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG8
+	{SPR_STLG, 9, -1, {NULL}, 0, 0, S_NULL, 0}, // S_STG9
 
 	// Xmas-specific stuff
-	{SPR_XMS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_XMASPOLE
-	{SPR_XMS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANDYCANE
-	{SPR_XMS3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOWMAN
-	{SPR_XMS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOWMANHAT
-	{SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST1
-	{SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2
-	{SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR
-	{SPR_XMS6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MISTLETOE
+	{SPR_XMS1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASPOLE
+	{SPR_XMS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CANDYCANE
+	{SPR_XMS3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOWMAN
+	{SPR_XMS3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOWMANHAT
+	{SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LAMPPOST1
+	{SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LAMPPOST2
+	{SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HANGSTAR
+	{SPR_XMS6, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MISTLETOE
 	// Xmas GFZ bushes
-	{SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBLUEBERRYBUSH
-	{SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBERRYBUSH
-	{SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBUSH
+	{SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASBLUEBERRYBUSH
+	{SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASBERRYBUSH
+	{SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_XMASBUSH
 	// FHZ
-	{SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE1
-	{SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE2
-	{SPR_ROSY, 16, 8, {NULL}, 0, 0, S_ROSY_IDLE2}, // S_ROSY_IDLE1
-	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE3}, // S_ROSY_IDLE2
-	{SPR_ROSY, 18, 8, {NULL}, 0, 0, S_ROSY_IDLE4}, // S_ROSY_IDLE3
-	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE1}, // S_ROSY_IDLE4
-	{SPR_ROSY, 14, -1, {NULL}, 1, 0, S_NULL}, // S_ROSY_JUMP
-	{SPR_ROSY,  5, -1, {NULL}, 7, 0, S_NULL}, // S_ROSY_WALK
-	{SPR_ROSY, 19, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_HUG
-	{SPR_ROSY, 13, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_PAIN
-	{SPR_ROSY,  1|FF_ANIMATE, -1, {NULL}, 3, 16, S_NULL}, // S_ROSY_STND
-	{SPR_ROSY, 20|FF_ANIMATE, TICRATE, {NULL}, 3, 4, S_ROSY_WALK}, // S_ROSY_UNHAPPY
+	{SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZICE1
+	{SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FHZICE2
+	{SPR_ROSY, 16, 8, {NULL}, 0, 0, S_ROSY_IDLE2, 0}, // S_ROSY_IDLE1
+	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE3, 0}, // S_ROSY_IDLE2
+	{SPR_ROSY, 18, 8, {NULL}, 0, 0, S_ROSY_IDLE4, 0}, // S_ROSY_IDLE3
+	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE1, 0}, // S_ROSY_IDLE4
+	{SPR_ROSY, 14, -1, {NULL}, 1, 0, S_NULL, 0}, // S_ROSY_JUMP
+	{SPR_ROSY,  5, -1, {NULL}, 7, 0, S_NULL, 0}, // S_ROSY_WALK
+	{SPR_ROSY, 19, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_HUG
+	{SPR_ROSY, 13, -1, {NULL}, 0, 0, S_NULL, 0}, // S_ROSY_PAIN
+	{SPR_ROSY,  1|FF_ANIMATE, -1, {NULL}, 3, 16, S_NULL, 0}, // S_ROSY_STND
+	{SPR_ROSY, 20|FF_ANIMATE, TICRATE, {NULL}, 3, 4, S_ROSY_WALK, 0}, // S_ROSY_UNHAPPY
 
 	// Halloween Scenery
 	// Pumpkins
-	{SPR_PUMK,  0, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO1
-	{SPR_PUMK,  3|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_2}, // S_JACKO1OVERLAY_1
-	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_3}, // S_JACKO1OVERLAY_2
-	{SPR_PUMK,  5|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_4}, // S_JACKO1OVERLAY_3
-	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_1}, // S_JACKO1OVERLAY_4
-	{SPR_PUMK,  1, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO2
-	{SPR_PUMK,  6|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_2}, // S_JACKO2OVERLAY_1
-	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_3}, // S_JACKO2OVERLAY_2
-	{SPR_PUMK,  8|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_4}, // S_JACKO2OVERLAY_3
-	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_1}, // S_JACKO2OVERLAY_4
-	{SPR_PUMK,  2, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO3
-	{SPR_PUMK,  9|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_2}, // S_JACKO3OVERLAY_1
-	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_3}, // S_JACKO3OVERLAY_2
-	{SPR_PUMK, 11|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_4}, // S_JACKO3OVERLAY_3
-	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_1}, // S_JACKO3OVERLAY_4
+	{SPR_PUMK,  0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JACKO1
+	{SPR_PUMK,  3|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_2, 0}, // S_JACKO1OVERLAY_1
+	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_3, 0}, // S_JACKO1OVERLAY_2
+	{SPR_PUMK,  5|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_4, 0}, // S_JACKO1OVERLAY_3
+	{SPR_PUMK,  4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_1, 0}, // S_JACKO1OVERLAY_4
+	{SPR_PUMK,  1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JACKO2
+	{SPR_PUMK,  6|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_2, 0}, // S_JACKO2OVERLAY_1
+	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_3, 0}, // S_JACKO2OVERLAY_2
+	{SPR_PUMK,  8|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_4, 0}, // S_JACKO2OVERLAY_3
+	{SPR_PUMK,  7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_1, 0}, // S_JACKO2OVERLAY_4
+	{SPR_PUMK,  2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_JACKO3
+	{SPR_PUMK,  9|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_2, 0}, // S_JACKO3OVERLAY_1
+	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_3, 0}, // S_JACKO3OVERLAY_2
+	{SPR_PUMK, 11|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_4, 0}, // S_JACKO3OVERLAY_3
+	{SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_1, 0}, // S_JACKO3OVERLAY_4
 	// Dr Seuss Trees
-	{SPR_HHPL, 2, -1, {A_ConnectToGround}, MT_HHZTREE_PART, 0, S_NULL}, // S_HHZTREE_TOP,
-	{SPR_HHPL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTREE_TRUNK,
-	{SPR_HHPL, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTREE_LEAF,
+	{SPR_HHPL, 2, -1, {A_ConnectToGround}, MT_HHZTREE_PART, 0, S_NULL, 0}, // S_HHZTREE_TOP,
+	{SPR_HHPL, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTREE_TRUNK,
+	{SPR_HHPL, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTREE_LEAF,
 	// Mushroom
-	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_2},  // S_HHZSHROOM_1,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_3},  // S_HHZSHROOM_2,
-	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_4},  // S_HHZSHROOM_3,
-	{SPR_SHRM, 1,  1, {NULL}, 0, 0, S_HHZSHROOM_5},  // S_HHZSHROOM_4,
-	{SPR_SHRM, 0,  1, {NULL}, 0, 0, S_HHZSHROOM_6},  // S_HHZSHROOM_5,
-	{SPR_SHRM, 1,  4, {NULL}, 0, 0, S_HHZSHROOM_7},  // S_HHZSHROOM_6,
-	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_8},  // S_HHZSHROOM_7,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_9},  // S_HHZSHROOM_8,
-	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_10}, // S_HHZSHROOM_9,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_11}, // S_HHZSHROOM_10,
-	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_12}, // S_HHZSHROOM_11,
-	{SPR_SHRM, 6,  1, {NULL}, 0, 0, S_HHZSHROOM_13}, // S_HHZSHROOM_12,
-	{SPR_SHRM, 7,  1, {NULL}, 0, 0, S_HHZSHROOM_14}, // S_HHZSHROOM_13,
-	{SPR_SHRM, 6,  4, {NULL}, 0, 0, S_HHZSHROOM_15}, // S_HHZSHROOM_14,
-	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_16}, // S_HHZSHROOM_15,
-	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_1},  // S_HHZSHROOM_16,
+	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_2, 0},  // S_HHZSHROOM_1,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_3, 0},  // S_HHZSHROOM_2,
+	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_4, 0},  // S_HHZSHROOM_3,
+	{SPR_SHRM, 1,  1, {NULL}, 0, 0, S_HHZSHROOM_5, 0},  // S_HHZSHROOM_4,
+	{SPR_SHRM, 0,  1, {NULL}, 0, 0, S_HHZSHROOM_6, 0},  // S_HHZSHROOM_5,
+	{SPR_SHRM, 1,  4, {NULL}, 0, 0, S_HHZSHROOM_7, 0},  // S_HHZSHROOM_6,
+	{SPR_SHRM, 2,  2, {NULL}, 0, 0, S_HHZSHROOM_8, 0},  // S_HHZSHROOM_7,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_9, 0},  // S_HHZSHROOM_8,
+	{SPR_SHRM, 4,  3, {NULL}, 0, 0, S_HHZSHROOM_10, 0}, // S_HHZSHROOM_9,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_11, 0}, // S_HHZSHROOM_10,
+	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_12, 0}, // S_HHZSHROOM_11,
+	{SPR_SHRM, 6,  1, {NULL}, 0, 0, S_HHZSHROOM_13, 0}, // S_HHZSHROOM_12,
+	{SPR_SHRM, 7,  1, {NULL}, 0, 0, S_HHZSHROOM_14, 0}, // S_HHZSHROOM_13,
+	{SPR_SHRM, 6,  4, {NULL}, 0, 0, S_HHZSHROOM_15, 0}, // S_HHZSHROOM_14,
+	{SPR_SHRM, 5,  2, {NULL}, 0, 0, S_HHZSHROOM_16, 0}, // S_HHZSHROOM_15,
+	{SPR_SHRM, 3,  3, {NULL}, 0, 0, S_HHZSHROOM_1, 0},  // S_HHZSHROOM_16,
 	// Misc
-	{SPR_HHZM, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HHZGRASS,
-	{SPR_HHZM, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTENT1,
-	{SPR_HHZM, 2, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTENT2,
-	{SPR_HHZM, 4, -1, {NULL}, 0, 0, S_NULL}, // S_HHZSTALAGMITE_TALL,
-	{SPR_HHZM, 5, -1, {NULL}, 0, 0, S_NULL}, // S_HHZSTALAGMITE_SHORT,
+	{SPR_HHZM, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZGRASS,
+	{SPR_HHZM, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTENT1,
+	{SPR_HHZM, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZTENT2,
+	{SPR_HHZM, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZSTALAGMITE_TALL,
+	{SPR_HHZM, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HHZSTALAGMITE_SHORT,
 
 	// Loads of Botanic Serenity bullshit
-	{SPR_BSZ1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_RED
-	{SPR_BSZ1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_PURPLE
-	{SPR_BSZ1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_BLUE
-	{SPR_BSZ1, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_CYAN
-	{SPR_BSZ1, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_YELLOW
-	{SPR_BSZ1, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_ORANGE
-	{SPR_BSZ2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_RED
-	{SPR_BSZ2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_PURPLE
-	{SPR_BSZ2, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_BLUE
-	{SPR_BSZ2, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_CYAN
-	{SPR_BSZ2, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_YELLOW
-	{SPR_BSZ2, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZFLOWER_ORANGE
-	{SPR_BSZ3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_RED
-	{SPR_BSZ3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_PURPLE
-	{SPR_BSZ3, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_BLUE
-	{SPR_BSZ3, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_CYAN
-	{SPR_BSZ3, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_YELLOW
-	{SPR_BSZ3, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_ORANGE
-	{SPR_BST1, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_RED
-	{SPR_BST2, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_PURPLE
-	{SPR_BST3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_BLUE
-	{SPR_BST4, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_CYAN
-	{SPR_BST5, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_YELLOW
-	{SPR_BST6, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_ORANGE
-	{SPR_BSZ5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_RED
-	{SPR_BSZ5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_PURPLE
-	{SPR_BSZ5, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_BLUE
-	{SPR_BSZ5, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_CYAN
-	{SPR_BSZ5, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_YELLOW
-	{SPR_BSZ5, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_ORANGE
-	{SPR_BSZ6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_RED
-	{SPR_BSZ6, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_PURPLE
-	{SPR_BSZ6, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_BLUE
-	{SPR_BSZ6, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_CYAN
-	{SPR_BSZ6, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_YELLOW
-	{SPR_BSZ6, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZBUSH_ORANGE
-	{SPR_BSZ7, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_RED
-	{SPR_BSZ7, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_PURPLE
-	{SPR_BSZ7, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_BLUE
-	{SPR_BSZ7, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_CYAN
-	{SPR_BSZ7, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_YELLOW
-	{SPR_BSZ7, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZVINE_ORANGE
-	{SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHRUB
-	{SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLOVER
-	{SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BIG_PALMTREE_TRUNK
-	{SPR_BSZ8, 3, -1, {A_ConnectToGround}, MT_BIG_PALMTREE_TRUNK, 0, S_NULL}, // S_BIG_PALMTREE_TOP
-	{SPR_BSZ8, 4, -1, {NULL}, 0, 0, S_NULL}, // S_PALMTREE_TRUNK
-	{SPR_BSZ8, 5, -1, {A_ConnectToGround},     MT_PALMTREE_TRUNK, 0, S_NULL}, // S_PALMTREE_TOP
+	{SPR_BSZ1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_RED
+	{SPR_BSZ1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_PURPLE
+	{SPR_BSZ1, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_BLUE
+	{SPR_BSZ1, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_CYAN
+	{SPR_BSZ1, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_YELLOW
+	{SPR_BSZ1, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZTALLFLOWER_ORANGE
+	{SPR_BSZ2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_RED
+	{SPR_BSZ2, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_PURPLE
+	{SPR_BSZ2, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_BLUE
+	{SPR_BSZ2, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_CYAN
+	{SPR_BSZ2, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_YELLOW
+	{SPR_BSZ2, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZFLOWER_ORANGE
+	{SPR_BSZ3, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_RED
+	{SPR_BSZ3, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_PURPLE
+	{SPR_BSZ3, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_BLUE
+	{SPR_BSZ3, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_CYAN
+	{SPR_BSZ3, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_YELLOW
+	{SPR_BSZ3, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHORTFLOWER_ORANGE
+	{SPR_BST1, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_RED
+	{SPR_BST2, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_PURPLE
+	{SPR_BST3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_BLUE
+	{SPR_BST4, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_CYAN
+	{SPR_BST5, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_YELLOW
+	{SPR_BST6, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL, 0}, // S_BSZTULIP_ORANGE
+	{SPR_BSZ5, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_RED
+	{SPR_BSZ5, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_PURPLE
+	{SPR_BSZ5, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_BLUE
+	{SPR_BSZ5, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_CYAN
+	{SPR_BSZ5, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_YELLOW
+	{SPR_BSZ5, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLUSTER_ORANGE
+	{SPR_BSZ6, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_RED
+	{SPR_BSZ6, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_PURPLE
+	{SPR_BSZ6, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_BLUE
+	{SPR_BSZ6, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_CYAN
+	{SPR_BSZ6, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_YELLOW
+	{SPR_BSZ6, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZBUSH_ORANGE
+	{SPR_BSZ7, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_RED
+	{SPR_BSZ7, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_PURPLE
+	{SPR_BSZ7, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_BLUE
+	{SPR_BSZ7, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_CYAN
+	{SPR_BSZ7, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_YELLOW
+	{SPR_BSZ7, 5, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZVINE_ORANGE
+	{SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZSHRUB
+	{SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BSZCLOVER
+	{SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BIG_PALMTREE_TRUNK
+	{SPR_BSZ8, 3, -1, {A_ConnectToGround}, MT_BIG_PALMTREE_TRUNK, 0, S_NULL, 0}, // S_BIG_PALMTREE_TOP
+	{SPR_BSZ8, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_PALMTREE_TRUNK
+	{SPR_BSZ8, 5, -1, {A_ConnectToGround},     MT_PALMTREE_TRUNK, 0, S_NULL, 0}, // S_PALMTREE_TOP
 
 	// Disco ball
-	{SPR_DBAL, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_DBALL2}, // S_DBALL1
-	{SPR_DBAL, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_DBALL3}, // S_DBALL2
-	{SPR_DBAL, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_DBALL4}, // S_DBALL3
-	{SPR_DBAL, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_DBALL5}, // S_DBALL4
-	{SPR_DBAL, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_DBALL6}, // S_DBALL5
-	{SPR_DBAL, FF_FULLBRIGHT|5, 5, {NULL}, 0, 0, S_DBALL1}, // S_DBALL6
+	{SPR_DBAL, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_DBALL2, 0}, // S_DBALL1
+	{SPR_DBAL, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_DBALL3, 0}, // S_DBALL2
+	{SPR_DBAL, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_DBALL4, 0}, // S_DBALL3
+	{SPR_DBAL, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_DBALL5, 0}, // S_DBALL4
+	{SPR_DBAL, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_DBALL6, 0}, // S_DBALL5
+	{SPR_DBAL, FF_FULLBRIGHT|5, 5, {NULL}, 0, 0, S_DBALL1, 0}, // S_DBALL6
 
-	{SPR_ESTA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE2
+	{SPR_ESTA, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGSTATUE2
 
 	// Shield Orb
-	{SPR_ARMA, FF_TRANS40   , 2, {NULL}, 0, 0, S_ARMA2 }, // S_ARMA1
-	{SPR_ARMA, FF_TRANS40| 1, 2, {NULL}, 0, 0, S_ARMA3 }, // S_ARMA2
-	{SPR_ARMA, FF_TRANS40| 2, 2, {NULL}, 0, 0, S_ARMA4 }, // S_ARMA3
-	{SPR_ARMA, FF_TRANS40| 3, 2, {NULL}, 0, 0, S_ARMA5 }, // S_ARMA4
-	{SPR_ARMA, FF_TRANS40| 4, 2, {NULL}, 0, 0, S_ARMA6 }, // S_ARMA5
-	{SPR_ARMA, FF_TRANS40| 5, 2, {NULL}, 0, 0, S_ARMA7 }, // S_ARMA6
-	{SPR_ARMA, FF_TRANS40| 6, 2, {NULL}, 0, 0, S_ARMA8 }, // S_ARMA7
-	{SPR_ARMA, FF_TRANS40| 7, 2, {NULL}, 0, 0, S_ARMA9 }, // S_ARMA8
-	{SPR_ARMA, FF_TRANS40| 8, 2, {NULL}, 0, 0, S_ARMA10}, // S_ARMA9
-	{SPR_ARMA, FF_TRANS40| 9, 2, {NULL}, 0, 0, S_ARMA11}, // S_ARMA10
-	{SPR_ARMA, FF_TRANS40|10, 2, {NULL}, 0, 0, S_ARMA12}, // S_ARMA11
-	{SPR_ARMA, FF_TRANS40|11, 2, {NULL}, 0, 0, S_ARMA13}, // S_ARMA12
-	{SPR_ARMA, FF_TRANS40|12, 2, {NULL}, 0, 0, S_ARMA14}, // S_ARMA13
-	{SPR_ARMA, FF_TRANS40|13, 2, {NULL}, 0, 0, S_ARMA15}, // S_ARMA14
-	{SPR_ARMA, FF_TRANS40|14, 2, {NULL}, 0, 0, S_ARMA16}, // S_ARMA15
-	{SPR_ARMA, FF_TRANS40|15, 2, {NULL}, 0, 0, S_ARMA1 }, // S_ARMA16
-
-	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF2 }, // S_ARMF1
-	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF3 }, // S_ARMF2
-	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF4 }, // S_ARMF3
-	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF5 }, // S_ARMF4
-	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF6 }, // S_ARMF5
-	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF7 }, // S_ARMF6
-	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF8 }, // S_ARMF7
-	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF9 }, // S_ARMF8
-	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF10}, // S_ARMF9
-	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF11}, // S_ARMF10
-	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF12}, // S_ARMF11
-	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF13}, // S_ARMF12
-	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF14}, // S_ARMF13
-	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF15}, // S_ARMF14
-	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF16}, // S_ARMF15
-	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF17}, // S_ARMF16
-	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF18}, // S_ARMF17
-	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF19}, // S_ARMF18
-	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF20}, // S_ARMF19
-	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF21}, // S_ARMF20
-	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF22}, // S_ARMF21
-	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF23}, // S_ARMF22
-	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF24}, // S_ARMF23
-	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF25}, // S_ARMF24
-	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF26}, // S_ARMF25
-	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF27}, // S_ARMF26
-	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF28}, // S_ARMF27
-	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF29}, // S_ARMF28
-	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF30}, // S_ARMF29
-	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF31}, // S_ARMF30
-	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF32}, // S_ARMF31
-	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF1 }, // S_ARMF32
-
-	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB2 }, // S_ARMB1
-	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB3 }, // S_ARMB2
-	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB4 }, // S_ARMB3
-	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB5 }, // S_ARMB4
-	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB6 }, // S_ARMB5
-	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB7 }, // S_ARMB6
-	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB8 }, // S_ARMB7
-	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB9 }, // S_ARMB8
-	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB10}, // S_ARMB9
-	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB11}, // S_ARMB10
-	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB12}, // S_ARMB11
-	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB13}, // S_ARMB12
-	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB14}, // S_ARMB13
-	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB15}, // S_ARMB14
-	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB16}, // S_ARMB15
-	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB17}, // S_ARMB16
-	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB18}, // S_ARMB17
-	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB19}, // S_ARMB18
-	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB20}, // S_ARMB19
-	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB21}, // S_ARMB20
-	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB22}, // S_ARMB21
-	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB23}, // S_ARMB22
-	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB24}, // S_ARMB23
-	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB25}, // S_ARMB24
-	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB26}, // S_ARMB25
-	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB27}, // S_ARMB26
-	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB28}, // S_ARMB27
-	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB29}, // S_ARMB28
-	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB30}, // S_ARMB29
-	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB31}, // S_ARMB30
-	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB32}, // S_ARMB31
-	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB1 }, // S_ARMB32
-
-	{SPR_WIND, FF_TRANS70  , 2, {NULL}, 0, 0, S_WIND2}, // S_WIND1
-	{SPR_WIND, FF_TRANS70|1, 2, {NULL}, 0, 0, S_WIND3}, // S_WIND2
-	{SPR_WIND, FF_TRANS70|2, 2, {NULL}, 0, 0, S_WIND4}, // S_WIND3
-	{SPR_WIND, FF_TRANS70|3, 2, {NULL}, 0, 0, S_WIND5}, // S_WIND4
-	{SPR_WIND, FF_TRANS70|4, 2, {NULL}, 0, 0, S_WIND6}, // S_WIND5
-	{SPR_WIND, FF_TRANS70|5, 2, {NULL}, 0, 0, S_WIND7}, // S_WIND6
-	{SPR_WIND, FF_TRANS70|6, 2, {NULL}, 0, 0, S_WIND8}, // S_WIND7
-	{SPR_WIND, FF_TRANS70|7, 2, {NULL}, 0, 0, S_WIND1}, // S_WIND8
-
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40   , 2, {NULL}, 0, 0, S_MAGN2 }, // S_MAGN1
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 1, 2, {NULL}, 0, 0, S_MAGN3 }, // S_MAGN2
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 2, 2, {NULL}, 0, 0, S_MAGN4 }, // S_MAGN3
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 3, 2, {NULL}, 0, 0, S_MAGN5 }, // S_MAGN4
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 4, 2, {NULL}, 0, 0, S_MAGN6 }, // S_MAGN5
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 5, 2, {NULL}, 0, 0, S_MAGN7 }, // S_MAGN6
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 6, 2, {NULL}, 0, 0, S_MAGN8 }, // S_MAGN7
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 7, 2, {NULL}, 0, 0, S_MAGN9 }, // S_MAGN8
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 8, 2, {NULL}, 0, 0, S_MAGN10}, // S_MAGN9
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_MAGN11}, // S_MAGN10
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_MAGN12}, // S_MAGN11
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN12
-
-	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS10|12, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN13
-
-	{SPR_FORC, FF_TRANS50  , 3, {NULL}, 0, 0, S_FORC2 }, // S_FORC1
-	{SPR_FORC, FF_TRANS50|1, 3, {NULL}, 0, 0, S_FORC3 }, // S_FORC2
-	{SPR_FORC, FF_TRANS50|2, 3, {NULL}, 0, 0, S_FORC4 }, // S_FORC3
-	{SPR_FORC, FF_TRANS50|3, 3, {NULL}, 0, 0, S_FORC5 }, // S_FORC4
-	{SPR_FORC, FF_TRANS50|4, 3, {NULL}, 0, 0, S_FORC6 }, // S_FORC5
-	{SPR_FORC, FF_TRANS50|5, 3, {NULL}, 0, 0, S_FORC7 }, // S_FORC6
-	{SPR_FORC, FF_TRANS50|6, 3, {NULL}, 0, 0, S_FORC8 }, // S_FORC7
-	{SPR_FORC, FF_TRANS50|7, 3, {NULL}, 0, 0, S_FORC9 }, // S_FORC8
-	{SPR_FORC, FF_TRANS50|8, 3, {NULL}, 0, 0, S_FORC10}, // S_FORC9
-	{SPR_FORC, FF_TRANS50|9, 3, {NULL}, 0, 0, S_FORC1 }, // S_FORC10
-
-	{SPR_FORC, FF_TRANS50|10, 3, {NULL}, 0, 0, S_FORC12}, // S_FORC11
-	{SPR_FORC, FF_TRANS50|11, 3, {NULL}, 0, 0, S_FORC13}, // S_FORC12
-	{SPR_FORC, FF_TRANS50|12, 3, {NULL}, 0, 0, S_FORC14}, // S_FORC13
-	{SPR_FORC, FF_TRANS50|13, 3, {NULL}, 0, 0, S_FORC15}, // S_FORC14
-	{SPR_FORC, FF_TRANS50|14, 3, {NULL}, 0, 0, S_FORC16}, // S_FORC15
-	{SPR_FORC, FF_TRANS50|15, 3, {NULL}, 0, 0, S_FORC17}, // S_FORC16
-	{SPR_FORC, FF_TRANS50|16, 3, {NULL}, 0, 0, S_FORC18}, // S_FORC17
-	{SPR_FORC, FF_TRANS50|17, 3, {NULL}, 0, 0, S_FORC19}, // S_FORC18
-	{SPR_FORC, FF_TRANS50|18, 3, {NULL}, 0, 0, S_FORC20}, // S_FORC19
-	{SPR_FORC, FF_TRANS50|19, 3, {NULL}, 0, 0, S_FORC11}, // S_FORC20
-
-	{SPR_FORC, FF_TRANS50|20, -1, {NULL}, 0, 0, S_NULL}, // S_FORC21
-
-	{SPR_ELEM, FF_TRANS50   , 4, {NULL}, 0, 0, S_ELEM2 }, // S_ELEM1
-	{SPR_ELEM, FF_TRANS50| 1, 4, {NULL}, 0, 0, S_ELEM3 }, // S_ELEM2
-	{SPR_ELEM, FF_TRANS50| 2, 4, {NULL}, 0, 0, S_ELEM4 }, // S_ELEM3
-	{SPR_ELEM, FF_TRANS50| 3, 4, {NULL}, 0, 0, S_ELEM5 }, // S_ELEM4
-	{SPR_ELEM, FF_TRANS50| 4, 4, {NULL}, 0, 0, S_ELEM6 }, // S_ELEM5
-	{SPR_ELEM, FF_TRANS50| 5, 4, {NULL}, 0, 0, S_ELEM7 }, // S_ELEM6
-	{SPR_ELEM, FF_TRANS50| 6, 4, {NULL}, 0, 0, S_ELEM8 }, // S_ELEM7
-	{SPR_ELEM, FF_TRANS50| 7, 4, {NULL}, 0, 0, S_ELEM9 }, // S_ELEM8
-	{SPR_ELEM, FF_TRANS50| 8, 4, {NULL}, 0, 0, S_ELEM10}, // S_ELEM9
-	{SPR_ELEM, FF_TRANS50| 9, 4, {NULL}, 0, 0, S_ELEM11}, // S_ELEM10
-	{SPR_ELEM, FF_TRANS50|10, 4, {NULL}, 0, 0, S_ELEM12}, // S_ELEM11
-	{SPR_ELEM, FF_TRANS50|11, 4, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM12
-
-	{SPR_NULL,             0, 1, {NULL}, 0, 0, S_ELEM14}, // S_ELEM13
-	{SPR_ELEM, FF_TRANS50|11, 1, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM14
-
-	{SPR_ELEM, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ELEMF2 }, // S_ELEMF1
-	{SPR_ELEM, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ELEMF3 }, // S_ELEMF2
-	{SPR_ELEM, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ELEMF4 }, // S_ELEMF3
-	{SPR_ELEM, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ELEMF5 }, // S_ELEMF4
-	{SPR_ELEM, FF_FULLBRIGHT|16, 3, {NULL}, 0, 0, S_ELEMF6 }, // S_ELEMF5
-	{SPR_ELEM, FF_FULLBRIGHT|17, 3, {NULL}, 0, 0, S_ELEMF7 }, // S_ELEMF6
-	{SPR_ELEM, FF_FULLBRIGHT|18, 3, {NULL}, 0, 0, S_ELEMF8 }, // S_ELEMF7
-	{SPR_ELEM, FF_FULLBRIGHT|19, 3, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF8
-
-	{SPR_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10}, // S_ELEMF9
-	{SPR_NULL, 0,                1, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF10
-
-	{SPR_PITY, FF_TRANS30   , 2, {NULL}, 0, 0, S_PITY2},  // S_PITY1
-	{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3},  // S_PITY2
-	{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4},  // S_PITY3
-	{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5},  // S_PITY4
-	{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6},  // S_PITY5
-	{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7},  // S_PITY6
-	{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8},  // S_PITY7
-	{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9},  // S_PITY8
-	{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10}, // S_PITY9
-	{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11}, // S_PITY10
-	{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12}, // S_PITY11
-	{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1},  // S_PITY12
-
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40  , 2, {NULL}, 0, 0, S_FIRS2}, // S_FIRS1
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3}, // S_FIRS2
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|2, 2, {NULL}, 0, 0, S_FIRS4}, // S_FIRS3
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|3, 2, {NULL}, 0, 0, S_FIRS5}, // S_FIRS4
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|4, 2, {NULL}, 0, 0, S_FIRS6}, // S_FIRS5
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|5, 2, {NULL}, 0, 0, S_FIRS7}, // S_FIRS6
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|6, 2, {NULL}, 0, 0, S_FIRS8}, // S_FIRS7
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|7, 2, {NULL}, 0, 0, S_FIRS9}, // S_FIRS8
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|8, 2, {NULL}, 0, 0, S_FIRS1}, // S_FIRS9
-
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|18, 1, {NULL}, 0, 0, S_FIRS11}, // S_FIRS10
-	{SPR_NULL, 0,                           1, {NULL}, 0, 0, S_FIRS1 }, // S_FIRS11
-
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_FIRSB2}, // S_FIRSB1
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_FIRSB3}, // S_FIRSB2
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_FIRSB4}, // S_FIRSB3
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|12, 2, {NULL}, 0, 0, S_FIRSB5}, // S_FIRSB4
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|13, 2, {NULL}, 0, 0, S_FIRSB6}, // S_FIRSB5
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|14, 2, {NULL}, 0, 0, S_FIRSB7}, // S_FIRSB6
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|15, 2, {NULL}, 0, 0, S_FIRSB8}, // S_FIRSB7
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|16, 2, {NULL}, 0, 0, S_FIRSB9}, // S_FIRSB8
-	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|17, 2, {NULL}, 0, 0, S_FIRSB1}, // S_FIRSB9
-
-	{SPR_NULL, 0,                           2, {NULL}, 0, 0, S_FIRSB1 }, // S_FIRSB10
-
-	{SPR_BUBS, FF_TRANS30  , 3, {NULL}, 0, 0, S_BUBS2}, // S_BUBS1
-	{SPR_BUBS, FF_TRANS30|1, 3, {NULL}, 0, 0, S_BUBS3}, // S_BUBS2
-	{SPR_BUBS, FF_TRANS30|2, 3, {NULL}, 0, 0, S_BUBS4}, // S_BUBS3
-	{SPR_BUBS, FF_TRANS30|3, 3, {NULL}, 0, 0, S_BUBS5}, // S_BUBS4
-	{SPR_BUBS, FF_TRANS30|4, 3, {NULL}, 0, 0, S_BUBS6}, // S_BUBS5
-	{SPR_BUBS, FF_TRANS30|5, 3, {NULL}, 0, 0, S_BUBS7}, // S_BUBS6
-	{SPR_BUBS, FF_TRANS30|6, 3, {NULL}, 0, 0, S_BUBS8}, // S_BUBS7
-	{SPR_BUBS, FF_TRANS30|7, 3, {NULL}, 0, 0, S_BUBS9}, // S_BUBS8
-	{SPR_BUBS, FF_TRANS30|8, 3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS9
-
-	{SPR_NULL, 0,   3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS10
-	{SPR_NULL, 0, 4*3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS11
-
-	{SPR_BUBS, FF_TRANS30| 9, 3, {NULL}, 0, 0, S_BUBSB2}, // S_BUBSB1
-	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB3}, // S_BUBSB2
-	{SPR_BUBS, FF_TRANS30|11, 3, {NULL}, 0, 0, S_BUBSB4}, // S_BUBSB3
-	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB1}, // S_BUBSB4
-
-	{SPR_BUBS, FF_TRANS30|12, 3, {NULL}, 0, 0, S_BUBSB3}, // S_BUBSB5
-	{SPR_BUBS, FF_TRANS30|13, 3, {NULL}, 0, 0, S_BUBSB5}, // S_BUBSB6
-
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,   2, {NULL}, 0, 0, S_ZAPS2 }, // S_ZAPS1
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,   2, {NULL}, 0, 0, S_ZAPS3 }, // S_ZAPS2
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,   2, {NULL}, 0, 0, S_ZAPS4 }, // S_ZAPS3
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,   2, {NULL}, 0, 0, S_ZAPS5 }, // S_ZAPS4
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,   2, {NULL}, 0, 0, S_ZAPS6 }, // S_ZAPS5
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,   2, {NULL}, 0, 0, S_ZAPS7 }, // S_ZAPS6
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,   2, {NULL}, 0, 0, S_ZAPS8 }, // S_ZAPS7
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,   2, {NULL}, 0, 0, S_ZAPS9 }, // S_ZAPS8
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,   2, {NULL}, 0, 0, S_ZAPS10}, // S_ZAPS9
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS11}, // S_ZAPS10
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS12}, // S_ZAPS11
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS13}, // S_ZAPS12
-	{SPR_NULL,                           0, 9*2, {NULL}, 0, 0, S_ZAPS14}, // S_ZAPS13
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS15}, // S_ZAPS14
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS16}, // S_ZAPS15
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS1 }, // S_ZAPS16
-
-	{SPR_NULL,                           0, 12*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB1
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,    2, {NULL}, 0, 0, S_ZAPSB3 }, // S_ZAPSB2
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,    2, {NULL}, 0, 0, S_ZAPSB4 }, // S_ZAPSB3
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,    2, {NULL}, 0, 0, S_ZAPSB5 }, // S_ZAPSB4
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,    2, {NULL}, 0, 0, S_ZAPSB6 }, // S_ZAPSB5
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,    2, {NULL}, 0, 0, S_ZAPSB7 }, // S_ZAPSB6
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,    2, {NULL}, 0, 0, S_ZAPSB8 }, // S_ZAPSB7
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,    2, {NULL}, 0, 0, S_ZAPSB9 }, // S_ZAPSB8
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,    2, {NULL}, 0, 0, S_ZAPSB10}, // S_ZAPSB9
-	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,    2, {NULL}, 0, 0, S_ZAPSB11}, // S_ZAPSB10
-	{SPR_NULL,                           0, 15*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB11
+	{SPR_ARMA, FF_TRANS40   , 2, {NULL}, 0, 0, S_ARMA2 , 0}, // S_ARMA1
+	{SPR_ARMA, FF_TRANS40| 1, 2, {NULL}, 0, 0, S_ARMA3 , 0}, // S_ARMA2
+	{SPR_ARMA, FF_TRANS40| 2, 2, {NULL}, 0, 0, S_ARMA4 , 0}, // S_ARMA3
+	{SPR_ARMA, FF_TRANS40| 3, 2, {NULL}, 0, 0, S_ARMA5 , 0}, // S_ARMA4
+	{SPR_ARMA, FF_TRANS40| 4, 2, {NULL}, 0, 0, S_ARMA6 , 0}, // S_ARMA5
+	{SPR_ARMA, FF_TRANS40| 5, 2, {NULL}, 0, 0, S_ARMA7 , 0}, // S_ARMA6
+	{SPR_ARMA, FF_TRANS40| 6, 2, {NULL}, 0, 0, S_ARMA8 , 0}, // S_ARMA7
+	{SPR_ARMA, FF_TRANS40| 7, 2, {NULL}, 0, 0, S_ARMA9 , 0}, // S_ARMA8
+	{SPR_ARMA, FF_TRANS40| 8, 2, {NULL}, 0, 0, S_ARMA10, 0}, // S_ARMA9
+	{SPR_ARMA, FF_TRANS40| 9, 2, {NULL}, 0, 0, S_ARMA11, 0}, // S_ARMA10
+	{SPR_ARMA, FF_TRANS40|10, 2, {NULL}, 0, 0, S_ARMA12, 0}, // S_ARMA11
+	{SPR_ARMA, FF_TRANS40|11, 2, {NULL}, 0, 0, S_ARMA13, 0}, // S_ARMA12
+	{SPR_ARMA, FF_TRANS40|12, 2, {NULL}, 0, 0, S_ARMA14, 0}, // S_ARMA13
+	{SPR_ARMA, FF_TRANS40|13, 2, {NULL}, 0, 0, S_ARMA15, 0}, // S_ARMA14
+	{SPR_ARMA, FF_TRANS40|14, 2, {NULL}, 0, 0, S_ARMA16, 0}, // S_ARMA15
+	{SPR_ARMA, FF_TRANS40|15, 2, {NULL}, 0, 0, S_ARMA1 , 0}, // S_ARMA16
+
+	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF2 , 0}, // S_ARMF1
+	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF3 , 0}, // S_ARMF2
+	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF4 , 0}, // S_ARMF3
+	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF5 , 0}, // S_ARMF4
+	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF6 , 0}, // S_ARMF5
+	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF7 , 0}, // S_ARMF6
+	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF8 , 0}, // S_ARMF7
+	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF9 , 0}, // S_ARMF8
+	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF10, 0}, // S_ARMF9
+	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF11, 0}, // S_ARMF10
+	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF12, 0}, // S_ARMF11
+	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF13, 0}, // S_ARMF12
+	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF14, 0}, // S_ARMF13
+	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF15, 0}, // S_ARMF14
+	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF16, 0}, // S_ARMF15
+	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF17, 0}, // S_ARMF16
+	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 0, 0, S_ARMF18, 0}, // S_ARMF17
+	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF19, 0}, // S_ARMF18
+	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF20, 0}, // S_ARMF19
+	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF21, 0}, // S_ARMF20
+	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF22, 0}, // S_ARMF21
+	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF23, 0}, // S_ARMF22
+	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF24, 0}, // S_ARMF23
+	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF25, 0}, // S_ARMF24
+	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF26, 0}, // S_ARMF25
+	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF27, 0}, // S_ARMF26
+	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF28, 0}, // S_ARMF27
+	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF29, 0}, // S_ARMF28
+	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF30, 0}, // S_ARMF29
+	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF31, 0}, // S_ARMF30
+	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF32, 0}, // S_ARMF31
+	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF1 , 0}, // S_ARMF32
+
+	{SPR_ARMB, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB2 , 0}, // S_ARMB1
+	{SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB3 , 0}, // S_ARMB2
+	{SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB4 , 0}, // S_ARMB3
+	{SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB5 , 0}, // S_ARMB4
+	{SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB6 , 0}, // S_ARMB5
+	{SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB7 , 0}, // S_ARMB6
+	{SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB8 , 0}, // S_ARMB7
+	{SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB9 , 0}, // S_ARMB8
+	{SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB10, 0}, // S_ARMB9
+	{SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB11, 0}, // S_ARMB10
+	{SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB12, 0}, // S_ARMB11
+	{SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB13, 0}, // S_ARMB12
+	{SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB14, 0}, // S_ARMB13
+	{SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB15, 0}, // S_ARMB14
+	{SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB16, 0}, // S_ARMB15
+	{SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB17, 0}, // S_ARMB16
+	{SPR_ARMF, FF_FULLBRIGHT   , 2, {NULL}, 1, 0, S_ARMB18, 0}, // S_ARMB17
+	{SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB19, 0}, // S_ARMB18
+	{SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB20, 0}, // S_ARMB19
+	{SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB21, 0}, // S_ARMB20
+	{SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB22, 0}, // S_ARMB21
+	{SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB23, 0}, // S_ARMB22
+	{SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB24, 0}, // S_ARMB23
+	{SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB25, 0}, // S_ARMB24
+	{SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB26, 0}, // S_ARMB25
+	{SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB27, 0}, // S_ARMB26
+	{SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB28, 0}, // S_ARMB27
+	{SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB29, 0}, // S_ARMB28
+	{SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB30, 0}, // S_ARMB29
+	{SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB31, 0}, // S_ARMB30
+	{SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB32, 0}, // S_ARMB31
+	{SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB1 , 0}, // S_ARMB32
+
+	{SPR_WIND, FF_TRANS70  , 2, {NULL}, 0, 0, S_WIND2, 0}, // S_WIND1
+	{SPR_WIND, FF_TRANS70|1, 2, {NULL}, 0, 0, S_WIND3, 0}, // S_WIND2
+	{SPR_WIND, FF_TRANS70|2, 2, {NULL}, 0, 0, S_WIND4, 0}, // S_WIND3
+	{SPR_WIND, FF_TRANS70|3, 2, {NULL}, 0, 0, S_WIND5, 0}, // S_WIND4
+	{SPR_WIND, FF_TRANS70|4, 2, {NULL}, 0, 0, S_WIND6, 0}, // S_WIND5
+	{SPR_WIND, FF_TRANS70|5, 2, {NULL}, 0, 0, S_WIND7, 0}, // S_WIND6
+	{SPR_WIND, FF_TRANS70|6, 2, {NULL}, 0, 0, S_WIND8, 0}, // S_WIND7
+	{SPR_WIND, FF_TRANS70|7, 2, {NULL}, 0, 0, S_WIND1, 0}, // S_WIND8
+
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40   , 2, {NULL}, 0, 0, S_MAGN2 , 0}, // S_MAGN1
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 1, 2, {NULL}, 0, 0, S_MAGN3 , 0}, // S_MAGN2
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 2, 2, {NULL}, 0, 0, S_MAGN4 , 0}, // S_MAGN3
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 3, 2, {NULL}, 0, 0, S_MAGN5 , 0}, // S_MAGN4
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 4, 2, {NULL}, 0, 0, S_MAGN6 , 0}, // S_MAGN5
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 5, 2, {NULL}, 0, 0, S_MAGN7 , 0}, // S_MAGN6
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 6, 2, {NULL}, 0, 0, S_MAGN8 , 0}, // S_MAGN7
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 7, 2, {NULL}, 0, 0, S_MAGN9 , 0}, // S_MAGN8
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 8, 2, {NULL}, 0, 0, S_MAGN10, 0}, // S_MAGN9
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_MAGN11, 0}, // S_MAGN10
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_MAGN12, 0}, // S_MAGN11
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_MAGN1 , 0}, // S_MAGN12
+
+	{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS10|12, 2, {NULL}, 0, 0, S_MAGN1 , 0}, // S_MAGN13
+
+	{SPR_FORC, FF_TRANS50  , 3, {NULL}, 0, 0, S_FORC2 , 0}, // S_FORC1
+	{SPR_FORC, FF_TRANS50|1, 3, {NULL}, 0, 0, S_FORC3 , 0}, // S_FORC2
+	{SPR_FORC, FF_TRANS50|2, 3, {NULL}, 0, 0, S_FORC4 , 0}, // S_FORC3
+	{SPR_FORC, FF_TRANS50|3, 3, {NULL}, 0, 0, S_FORC5 , 0}, // S_FORC4
+	{SPR_FORC, FF_TRANS50|4, 3, {NULL}, 0, 0, S_FORC6 , 0}, // S_FORC5
+	{SPR_FORC, FF_TRANS50|5, 3, {NULL}, 0, 0, S_FORC7 , 0}, // S_FORC6
+	{SPR_FORC, FF_TRANS50|6, 3, {NULL}, 0, 0, S_FORC8 , 0}, // S_FORC7
+	{SPR_FORC, FF_TRANS50|7, 3, {NULL}, 0, 0, S_FORC9 , 0}, // S_FORC8
+	{SPR_FORC, FF_TRANS50|8, 3, {NULL}, 0, 0, S_FORC10, 0}, // S_FORC9
+	{SPR_FORC, FF_TRANS50|9, 3, {NULL}, 0, 0, S_FORC1 , 0}, // S_FORC10
+
+	{SPR_FORC, FF_TRANS50|10, 3, {NULL}, 0, 0, S_FORC12, 0}, // S_FORC11
+	{SPR_FORC, FF_TRANS50|11, 3, {NULL}, 0, 0, S_FORC13, 0}, // S_FORC12
+	{SPR_FORC, FF_TRANS50|12, 3, {NULL}, 0, 0, S_FORC14, 0}, // S_FORC13
+	{SPR_FORC, FF_TRANS50|13, 3, {NULL}, 0, 0, S_FORC15, 0}, // S_FORC14
+	{SPR_FORC, FF_TRANS50|14, 3, {NULL}, 0, 0, S_FORC16, 0}, // S_FORC15
+	{SPR_FORC, FF_TRANS50|15, 3, {NULL}, 0, 0, S_FORC17, 0}, // S_FORC16
+	{SPR_FORC, FF_TRANS50|16, 3, {NULL}, 0, 0, S_FORC18, 0}, // S_FORC17
+	{SPR_FORC, FF_TRANS50|17, 3, {NULL}, 0, 0, S_FORC19, 0}, // S_FORC18
+	{SPR_FORC, FF_TRANS50|18, 3, {NULL}, 0, 0, S_FORC20, 0}, // S_FORC19
+	{SPR_FORC, FF_TRANS50|19, 3, {NULL}, 0, 0, S_FORC11, 0}, // S_FORC20
+
+	{SPR_FORC, FF_TRANS50|20, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FORC21
+
+	{SPR_ELEM, FF_TRANS50   , 4, {NULL}, 0, 0, S_ELEM2 , 0}, // S_ELEM1
+	{SPR_ELEM, FF_TRANS50| 1, 4, {NULL}, 0, 0, S_ELEM3 , 0}, // S_ELEM2
+	{SPR_ELEM, FF_TRANS50| 2, 4, {NULL}, 0, 0, S_ELEM4 , 0}, // S_ELEM3
+	{SPR_ELEM, FF_TRANS50| 3, 4, {NULL}, 0, 0, S_ELEM5 , 0}, // S_ELEM4
+	{SPR_ELEM, FF_TRANS50| 4, 4, {NULL}, 0, 0, S_ELEM6 , 0}, // S_ELEM5
+	{SPR_ELEM, FF_TRANS50| 5, 4, {NULL}, 0, 0, S_ELEM7 , 0}, // S_ELEM6
+	{SPR_ELEM, FF_TRANS50| 6, 4, {NULL}, 0, 0, S_ELEM8 , 0}, // S_ELEM7
+	{SPR_ELEM, FF_TRANS50| 7, 4, {NULL}, 0, 0, S_ELEM9 , 0}, // S_ELEM8
+	{SPR_ELEM, FF_TRANS50| 8, 4, {NULL}, 0, 0, S_ELEM10, 0}, // S_ELEM9
+	{SPR_ELEM, FF_TRANS50| 9, 4, {NULL}, 0, 0, S_ELEM11, 0}, // S_ELEM10
+	{SPR_ELEM, FF_TRANS50|10, 4, {NULL}, 0, 0, S_ELEM12, 0}, // S_ELEM11
+	{SPR_ELEM, FF_TRANS50|11, 4, {NULL}, 0, 0, S_ELEM1 , 0}, // S_ELEM12
+
+	{SPR_NULL,             0, 1, {NULL}, 0, 0, S_ELEM14, 0}, // S_ELEM13
+	{SPR_ELEM, FF_TRANS50|11, 1, {NULL}, 0, 0, S_ELEM1 , 0}, // S_ELEM14
+
+	{SPR_ELEM, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ELEMF2 , 0}, // S_ELEMF1
+	{SPR_ELEM, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ELEMF3 , 0}, // S_ELEMF2
+	{SPR_ELEM, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ELEMF4 , 0}, // S_ELEMF3
+	{SPR_ELEM, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ELEMF5 , 0}, // S_ELEMF4
+	{SPR_ELEM, FF_FULLBRIGHT|16, 3, {NULL}, 0, 0, S_ELEMF6 , 0}, // S_ELEMF5
+	{SPR_ELEM, FF_FULLBRIGHT|17, 3, {NULL}, 0, 0, S_ELEMF7 , 0}, // S_ELEMF6
+	{SPR_ELEM, FF_FULLBRIGHT|18, 3, {NULL}, 0, 0, S_ELEMF8 , 0}, // S_ELEMF7
+	{SPR_ELEM, FF_FULLBRIGHT|19, 3, {NULL}, 0, 0, S_ELEMF1 , 0}, // S_ELEMF8
+
+	{SPR_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10, 0}, // S_ELEMF9
+	{SPR_NULL, 0,                1, {NULL}, 0, 0, S_ELEMF1 , 0}, // S_ELEMF10
+
+	{SPR_PITY, FF_TRANS30   , 2, {NULL}, 0, 0, S_PITY2, 0},  // S_PITY1
+	{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3, 0},  // S_PITY2
+	{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4, 0},  // S_PITY3
+	{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5, 0},  // S_PITY4
+	{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6, 0},  // S_PITY5
+	{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7, 0},  // S_PITY6
+	{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8, 0},  // S_PITY7
+	{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9, 0},  // S_PITY8
+	{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10, 0}, // S_PITY9
+	{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11, 0}, // S_PITY10
+	{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12, 0}, // S_PITY11
+	{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1, 0},  // S_PITY12
+
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40  , 2, {NULL}, 0, 0, S_FIRS2, 0}, // S_FIRS1
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3, 0}, // S_FIRS2
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|2, 2, {NULL}, 0, 0, S_FIRS4, 0}, // S_FIRS3
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|3, 2, {NULL}, 0, 0, S_FIRS5, 0}, // S_FIRS4
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|4, 2, {NULL}, 0, 0, S_FIRS6, 0}, // S_FIRS5
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|5, 2, {NULL}, 0, 0, S_FIRS7, 0}, // S_FIRS6
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|6, 2, {NULL}, 0, 0, S_FIRS8, 0}, // S_FIRS7
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|7, 2, {NULL}, 0, 0, S_FIRS9, 0}, // S_FIRS8
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|8, 2, {NULL}, 0, 0, S_FIRS1, 0}, // S_FIRS9
+
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|18, 1, {NULL}, 0, 0, S_FIRS11, 0}, // S_FIRS10
+	{SPR_NULL, 0,                           1, {NULL}, 0, 0, S_FIRS1 , 0}, // S_FIRS11
+
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_FIRSB2, 0}, // S_FIRSB1
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_FIRSB3, 0}, // S_FIRSB2
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_FIRSB4, 0}, // S_FIRSB3
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|12, 2, {NULL}, 0, 0, S_FIRSB5, 0}, // S_FIRSB4
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|13, 2, {NULL}, 0, 0, S_FIRSB6, 0}, // S_FIRSB5
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|14, 2, {NULL}, 0, 0, S_FIRSB7, 0}, // S_FIRSB6
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|15, 2, {NULL}, 0, 0, S_FIRSB8, 0}, // S_FIRSB7
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|16, 2, {NULL}, 0, 0, S_FIRSB9, 0}, // S_FIRSB8
+	{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|17, 2, {NULL}, 0, 0, S_FIRSB1, 0}, // S_FIRSB9
+
+	{SPR_NULL, 0,                           2, {NULL}, 0, 0, S_FIRSB1 , 0}, // S_FIRSB10
+
+	{SPR_BUBS, FF_TRANS30  , 3, {NULL}, 0, 0, S_BUBS2, 0}, // S_BUBS1
+	{SPR_BUBS, FF_TRANS30|1, 3, {NULL}, 0, 0, S_BUBS3, 0}, // S_BUBS2
+	{SPR_BUBS, FF_TRANS30|2, 3, {NULL}, 0, 0, S_BUBS4, 0}, // S_BUBS3
+	{SPR_BUBS, FF_TRANS30|3, 3, {NULL}, 0, 0, S_BUBS5, 0}, // S_BUBS4
+	{SPR_BUBS, FF_TRANS30|4, 3, {NULL}, 0, 0, S_BUBS6, 0}, // S_BUBS5
+	{SPR_BUBS, FF_TRANS30|5, 3, {NULL}, 0, 0, S_BUBS7, 0}, // S_BUBS6
+	{SPR_BUBS, FF_TRANS30|6, 3, {NULL}, 0, 0, S_BUBS8, 0}, // S_BUBS7
+	{SPR_BUBS, FF_TRANS30|7, 3, {NULL}, 0, 0, S_BUBS9, 0}, // S_BUBS8
+	{SPR_BUBS, FF_TRANS30|8, 3, {NULL}, 0, 0, S_BUBS1, 0}, // S_BUBS9
+
+	{SPR_NULL, 0,   3, {NULL}, 0, 0, S_BUBS1, 0}, // S_BUBS10
+	{SPR_NULL, 0, 4*3, {NULL}, 0, 0, S_BUBS1, 0}, // S_BUBS11
+
+	{SPR_BUBS, FF_TRANS30| 9, 3, {NULL}, 0, 0, S_BUBSB2, 0}, // S_BUBSB1
+	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB3, 0}, // S_BUBSB2
+	{SPR_BUBS, FF_TRANS30|11, 3, {NULL}, 0, 0, S_BUBSB4, 0}, // S_BUBSB3
+	{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB1, 0}, // S_BUBSB4
+
+	{SPR_BUBS, FF_TRANS30|12, 3, {NULL}, 0, 0, S_BUBSB3, 0}, // S_BUBSB5
+	{SPR_BUBS, FF_TRANS30|13, 3, {NULL}, 0, 0, S_BUBSB5, 0}, // S_BUBSB6
+
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,   2, {NULL}, 0, 0, S_ZAPS2 , 0}, // S_ZAPS1
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,   2, {NULL}, 0, 0, S_ZAPS3 , 0}, // S_ZAPS2
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,   2, {NULL}, 0, 0, S_ZAPS4 , 0}, // S_ZAPS3
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,   2, {NULL}, 0, 0, S_ZAPS5 , 0}, // S_ZAPS4
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,   2, {NULL}, 0, 0, S_ZAPS6 , 0}, // S_ZAPS5
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,   2, {NULL}, 0, 0, S_ZAPS7 , 0}, // S_ZAPS6
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,   2, {NULL}, 0, 0, S_ZAPS8 , 0}, // S_ZAPS7
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,   2, {NULL}, 0, 0, S_ZAPS9 , 0}, // S_ZAPS8
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,   2, {NULL}, 0, 0, S_ZAPS10, 0}, // S_ZAPS9
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS11, 0}, // S_ZAPS10
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS12, 0}, // S_ZAPS11
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS13, 0}, // S_ZAPS12
+	{SPR_NULL,                           0, 9*2, {NULL}, 0, 0, S_ZAPS14, 0}, // S_ZAPS13
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9,   2, {NULL}, 0, 0, S_ZAPS15, 0}, // S_ZAPS14
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10,   2, {NULL}, 0, 0, S_ZAPS16, 0}, // S_ZAPS15
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11,   2, {NULL}, 0, 0, S_ZAPS1 , 0}, // S_ZAPS16
+
+	{SPR_NULL,                           0, 12*2, {NULL}, 0, 0, S_ZAPSB2 , 0}, // S_ZAPSB1
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8,    2, {NULL}, 0, 0, S_ZAPSB3 , 0}, // S_ZAPSB2
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7,    2, {NULL}, 0, 0, S_ZAPSB4 , 0}, // S_ZAPSB3
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6,    2, {NULL}, 0, 0, S_ZAPSB5 , 0}, // S_ZAPSB4
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5,    2, {NULL}, 0, 0, S_ZAPSB6 , 0}, // S_ZAPSB5
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4,    2, {NULL}, 0, 0, S_ZAPSB7 , 0}, // S_ZAPSB6
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3,    2, {NULL}, 0, 0, S_ZAPSB8 , 0}, // S_ZAPSB7
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2,    2, {NULL}, 0, 0, S_ZAPSB9 , 0}, // S_ZAPSB8
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1,    2, {NULL}, 0, 0, S_ZAPSB10, 0}, // S_ZAPSB9
+	{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20   ,    2, {NULL}, 0, 0, S_ZAPSB11, 0}, // S_ZAPSB10
+	{SPR_NULL,                           0, 15*2, {NULL}, 0, 0, S_ZAPSB2 , 0}, // S_ZAPSB11
 
 	// Thunder spark
-	{SPR_SSPK, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL},   // S_THUNDERCOIN_SPARK
+	{SPR_SSPK, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL, 0},   // S_THUNDERCOIN_SPARK
 
 	// Invincibility Sparkles
-	{SPR_IVSP, FF_ANIMATE|FF_FULLBRIGHT, 32, {NULL}, 31, 1, S_NULL},   // S_IVSP
+	{SPR_IVSP, FF_ANIMATE|FF_FULLBRIGHT, 32, {NULL}, 31, 1, S_NULL, 0},   // S_IVSP
 
 	// Super Sonic Spark
-	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1
-	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK3}, // S_SSPK2
-	{SPR_SSPK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK4}, // S_SSPK3
-	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK5}, // S_SSPK4
-	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL},  // S_SSPK5
+	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2, 0}, // S_SSPK1
+	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK3, 0}, // S_SSPK2
+	{SPR_SSPK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK4, 0}, // S_SSPK3
+	{SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK5, 0}, // S_SSPK4
+	{SPR_SSPK,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0},  // S_SSPK5
 
 	// Flicky-sized bubble
-	{SPR_FBUB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FLICKY_BUBBLE
+	{SPR_FBUB, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FLICKY_BUBBLE
 
 	// Bluebird
-	{SPR_FL01, 0, 2, {A_FlickyCheck}, S_FLICKY_01_FLAP1, S_FLICKY_01_FLAP1, S_FLICKY_01_OUT},   // S_FLICKY_01_OUT
-	{SPR_FL01, 1, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP2}, // S_FLICKY_01_FLAP1
-	{SPR_FL01, 2, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP3}, // S_FLICKY_01_FLAP2
-	{SPR_FL01, 3, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP1}, // S_FLICKY_01_FLAP3
-	{SPR_FL01, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL},                                         // S_FLICKY_01_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_01, 384*FRACUNIT, S_FLICKY_01_CENTER},        // S_FLICKY_01_CENTER
+	{SPR_FL01, 0, 2, {A_FlickyCheck}, S_FLICKY_01_FLAP1, S_FLICKY_01_FLAP1, S_FLICKY_01_OUT, 0},   // S_FLICKY_01_OUT
+	{SPR_FL01, 1, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP2, 0}, // S_FLICKY_01_FLAP1
+	{SPR_FL01, 2, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP3, 0}, // S_FLICKY_01_FLAP2
+	{SPR_FL01, 3, 3, {A_FlickyFly},          4*FRACUNIT,       16*FRACUNIT, S_FLICKY_01_FLAP1, 0}, // S_FLICKY_01_FLAP3
+	{SPR_FL01, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL, 0},                                         // S_FLICKY_01_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_01, 384*FRACUNIT, S_FLICKY_01_CENTER, 0},        // S_FLICKY_01_CENTER
 
 	// Rabbit
-	{SPR_FL02, 0, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_OUT},  // S_FLICKY_02_OUT
-	{SPR_FL02, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_02_HOP},  // S_FLICKY_02_AIM
-	{SPR_FL02, 1, 1, {A_FlickyHop},        6*FRACUNIT,       4*FRACUNIT, S_FLICKY_02_UP},   // S_FLICKY_02_HOP
-	{SPR_FL02, 2, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, S_FLICKY_02_DOWN, S_FLICKY_02_UP},   // S_FLICKY_02_UP
-	{SPR_FL02, 3, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_DOWN}, // S_FLICKY_02_DOWN
-	{SPR_FL02, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_02_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_02, 384*FRACUNIT, S_FLICKY_02_CENTER},        // S_FLICKY_02_CENTER
+	{SPR_FL02, 0, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_OUT, 0},  // S_FLICKY_02_OUT
+	{SPR_FL02, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_02_HOP, 0},  // S_FLICKY_02_AIM
+	{SPR_FL02, 1, 1, {A_FlickyHop},        6*FRACUNIT,       4*FRACUNIT, S_FLICKY_02_UP, 0},   // S_FLICKY_02_HOP
+	{SPR_FL02, 2, 2, {A_FlickyCheck}, S_FLICKY_02_AIM, S_FLICKY_02_DOWN, S_FLICKY_02_UP, 0},   // S_FLICKY_02_UP
+	{SPR_FL02, 3, 2, {A_FlickyCheck}, S_FLICKY_02_AIM,                0, S_FLICKY_02_DOWN, 0}, // S_FLICKY_02_DOWN
+	{SPR_FL02, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_02_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_02, 384*FRACUNIT, S_FLICKY_02_CENTER, 0},        // S_FLICKY_02_CENTER
 
 	// Chicken
-	{SPR_FL03, 0, 2, {A_FlickyCheck},   S_FLICKY_03_AIM, S_FLICKY_03_FLAP1, S_FLICKY_03_OUT},   // S_FLICKY_03_OUT
-	{SPR_FL03, 1, 1, {A_FlickyAim},            ANGLE_45,       32*FRACUNIT, S_FLICKY_03_HOP},   // S_FLICKY_03_AIM
-	{SPR_FL03, 1, 1, {A_FlickyHop},          7*FRACUNIT,        2*FRACUNIT, S_FLICKY_03_UP},    // S_FLICKY_03_HOP
-	{SPR_FL03, 2, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, S_FLICKY_03_FLAP1, S_FLICKY_03_UP},    // S_FLICKY_03_UP
-	{SPR_FL03, 3, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP2}, // S_FLICKY_03_FLAP1
-	{SPR_FL03, 4, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP1}, // S_FLICKY_03_FLAP2
-	{SPR_FL03, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_03_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_03, 384*FRACUNIT, S_FLICKY_03_CENTER},        // S_FLICKY_03_CENTER
+	{SPR_FL03, 0, 2, {A_FlickyCheck},   S_FLICKY_03_AIM, S_FLICKY_03_FLAP1, S_FLICKY_03_OUT, 0},   // S_FLICKY_03_OUT
+	{SPR_FL03, 1, 1, {A_FlickyAim},            ANGLE_45,       32*FRACUNIT, S_FLICKY_03_HOP, 0},   // S_FLICKY_03_AIM
+	{SPR_FL03, 1, 1, {A_FlickyHop},          7*FRACUNIT,        2*FRACUNIT, S_FLICKY_03_UP, 0},    // S_FLICKY_03_HOP
+	{SPR_FL03, 2, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP, S_FLICKY_03_FLAP1, S_FLICKY_03_UP, 0},    // S_FLICKY_03_UP
+	{SPR_FL03, 3, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP2, 0}, // S_FLICKY_03_FLAP1
+	{SPR_FL03, 4, 2, {A_FlickyFlutter}, S_FLICKY_03_HOP,                 0, S_FLICKY_03_FLAP1, 0}, // S_FLICKY_03_FLAP2
+	{SPR_FL03, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_03_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_03, 384*FRACUNIT, S_FLICKY_03_CENTER, 0},        // S_FLICKY_03_CENTER
 
 	// Seal
-	{SPR_FL04, 0, 2, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_OUT},   // S_FLICKY_04_OUT
-	{SPR_FL04, 1, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_04_HOP},   // S_FLICKY_04_AIM
-	{SPR_FL04, 1, 1, {A_FlickyHop},        3*FRACUNIT,        2*FRACUNIT, S_FLICKY_04_UP},    // S_FLICKY_04_HOP
-	{SPR_FL04, 2, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,  S_FLICKY_04_DOWN, S_FLICKY_04_UP},    // S_FLICKY_04_UP
-	{SPR_FL04, 3, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_DOWN},  // S_FLICKY_04_DOWN
-	{SPR_FL04, 3, 4, {A_FlickyFly},        2*FRACUNIT,       48*FRACUNIT, S_FLICKY_04_SWIM2}, // S_FLICKY_04_SWIM1
-	{SPR_FL04, 4, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM3}, // S_FLICKY_04_SWIM2
-	{SPR_FL04, 3, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM4}, // S_FLICKY_04_SWIM3
-	{SPR_FL04, 5, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM1}, // S_FLICKY_04_SWIM4
-	{SPR_FL04, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_04_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_04, 384*FRACUNIT, S_FLICKY_04_CENTER},        // S_FLICKY_04_CENTER
+	{SPR_FL04, 0, 2, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_OUT, 0},   // S_FLICKY_04_OUT
+	{SPR_FL04, 1, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_04_HOP, 0},   // S_FLICKY_04_AIM
+	{SPR_FL04, 1, 1, {A_FlickyHop},        3*FRACUNIT,        2*FRACUNIT, S_FLICKY_04_UP, 0},    // S_FLICKY_04_HOP
+	{SPR_FL04, 2, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,  S_FLICKY_04_DOWN, S_FLICKY_04_UP, 0},    // S_FLICKY_04_UP
+	{SPR_FL04, 3, 4, {A_FlickyCheck}, S_FLICKY_04_AIM,                 0, S_FLICKY_04_DOWN, 0},  // S_FLICKY_04_DOWN
+	{SPR_FL04, 3, 4, {A_FlickyFly},        2*FRACUNIT,       48*FRACUNIT, S_FLICKY_04_SWIM2, 0}, // S_FLICKY_04_SWIM1
+	{SPR_FL04, 4, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM3, 0}, // S_FLICKY_04_SWIM2
+	{SPR_FL04, 3, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM4, 0}, // S_FLICKY_04_SWIM3
+	{SPR_FL04, 5, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_04_SWIM1, S_FLICKY_04_SWIM1, 0}, // S_FLICKY_04_SWIM4
+	{SPR_FL04, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_04_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_04, 384*FRACUNIT, S_FLICKY_04_CENTER, 0},        // S_FLICKY_04_CENTER
 
 	// Pig
-	{SPR_FL05, 0, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_OUT},  // S_FLICKY_05_OUT
-	{SPR_FL05, 1, 1, {A_FlickyAim},             ANG20,      32*FRACUNIT, S_FLICKY_05_HOP},  // S_FLICKY_05_AIM
-	{SPR_FL05, 1, 1, {A_FlickyHop},        4*FRACUNIT,       3*FRACUNIT, S_FLICKY_05_UP},   // S_FLICKY_05_HOP
-	{SPR_FL05, 2, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, S_FLICKY_05_DOWN, S_FLICKY_05_UP},   // S_FLICKY_05_UP
-	{SPR_FL05, 3, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_DOWN}, // S_FLICKY_05_DOWN
-	{SPR_FL05, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_05_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_05, 384*FRACUNIT, S_FLICKY_05_CENTER},        // S_FLICKY_05_CENTER
+	{SPR_FL05, 0, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_OUT, 0},  // S_FLICKY_05_OUT
+	{SPR_FL05, 1, 1, {A_FlickyAim},             ANG20,      32*FRACUNIT, S_FLICKY_05_HOP, 0},  // S_FLICKY_05_AIM
+	{SPR_FL05, 1, 1, {A_FlickyHop},        4*FRACUNIT,       3*FRACUNIT, S_FLICKY_05_UP, 0},   // S_FLICKY_05_HOP
+	{SPR_FL05, 2, 2, {A_FlickyCheck}, S_FLICKY_05_AIM, S_FLICKY_05_DOWN, S_FLICKY_05_UP, 0},   // S_FLICKY_05_UP
+	{SPR_FL05, 3, 2, {A_FlickyCheck}, S_FLICKY_05_AIM,                0, S_FLICKY_05_DOWN, 0}, // S_FLICKY_05_DOWN
+	{SPR_FL05, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_05_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_05, 384*FRACUNIT, S_FLICKY_05_CENTER, 0},        // S_FLICKY_05_CENTER
 
 	// Chipmunk
-	{SPR_FL06, 0, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_OUT},  // S_FLICKY_06_OUT
-	{SPR_FL06, 1, 1, {A_FlickyAim},          ANGLE_90,      32*FRACUNIT, S_FLICKY_06_HOP},  // S_FLICKY_06_AIM
-	{SPR_FL06, 1, 1, {A_FlickyHop},        5*FRACUNIT,       6*FRACUNIT, S_FLICKY_06_UP},   // S_FLICKY_06_HOP
-	{SPR_FL06, 2, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, S_FLICKY_06_DOWN, S_FLICKY_06_UP},   // S_FLICKY_06_UP
-	{SPR_FL06, 3, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_DOWN}, // S_FLICKY_06_DOWN
-	{SPR_FL06, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_06_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_06, 384*FRACUNIT, S_FLICKY_06_CENTER},        // S_FLICKY_06_CENTER
+	{SPR_FL06, 0, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_OUT, 0},  // S_FLICKY_06_OUT
+	{SPR_FL06, 1, 1, {A_FlickyAim},          ANGLE_90,      32*FRACUNIT, S_FLICKY_06_HOP, 0},  // S_FLICKY_06_AIM
+	{SPR_FL06, 1, 1, {A_FlickyHop},        5*FRACUNIT,       6*FRACUNIT, S_FLICKY_06_UP, 0},   // S_FLICKY_06_HOP
+	{SPR_FL06, 2, 2, {A_FlickyCheck}, S_FLICKY_06_AIM, S_FLICKY_06_DOWN, S_FLICKY_06_UP, 0},   // S_FLICKY_06_UP
+	{SPR_FL06, 3, 2, {A_FlickyCheck}, S_FLICKY_06_AIM,                0, S_FLICKY_06_DOWN, 0}, // S_FLICKY_06_DOWN
+	{SPR_FL06, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_06_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_06, 384*FRACUNIT, S_FLICKY_06_CENTER, 0},        // S_FLICKY_06_CENTER
 
 	// Penguin
-	{SPR_FL07, 0, 2, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_OUT},   // S_FLICKY_07_OUT
-	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPL},  // S_FLICKY_07_AIML
-	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPL},   // S_FLICKY_07_HOPL
-	{SPR_FL07, 2, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR, S_FLICKY_07_DOWNL, S_FLICKY_07_UPL},   // S_FLICKY_07_UPL
-	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR,                 0, S_FLICKY_07_DOWNL}, // S_FLICKY_07_DOWNL
-	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPR},  // S_FLICKY_07_AIMR
-	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPR},   // S_FLICKY_07_HOPR
-	{SPR_FL07, 3, 4, {A_FlickyCheck}, S_FLICKY_07_AIML, S_FLICKY_07_DOWNR, S_FLICKY_07_UPR},   // S_FLICKY_07_UPR
-	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_DOWNR}, // S_FLICKY_07_DOWNR
-	{SPR_FL07, 4, 4, {A_FlickyFly},         3*FRACUNIT,       72*FRACUNIT, S_FLICKY_07_SWIM2}, // S_FLICKY_07_SWIM1
-	{SPR_FL07, 5, 4, {A_FlickyCoast},         FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3}, // S_FLICKY_07_SWIM2
-	{SPR_FL07, 6, 4, {A_FlickyCoast},       2*FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3}, // S_FLICKY_07_SWIM3
-	{SPR_FL07, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_07_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_07, 384*FRACUNIT, S_FLICKY_07_CENTER},        // S_FLICKY_07_CENTER
+	{SPR_FL07, 0, 2, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_OUT, 0},   // S_FLICKY_07_OUT
+	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPL, 0},  // S_FLICKY_07_AIML
+	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPL, 0},   // S_FLICKY_07_HOPL
+	{SPR_FL07, 2, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR, S_FLICKY_07_DOWNL, S_FLICKY_07_UPL, 0},   // S_FLICKY_07_UPL
+	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIMR,                 0, S_FLICKY_07_DOWNL, 0}, // S_FLICKY_07_DOWNL
+	{SPR_FL07, 1, 1, {A_FlickyAim},              ANG30,       32*FRACUNIT, S_FLICKY_07_HOPR, 0},  // S_FLICKY_07_AIMR
+	{SPR_FL07, 1, 1, {A_FlickyHop},         4*FRACUNIT,        2*FRACUNIT, S_FLICKY_07_UPR, 0},   // S_FLICKY_07_HOPR
+	{SPR_FL07, 3, 4, {A_FlickyCheck}, S_FLICKY_07_AIML, S_FLICKY_07_DOWNR, S_FLICKY_07_UPR, 0},   // S_FLICKY_07_UPR
+	{SPR_FL07, 1, 4, {A_FlickyCheck}, S_FLICKY_07_AIML,                 0, S_FLICKY_07_DOWNR, 0}, // S_FLICKY_07_DOWNR
+	{SPR_FL07, 4, 4, {A_FlickyFly},         3*FRACUNIT,       72*FRACUNIT, S_FLICKY_07_SWIM2, 0}, // S_FLICKY_07_SWIM1
+	{SPR_FL07, 5, 4, {A_FlickyCoast},         FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3, 0}, // S_FLICKY_07_SWIM2
+	{SPR_FL07, 6, 4, {A_FlickyCoast},       2*FRACUNIT, S_FLICKY_07_SWIM1, S_FLICKY_07_SWIM3, 0}, // S_FLICKY_07_SWIM3
+	{SPR_FL07, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_07_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_07, 384*FRACUNIT, S_FLICKY_07_CENTER, 0},        // S_FLICKY_07_CENTER
 
 	// Fish
-	{SPR_FL08, 0, 2, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_OUT},   // S_FLICKY_08_OUT
-	{SPR_FL08, 2, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_08_HOP},   // S_FLICKY_08_AIM
-	{SPR_FL08, 2, 1, {A_FlickyFlounder},   2*FRACUNIT,        1*FRACUNIT, S_FLICKY_08_FLAP1}, // S_FLICKY_08_HOP
-	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP2}, // S_FLICKY_08_FLAP1
-	{SPR_FL08, 1, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP3}, // S_FLICKY_08_FLAP2
-	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP4}, // S_FLICKY_08_FLAP3
-	{SPR_FL08, 2, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP1}, // S_FLICKY_08_FLAP4
-	{SPR_FL08, 0, 4, {A_FlickyFly},        3*FRACUNIT,       64*FRACUNIT, S_FLICKY_08_SWIM2}, // S_FLICKY_08_SWIM1
-	{SPR_FL08, 1, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM3}, // S_FLICKY_08_SWIM2
-	{SPR_FL08, 0, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4}, // S_FLICKY_08_SWIM3
-	{SPR_FL08, 2, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4}, // S_FLICKY_08_SWIM4
-	{SPR_FL08, FF_ANIMATE, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_08_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_08, 384*FRACUNIT, S_FLICKY_08_CENTER},        // S_FLICKY_08_CENTER
+	{SPR_FL08, 0, 2, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_OUT, 0},   // S_FLICKY_08_OUT
+	{SPR_FL08, 2, 1, {A_FlickyAim},             ANG30,       32*FRACUNIT, S_FLICKY_08_HOP, 0},   // S_FLICKY_08_AIM
+	{SPR_FL08, 2, 1, {A_FlickyFlounder},   2*FRACUNIT,        1*FRACUNIT, S_FLICKY_08_FLAP1, 0}, // S_FLICKY_08_HOP
+	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP2, 0}, // S_FLICKY_08_FLAP1
+	{SPR_FL08, 1, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP3, 0}, // S_FLICKY_08_FLAP2
+	{SPR_FL08, 0, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP4, 0}, // S_FLICKY_08_FLAP3
+	{SPR_FL08, 2, 4, {A_FlickyCheck}, S_FLICKY_08_AIM,                 0, S_FLICKY_08_FLAP1, 0}, // S_FLICKY_08_FLAP4
+	{SPR_FL08, 0, 4, {A_FlickyFly},        3*FRACUNIT,       64*FRACUNIT, S_FLICKY_08_SWIM2, 0}, // S_FLICKY_08_SWIM1
+	{SPR_FL08, 1, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM3, 0}, // S_FLICKY_08_SWIM2
+	{SPR_FL08, 0, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4, 0}, // S_FLICKY_08_SWIM3
+	{SPR_FL08, 2, 4, {A_FlickyCoast},        FRACUNIT, S_FLICKY_08_SWIM1, S_FLICKY_08_SWIM4, 0}, // S_FLICKY_08_SWIM4
+	{SPR_FL08, FF_ANIMATE, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_08_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_08, 384*FRACUNIT, S_FLICKY_08_CENTER, 0},        // S_FLICKY_08_CENTER
 
 	// Ram
-	{SPR_FL09, 0, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_OUT},  // S_FLICKY_09_OUT
-	{SPR_FL09, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_09_HOP},  // S_FLICKY_09_AIM
-	{SPR_FL09, 1, 1, {A_FlickyHop},        7*FRACUNIT,       2*FRACUNIT, S_FLICKY_09_UP},   // S_FLICKY_09_HOP
-	{SPR_FL09, 2, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, S_FLICKY_09_DOWN, S_FLICKY_09_UP},   // S_FLICKY_09_UP
-	{SPR_FL09, 3, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_DOWN}, // S_FLICKY_09_DOWN
-	{SPR_FL09, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_09_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_09, 384*FRACUNIT, S_FLICKY_09_CENTER},        // S_FLICKY_09_CENTER
+	{SPR_FL09, 0, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_OUT, 0},  // S_FLICKY_09_OUT
+	{SPR_FL09, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_09_HOP, 0},  // S_FLICKY_09_AIM
+	{SPR_FL09, 1, 1, {A_FlickyHop},        7*FRACUNIT,       2*FRACUNIT, S_FLICKY_09_UP, 0},   // S_FLICKY_09_HOP
+	{SPR_FL09, 2, 2, {A_FlickyCheck}, S_FLICKY_09_AIM, S_FLICKY_09_DOWN, S_FLICKY_09_UP, 0},   // S_FLICKY_09_UP
+	{SPR_FL09, 3, 2, {A_FlickyCheck}, S_FLICKY_09_AIM,                0, S_FLICKY_09_DOWN, 0}, // S_FLICKY_09_DOWN
+	{SPR_FL09, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_09_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_09, 384*FRACUNIT, S_FLICKY_09_CENTER, 0},        // S_FLICKY_09_CENTER
 
 	// Puffin
-	{SPR_FL10, 0, 2, {A_FlickyCheck}, S_FLICKY_10_FLAP1, S_FLICKY_10_FLAP1, S_FLICKY_10_OUT},   // S_FLICKY_10_OUT
-	{SPR_FL10, 1, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP2}, // S_FLICKY_10_FLAP1
-	{SPR_FL10, 2, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP1}, // S_FLICKY_10_FLAP2
-	{SPR_FL10, FF_ANIMATE|1, -1, {NULL}, 1, 3, S_NULL}, // S_FLICKY_10_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_10, 384*FRACUNIT, S_FLICKY_10_CENTER},        // S_FLICKY_10_CENTER
+	{SPR_FL10, 0, 2, {A_FlickyCheck}, S_FLICKY_10_FLAP1, S_FLICKY_10_FLAP1, S_FLICKY_10_OUT, 0},   // S_FLICKY_10_OUT
+	{SPR_FL10, 1, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP2, 0}, // S_FLICKY_10_FLAP1
+	{SPR_FL10, 2, 3, {A_FlickySoar},         4*FRACUNIT,       16*FRACUNIT, S_FLICKY_10_FLAP1, 0}, // S_FLICKY_10_FLAP2
+	{SPR_FL10, FF_ANIMATE|1, -1, {NULL}, 1, 3, S_NULL, 0}, // S_FLICKY_10_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_10, 384*FRACUNIT, S_FLICKY_10_CENTER, 0},        // S_FLICKY_10_CENTER
 
 	// Cow
-	{SPR_FL11, 0, 2, {A_FlickyCheck}, S_FLICKY_11_AIM,           0, S_FLICKY_11_OUT},  // S_FLICKY_11_OUT
-	{SPR_FL11, 1, 1, {A_FlickyAim},          ANGLE_90, 64*FRACUNIT, S_FLICKY_11_RUN1}, // S_FLICKY_11_AIM
-	{SPR_FL11, 1, 3, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN2}, // S_FLICKY_11_RUN1
-	{SPR_FL11, 2, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN3}, // S_FLICKY_11_RUN2
-	{SPR_FL11, 3, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_AIM},  // S_FLICKY_11_RUN3
-	{SPR_FL11, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_11_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_11, 384*FRACUNIT, S_FLICKY_11_CENTER},        // S_FLICKY_11_CENTER
+	{SPR_FL11, 0, 2, {A_FlickyCheck}, S_FLICKY_11_AIM,           0, S_FLICKY_11_OUT, 0},  // S_FLICKY_11_OUT
+	{SPR_FL11, 1, 1, {A_FlickyAim},          ANGLE_90, 64*FRACUNIT, S_FLICKY_11_RUN1, 0}, // S_FLICKY_11_AIM
+	{SPR_FL11, 1, 3, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN2, 0}, // S_FLICKY_11_RUN1
+	{SPR_FL11, 2, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_RUN3, 0}, // S_FLICKY_11_RUN2
+	{SPR_FL11, 3, 4, {A_FlickyHop},        FRACUNIT/2,  2*FRACUNIT, S_FLICKY_11_AIM, 0},  // S_FLICKY_11_RUN3
+	{SPR_FL11, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_11_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_11, 384*FRACUNIT, S_FLICKY_11_CENTER, 0},        // S_FLICKY_11_CENTER
 
 	// Rat
-	{SPR_FL12, 0, 2, {A_FlickyCheck}, S_FLICKY_12_AIM,           0, S_FLICKY_12_OUT},  // S_FLICKY_12_OUT
-	{SPR_FL12, 1, 1, {A_FlickyAim},          ANGLE_90, 32*FRACUNIT, S_FLICKY_12_RUN1}, // S_FLICKY_12_AIM
-	{SPR_FL12, 1, 2, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN2}, // S_FLICKY_12_RUN1
-	{SPR_FL12, 2, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN3}, // S_FLICKY_12_RUN2
-	{SPR_FL12, 3, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_AIM},  // S_FLICKY_12_RUN3
-	{SPR_FL12, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_12_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_12, 384*FRACUNIT, S_FLICKY_12_CENTER},        // S_FLICKY_12_CENTER
+	{SPR_FL12, 0, 2, {A_FlickyCheck}, S_FLICKY_12_AIM,           0, S_FLICKY_12_OUT, 0},  // S_FLICKY_12_OUT
+	{SPR_FL12, 1, 1, {A_FlickyAim},          ANGLE_90, 32*FRACUNIT, S_FLICKY_12_RUN1, 0}, // S_FLICKY_12_AIM
+	{SPR_FL12, 1, 2, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN2, 0}, // S_FLICKY_12_RUN1
+	{SPR_FL12, 2, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_RUN3, 0}, // S_FLICKY_12_RUN2
+	{SPR_FL12, 3, 3, {A_FlickyHop},                 1, 12*FRACUNIT, S_FLICKY_12_AIM, 0},  // S_FLICKY_12_RUN3
+	{SPR_FL12, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_12_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_12, 384*FRACUNIT, S_FLICKY_12_CENTER, 0},        // S_FLICKY_12_CENTER
 
 	// Bear
-	{SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_OUT},  // S_FLICKY_13_OUT
-	{SPR_FL13, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_13_HOP},  // S_FLICKY_13_AIM
-	{SPR_FL13, 1, 1, {A_FlickyHop},        5*FRACUNIT,       3*FRACUNIT, S_FLICKY_13_UP},   // S_FLICKY_13_HOP
-	{SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP},   // S_FLICKY_13_UP
-	{SPR_FL13, 3, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_DOWN}, // S_FLICKY_13_DOWN
-	{SPR_FL13, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_13_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_13, 384*FRACUNIT, S_FLICKY_13_CENTER},        // S_FLICKY_13_CENTER
+	{SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_OUT, 0},  // S_FLICKY_13_OUT
+	{SPR_FL13, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_13_HOP, 0},  // S_FLICKY_13_AIM
+	{SPR_FL13, 1, 1, {A_FlickyHop},        5*FRACUNIT,       3*FRACUNIT, S_FLICKY_13_UP, 0},   // S_FLICKY_13_HOP
+	{SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP, 0},   // S_FLICKY_13_UP
+	{SPR_FL13, 3, 2, {A_FlickyCheck}, S_FLICKY_13_AIM,                0, S_FLICKY_13_DOWN, 0}, // S_FLICKY_13_DOWN
+	{SPR_FL13, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_13_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_13, 384*FRACUNIT, S_FLICKY_13_CENTER, 0},        // S_FLICKY_13_CENTER
 
 	// Dove
-	{SPR_FL14, 0, 2, {A_FlickyCheck}, S_FLICKY_14_FLAP1, S_FLICKY_14_FLAP1, S_FLICKY_14_OUT},   // S_FLICKY_14_OUT
-	{SPR_FL14, 1, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP2}, // S_FLICKY_14_FLAP1
-	{SPR_FL14, 2, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP3}, // S_FLICKY_14_FLAP2
-	{SPR_FL14, 3, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP1}, // S_FLICKY_14_FLAP3
-	{SPR_FL14, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_14_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_14, 384*FRACUNIT, S_FLICKY_14_CENTER},        // S_FLICKY_14_CENTER
+	{SPR_FL14, 0, 2, {A_FlickyCheck}, S_FLICKY_14_FLAP1, S_FLICKY_14_FLAP1, S_FLICKY_14_OUT, 0},   // S_FLICKY_14_OUT
+	{SPR_FL14, 1, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP2, 0}, // S_FLICKY_14_FLAP1
+	{SPR_FL14, 2, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP3, 0}, // S_FLICKY_14_FLAP2
+	{SPR_FL14, 3, 3, {A_FlickySoar},         4*FRACUNIT,       32*FRACUNIT, S_FLICKY_14_FLAP1, 0}, // S_FLICKY_14_FLAP3
+	{SPR_FL14, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL, 0}, // S_FLICKY_14_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_14, 384*FRACUNIT, S_FLICKY_14_CENTER, 0},        // S_FLICKY_14_CENTER
 
 	// Cat
-	{SPR_FL15, 0, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_OUT},  // S_FLICKY_15_OUT
-	{SPR_FL15, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_15_HOP},  // S_FLICKY_15_AIM
-	{SPR_FL15, 1, 1, {A_FlickyFlounder},   2*FRACUNIT,       6*FRACUNIT, S_FLICKY_15_UP},   // S_FLICKY_15_HOP
-	{SPR_FL15, 2, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, S_FLICKY_15_DOWN, S_FLICKY_15_UP},   // S_FLICKY_15_UP
-	{SPR_FL15, 3, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_DOWN}, // S_FLICKY_15_DOWN
-	{SPR_FL15, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_FLICKY_15_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_15, 384*FRACUNIT, S_FLICKY_15_CENTER},        // S_FLICKY_15_CENTER
+	{SPR_FL15, 0, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_OUT, 0},  // S_FLICKY_15_OUT
+	{SPR_FL15, 1, 1, {A_FlickyAim},             ANG30,      32*FRACUNIT, S_FLICKY_15_HOP, 0},  // S_FLICKY_15_AIM
+	{SPR_FL15, 1, 1, {A_FlickyFlounder},   2*FRACUNIT,       6*FRACUNIT, S_FLICKY_15_UP, 0},   // S_FLICKY_15_HOP
+	{SPR_FL15, 2, 2, {A_FlickyCheck}, S_FLICKY_15_AIM, S_FLICKY_15_DOWN, S_FLICKY_15_UP, 0},   // S_FLICKY_15_UP
+	{SPR_FL15, 3, 2, {A_FlickyCheck}, S_FLICKY_15_AIM,                0, S_FLICKY_15_DOWN, 0}, // S_FLICKY_15_DOWN
+	{SPR_FL15, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_FLICKY_15_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_15, 384*FRACUNIT, S_FLICKY_15_CENTER, 0},        // S_FLICKY_15_CENTER
 
 	// Canary
-	{SPR_FL16, 0, 2, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_OUT},   // S_FLICKY_16_OUT
-	{SPR_FL16, 1, 3, {A_FlickyFly},                4*FRACUNIT, 8*FRACUNIT, S_FLICKY_16_FLAP2}, // S_FLICKY_16_FLAP1
-	{SPR_FL16, 2, 3, {A_SetObjectFlags},         MF_NOGRAVITY,          1, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP2
-	{SPR_FL16, 3, 3, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP3
-	{SPR_FL16, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL}, // S_FLICKY_16_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_16, 384*FRACUNIT, S_FLICKY_16_CENTER},        // S_FLICKY_16_CENTER
+	{SPR_FL16, 0, 2, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_OUT, 0},   // S_FLICKY_16_OUT
+	{SPR_FL16, 1, 3, {A_FlickyFly},                4*FRACUNIT, 8*FRACUNIT, S_FLICKY_16_FLAP2, 0}, // S_FLICKY_16_FLAP1
+	{SPR_FL16, 2, 3, {A_SetObjectFlags},         MF_NOGRAVITY,          1, S_FLICKY_16_FLAP3, 0}, // S_FLICKY_16_FLAP2
+	{SPR_FL16, 3, 3, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1,          0, S_FLICKY_16_FLAP3, 0}, // S_FLICKY_16_FLAP3
+	{SPR_FL16, FF_ANIMATE|1, -1, {NULL}, 2, 3, S_NULL, 0}, // S_FLICKY_16_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_FLICKY_16, 384*FRACUNIT, S_FLICKY_16_CENTER, 0},        // S_FLICKY_16_CENTER
 
 	// Spider
-	{SPR_FS01, 0, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_OUT},  // S_SECRETFLICKY_01_OUT
-	{SPR_FS01, 1, 1, {A_FlickyAim},                   ANG30,            32*FRACUNIT, S_SECRETFLICKY_01_HOP},  // S_SECRETFLICKY_01_AIM
-	{SPR_FS01, 1, 1, {A_FlickyFlounder},         2*FRACUNIT,             6*FRACUNIT, S_SECRETFLICKY_01_UP},   // S_SECRETFLICKY_01_HOP
-	{SPR_FS01, 2, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, S_SECRETFLICKY_01_DOWN, S_SECRETFLICKY_01_UP},   // S_SECRETFLICKY_01_UP
-	{SPR_FS01, 3, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_DOWN}, // S_SECRETFLICKY_01_DOWN
-	{SPR_FS01, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL}, // S_SECRETFLICKY_01_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_01, 384*FRACUNIT, S_SECRETFLICKY_01_CENTER},        // S_SECRETFLICKY_01_CENTER
+	{SPR_FS01, 0, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_OUT, 0},  // S_SECRETFLICKY_01_OUT
+	{SPR_FS01, 1, 1, {A_FlickyAim},                   ANG30,            32*FRACUNIT, S_SECRETFLICKY_01_HOP, 0},  // S_SECRETFLICKY_01_AIM
+	{SPR_FS01, 1, 1, {A_FlickyFlounder},         2*FRACUNIT,             6*FRACUNIT, S_SECRETFLICKY_01_UP, 0},   // S_SECRETFLICKY_01_HOP
+	{SPR_FS01, 2, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, S_SECRETFLICKY_01_DOWN, S_SECRETFLICKY_01_UP, 0},   // S_SECRETFLICKY_01_UP
+	{SPR_FS01, 3, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM,                      0, S_SECRETFLICKY_01_DOWN, 0}, // S_SECRETFLICKY_01_DOWN
+	{SPR_FS01, FF_ANIMATE|1, -1, {NULL}, 2, 4, S_NULL, 0}, // S_SECRETFLICKY_01_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_01, 384*FRACUNIT, S_SECRETFLICKY_01_CENTER, 0},        // S_SECRETFLICKY_01_CENTER
 
 	// Bat
-	{SPR_FS02, 0, 2, {A_FlickyHeightCheck}, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_OUT},   // S_SECRETFLICKY_02_OUT
-	{SPR_FS02, 1, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP2}, // S_SECRETFLICKY_02_FLAP1
-	{SPR_FS02, 2, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP3}, // S_SECRETFLICKY_02_FLAP2
-	{SPR_FS02, 3, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP1}, // S_SECRETFLICKY_02_FLAP3
-	{SPR_FS02, FF_ANIMATE|1, -1, {NULL}, 2, 2, S_NULL}, // S_SECRETFLICKY_02_STAND
-	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_02, 384*FRACUNIT, S_SECRETFLICKY_02_CENTER},        // S_SECRETFLICKY_02_CENTER
+	{SPR_FS02, 0, 2, {A_FlickyHeightCheck}, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_OUT, 0},   // S_SECRETFLICKY_02_OUT
+	{SPR_FS02, 1, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP2, 0}, // S_SECRETFLICKY_02_FLAP1
+	{SPR_FS02, 2, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP3, 0}, // S_SECRETFLICKY_02_FLAP2
+	{SPR_FS02, 3, 3, {A_FlickyFly},                      4*FRACUNIT,             16*FRACUNIT, S_SECRETFLICKY_02_FLAP1, 0}, // S_SECRETFLICKY_02_FLAP3
+	{SPR_FS02, FF_ANIMATE|1, -1, {NULL}, 2, 2, S_NULL, 0}, // S_SECRETFLICKY_02_STAND
+	{SPR_NULL, 0, 15, {A_FlickyCenter}, MT_SECRETFLICKY_02, 384*FRACUNIT, S_SECRETFLICKY_02_CENTER, 0},        // S_SECRETFLICKY_02_CENTER
 
 	// Fan
-	{SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2}, // S_FAN
-	{SPR_FANS, 1, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN3}, // S_FAN2
-	{SPR_FANS, 2, 1, {A_FanBubbleSpawn},  512, 0, S_FAN4}, // S_FAN3
-	{SPR_FANS, 3, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN5}, // S_FAN4
-	{SPR_FANS, 4, 1, {A_FanBubbleSpawn},  512, 0, S_FAN},  // S_FAN5
+	{SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2, 0}, // S_FAN
+	{SPR_FANS, 1, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN3, 0}, // S_FAN2
+	{SPR_FANS, 2, 1, {A_FanBubbleSpawn},  512, 0, S_FAN4, 0}, // S_FAN3
+	{SPR_FANS, 3, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN5, 0}, // S_FAN4
+	{SPR_FANS, 4, 1, {A_FanBubbleSpawn},  512, 0, S_FAN, 0},  // S_FAN5
 
 	// Steam Riser
-	{SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2},   // S_STEAM1
-	{SPR_STEM, 1, 2, {A_UnsetSolidSteam}, 0, 0, S_STEAM3}, // S_STEAM2
-	{SPR_STEM, 2, 2, {NULL}, 0, 0, S_STEAM4},              // S_STEAM3
-	{SPR_STEM, 3, 2, {NULL}, 0, 0, S_STEAM5},              // S_STEAM4
-	{SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6},              // S_STEAM5
-	{SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7},              // S_STEAM6
-	{SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8},              // S_STEAM7
-	{SPR_NULL, 0, 18, {NULL}, 0, 0, S_STEAM1},             // S_STEAM8
+	{SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2, 0},   // S_STEAM1
+	{SPR_STEM, 1, 2, {A_UnsetSolidSteam}, 0, 0, S_STEAM3, 0}, // S_STEAM2
+	{SPR_STEM, 2, 2, {NULL}, 0, 0, S_STEAM4, 0},              // S_STEAM3
+	{SPR_STEM, 3, 2, {NULL}, 0, 0, S_STEAM5, 0},              // S_STEAM4
+	{SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6, 0},              // S_STEAM5
+	{SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7, 0},              // S_STEAM6
+	{SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8, 0},              // S_STEAM7
+	{SPR_NULL, 0, 18, {NULL}, 0, 0, S_STEAM1, 0},             // S_STEAM8
 
 	// Bumpers
-	{SPR_BUMP, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL},   3, 4, S_NULL},   // S_BUMPER
-	{SPR_BUMP, FF_ANIMATE|4,             12, {A_Pain}, 1, 3, S_BUMPER}, //S_BUMPERHIT
+	{SPR_BUMP, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL},   3, 4, S_NULL, 0},   // S_BUMPER
+	{SPR_BUMP, FF_ANIMATE|4,             12, {A_Pain}, 1, 3, S_BUMPER, 0}, //S_BUMPERHIT
 
 	// Balloons
-	{SPR_BLON, FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_BALLOON
-	{SPR_BLON, 3, 0, {A_RemoteDamage},   0, 1, S_BALLOONPOP2}, // S_BALLOONPOP1
-	{SPR_BLON, 3, 1, {A_Pain},           0, 0, S_BALLOONPOP3}, // S_BALLOONPOP2
-	{SPR_BLON, 4, 1, {NULL},             0, 0, S_BALLOONPOP4}, // S_BALLOONPOP3
-	{SPR_NULL, 0, TICRATE, {A_CheckFlags2}, MF2_AMBUSH, S_BALLOONPOP5, S_NULL}, // S_BALLOONPOP4
-	{SPR_NULL, 0, 15*TICRATE, {NULL},    0, 0, S_BALLOONPOP6}, // S_BALLOONPOP5
-	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_NULL},        // S_BALLOONPOP6
+	{SPR_BLON, FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL, 0}, // S_BALLOON
+	{SPR_BLON, 3, 0, {A_RemoteDamage},   0, 1, S_BALLOONPOP2, 0}, // S_BALLOONPOP1
+	{SPR_BLON, 3, 1, {A_Pain},           0, 0, S_BALLOONPOP3, 0}, // S_BALLOONPOP2
+	{SPR_BLON, 4, 1, {NULL},             0, 0, S_BALLOONPOP4, 0}, // S_BALLOONPOP3
+	{SPR_NULL, 0, TICRATE, {A_CheckFlags2}, MF2_AMBUSH, S_BALLOONPOP5, S_NULL, 0}, // S_BALLOONPOP4
+	{SPR_NULL, 0, 15*TICRATE, {NULL},    0, 0, S_BALLOONPOP6, 0}, // S_BALLOONPOP5
+	{SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_NULL, 0},        // S_BALLOONPOP6
 
 	// Yellow Spring
-	{SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL},           // S_YELLOWSPRING
-	{SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3}, // S_YELLOWSPRING2
-	{SPR_SPRY, 3, 1, {NULL}, 0, 0, S_YELLOWSPRING4},   // S_YELLOWSPRING3
-	{SPR_SPRY, 2, 1, {NULL}, 0, 0, S_YELLOWSPRING5},   // S_YELLOWSPRING4
-	{SPR_SPRY, 1, 1, {NULL}, 0, 0, S_YELLOWSPRING},    // S_YELLOWSPRING5
+	{SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL, 0},           // S_YELLOWSPRING
+	{SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3, 0}, // S_YELLOWSPRING2
+	{SPR_SPRY, 3, 1, {NULL}, 0, 0, S_YELLOWSPRING4, 0},   // S_YELLOWSPRING3
+	{SPR_SPRY, 2, 1, {NULL}, 0, 0, S_YELLOWSPRING5, 0},   // S_YELLOWSPRING4
+	{SPR_SPRY, 1, 1, {NULL}, 0, 0, S_YELLOWSPRING, 0},    // S_YELLOWSPRING5
 
 	// Red Spring
-	{SPR_SPRR, 0, -1, {NULL}, 0, 0, S_NULL},        // S_REDSPRING
-	{SPR_SPRR, 4, 4, {A_Pain}, 0, 0, S_REDSPRING3}, // S_REDSPRING2
-	{SPR_SPRR, 3, 1, {NULL}, 0, 0, S_REDSPRING4},   // S_REDSPRING3
-	{SPR_SPRR, 2, 1, {NULL}, 0, 0, S_REDSPRING5},   // S_REDSPRING4
-	{SPR_SPRR, 1, 1, {NULL}, 0, 0, S_REDSPRING},    // S_REDSPRING5
+	{SPR_SPRR, 0, -1, {NULL}, 0, 0, S_NULL, 0},        // S_REDSPRING
+	{SPR_SPRR, 4, 4, {A_Pain}, 0, 0, S_REDSPRING3, 0}, // S_REDSPRING2
+	{SPR_SPRR, 3, 1, {NULL}, 0, 0, S_REDSPRING4, 0},   // S_REDSPRING3
+	{SPR_SPRR, 2, 1, {NULL}, 0, 0, S_REDSPRING5, 0},   // S_REDSPRING4
+	{SPR_SPRR, 1, 1, {NULL}, 0, 0, S_REDSPRING, 0},    // S_REDSPRING5
 
 	// Blue Spring
-	{SPR_SPRB, 0, -1, {NULL}, 0, 0, S_NULL},         // S_BLUESPRING
-	{SPR_SPRB, 4, 4, {A_Pain}, 0, 0, S_BLUESPRING3}, // S_BLUESPRING2
-	{SPR_SPRB, 3, 1, {NULL}, 0, 0, S_BLUESPRING4},   // S_BLUESPRING3
-	{SPR_SPRB, 2, 1, {NULL}, 0, 0, S_BLUESPRING5},   // S_BLUESPRING4
-	{SPR_SPRB, 1, 1, {NULL}, 0, 0, S_BLUESPRING},    // S_BLUESPRING5
+	{SPR_SPRB, 0, -1, {NULL}, 0, 0, S_NULL, 0},         // S_BLUESPRING
+	{SPR_SPRB, 4, 4, {A_Pain}, 0, 0, S_BLUESPRING3, 0}, // S_BLUESPRING2
+	{SPR_SPRB, 3, 1, {NULL}, 0, 0, S_BLUESPRING4, 0},   // S_BLUESPRING3
+	{SPR_SPRB, 2, 1, {NULL}, 0, 0, S_BLUESPRING5, 0},   // S_BLUESPRING4
+	{SPR_SPRB, 1, 1, {NULL}, 0, 0, S_BLUESPRING, 0},    // S_BLUESPRING5
 
 	// Yellow Diagonal Spring
-	{SPR_YSPR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_YDIAG1
-	{SPR_YSPR, 1, 1, {A_Pain}, 0, 0, S_YDIAG3}, // S_YDIAG2
-	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG4},   // S_YDIAG3
-	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG5},   // S_YDIAG4
-	{SPR_YSPR, 4, 1, {NULL}, 0, 0, S_YDIAG6},   // S_YDIAG5
-	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG7},   // S_YDIAG6
-	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG8},   // S_YDIAG7
-	{SPR_YSPR, 1, 1, {NULL}, 0, 0, S_YDIAG1},   // S_YDIAG8
+	{SPR_YSPR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_YDIAG1
+	{SPR_YSPR, 1, 1, {A_Pain}, 0, 0, S_YDIAG3, 0}, // S_YDIAG2
+	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG4, 0},   // S_YDIAG3
+	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG5, 0},   // S_YDIAG4
+	{SPR_YSPR, 4, 1, {NULL}, 0, 0, S_YDIAG6, 0},   // S_YDIAG5
+	{SPR_YSPR, 3, 1, {NULL}, 0, 0, S_YDIAG7, 0},   // S_YDIAG6
+	{SPR_YSPR, 2, 1, {NULL}, 0, 0, S_YDIAG8, 0},   // S_YDIAG7
+	{SPR_YSPR, 1, 1, {NULL}, 0, 0, S_YDIAG1, 0},   // S_YDIAG8
 
 	// Red Diagonal Spring
-	{SPR_RSPR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_RDIAG1
-	{SPR_RSPR, 1, 1, {A_Pain}, 0, 0, S_RDIAG3}, // S_RDIAG2
-	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG4},   // S_RDIAG3
-	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG5},   // S_RDIAG4
-	{SPR_RSPR, 4, 1, {NULL}, 0, 0, S_RDIAG6},   // S_RDIAG5
-	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG7},   // S_RDIAG6
-	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG8},   // S_RDIAG7
-	{SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1},   // S_RDIAG8
+	{SPR_RSPR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_RDIAG1
+	{SPR_RSPR, 1, 1, {A_Pain}, 0, 0, S_RDIAG3, 0}, // S_RDIAG2
+	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG4, 0},   // S_RDIAG3
+	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG5, 0},   // S_RDIAG4
+	{SPR_RSPR, 4, 1, {NULL}, 0, 0, S_RDIAG6, 0},   // S_RDIAG5
+	{SPR_RSPR, 3, 1, {NULL}, 0, 0, S_RDIAG7, 0},   // S_RDIAG6
+	{SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG8, 0},   // S_RDIAG7
+	{SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1, 0},   // S_RDIAG8
 
 	// Blue Diagonal Spring
-	{SPR_BSPR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_BDIAG1
-	{SPR_BSPR, 1, 1, {A_Pain}, 0, 0, S_BDIAG3}, // S_BDIAG2
-	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG4},   // S_BDIAG3
-	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG5},   // S_BDIAG4
-	{SPR_BSPR, 4, 1, {NULL}, 0, 0, S_BDIAG6},   // S_BDIAG5
-	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG7},   // S_BDIAG6
-	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG8},   // S_BDIAG7
-	{SPR_BSPR, 1, 1, {NULL}, 0, 0, S_BDIAG1},   // S_BDIAG8
+	{SPR_BSPR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_BDIAG1
+	{SPR_BSPR, 1, 1, {A_Pain}, 0, 0, S_BDIAG3, 0}, // S_BDIAG2
+	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG4, 0},   // S_BDIAG3
+	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG5, 0},   // S_BDIAG4
+	{SPR_BSPR, 4, 1, {NULL}, 0, 0, S_BDIAG6, 0},   // S_BDIAG5
+	{SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG7, 0},   // S_BDIAG6
+	{SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG8, 0},   // S_BDIAG7
+	{SPR_BSPR, 1, 1, {NULL}, 0, 0, S_BDIAG1, 0},   // S_BDIAG8
 
 	// Yellow Side Spring
-	{SPR_SSWY, 0, -1, {NULL}, 0, 0, S_NULL},    // S_YHORIZ1
-	{SPR_SSWY, 1, 1, {A_Pain}, 0, 0, S_YHORIZ3}, // S_YHORIZ2
-	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ4},   // S_YHORIZ3
-	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ5},   // S_YHORIZ4
-	{SPR_SSWY, 4, 1, {NULL}, 0, 0, S_YHORIZ6},   // S_YHORIZ5
-	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ7},   // S_YHORIZ6
-	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ8},   // S_YHORIZ7
-	{SPR_SSWY, 1, 1, {NULL}, 0, 0, S_YHORIZ1},   // S_YHORIZ8
+	{SPR_SSWY, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_YHORIZ1
+	{SPR_SSWY, 1, 1, {A_Pain}, 0, 0, S_YHORIZ3, 0}, // S_YHORIZ2
+	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ4, 0},   // S_YHORIZ3
+	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ5, 0},   // S_YHORIZ4
+	{SPR_SSWY, 4, 1, {NULL}, 0, 0, S_YHORIZ6, 0},   // S_YHORIZ5
+	{SPR_SSWY, 3, 1, {NULL}, 0, 0, S_YHORIZ7, 0},   // S_YHORIZ6
+	{SPR_SSWY, 2, 1, {NULL}, 0, 0, S_YHORIZ8, 0},   // S_YHORIZ7
+	{SPR_SSWY, 1, 1, {NULL}, 0, 0, S_YHORIZ1, 0},   // S_YHORIZ8
 
 	// Red Side Spring
-	{SPR_SSWR, 0, -1, {NULL}, 0, 0, S_NULL},    // S_RHORIZ1
-	{SPR_SSWR, 1, 1, {A_Pain}, 0, 0, S_RHORIZ3}, // S_RHORIZ2
-	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ4},   // S_RHORIZ3
-	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ5},   // S_RHORIZ4
-	{SPR_SSWR, 4, 1, {NULL}, 0, 0, S_RHORIZ6},   // S_RHORIZ5
-	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ7},   // S_RHORIZ6
-	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ8},   // S_RHORIZ7
-	{SPR_SSWR, 1, 1, {NULL}, 0, 0, S_RHORIZ1},   // S_RHORIZ8
+	{SPR_SSWR, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_RHORIZ1
+	{SPR_SSWR, 1, 1, {A_Pain}, 0, 0, S_RHORIZ3, 0}, // S_RHORIZ2
+	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ4, 0},   // S_RHORIZ3
+	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ5, 0},   // S_RHORIZ4
+	{SPR_SSWR, 4, 1, {NULL}, 0, 0, S_RHORIZ6, 0},   // S_RHORIZ5
+	{SPR_SSWR, 3, 1, {NULL}, 0, 0, S_RHORIZ7, 0},   // S_RHORIZ6
+	{SPR_SSWR, 2, 1, {NULL}, 0, 0, S_RHORIZ8, 0},   // S_RHORIZ7
+	{SPR_SSWR, 1, 1, {NULL}, 0, 0, S_RHORIZ1, 0},   // S_RHORIZ8
 
 	// Blue Side Spring
-	{SPR_SSWB, 0, -1, {NULL}, 0, 0, S_NULL},    // S_BHORIZ1
-	{SPR_SSWB, 1, 1, {A_Pain}, 0, 0, S_BHORIZ3}, // S_BHORIZ2
-	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ4},   // S_BHORIZ3
-	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ5},   // S_BHORIZ4
-	{SPR_SSWB, 4, 1, {NULL}, 0, 0, S_BHORIZ6},   // S_BHORIZ5
-	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ7},   // S_BHORIZ6
-	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ8},   // S_BHORIZ7
-	{SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1},   // S_BHORIZ8
+	{SPR_SSWB, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_BHORIZ1
+	{SPR_SSWB, 1, 1, {A_Pain}, 0, 0, S_BHORIZ3, 0}, // S_BHORIZ2
+	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ4, 0},   // S_BHORIZ3
+	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ5, 0},   // S_BHORIZ4
+	{SPR_SSWB, 4, 1, {NULL}, 0, 0, S_BHORIZ6, 0},   // S_BHORIZ5
+	{SPR_SSWB, 3, 1, {NULL}, 0, 0, S_BHORIZ7, 0},   // S_BHORIZ6
+	{SPR_SSWB, 2, 1, {NULL}, 0, 0, S_BHORIZ8, 0},   // S_BHORIZ7
+	{SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1, 0},   // S_BHORIZ8
 
 	// Boosters
-	{SPR_NULL, 0, 1, {A_Pain}, 0, 0, S_INVISIBLE}, // S_BOOSTERSOUND
-	{SPR_BSTY,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_YELLOWBOOSTERROLLER
-	{SPR_BSTY, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_YELLOWBOOSTERSEG_LEFT
-	{SPR_BSTY, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_YELLOWBOOSTERSEG_RIGHT
-	{SPR_BSTY, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWBOOSTERSEG_FACE
-	{SPR_BSTR,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_REDBOOSTERROLLER
-	{SPR_BSTR, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_REDBOOSTERSEG_LEFT
-	{SPR_BSTR, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_REDBOOSTERSEG_RIGHT
-	{SPR_BSTR, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL}, // S_REDBOOSTERSEG_FACE
+	{SPR_NULL, 0, 1, {A_Pain}, 0, 0, S_INVISIBLE, 0}, // S_BOOSTERSOUND
+	{SPR_BSTY,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_YELLOWBOOSTERROLLER
+	{SPR_BSTY, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_YELLOWBOOSTERSEG_LEFT
+	{SPR_BSTY, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_YELLOWBOOSTERSEG_RIGHT
+	{SPR_BSTY, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL, 0}, // S_YELLOWBOOSTERSEG_FACE
+	{SPR_BSTR,                  FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL, 0}, // S_REDBOOSTERROLLER
+	{SPR_BSTR, 3|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_REDBOOSTERSEG_LEFT
+	{SPR_BSTR, 6|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL, 0}, // S_REDBOOSTERSEG_RIGHT
+	{SPR_BSTR, 9|FF_PAPERSPRITE,            -1, {NULL}, 0, 0, S_NULL, 0}, // S_REDBOOSTERSEG_FACE
 
 	// Rain
-	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
-	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
+	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL, 0}, // S_RAIN1
+	{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1, 0}, // S_RAINRETURN
 
 	// Snowflake
-	{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1
-	{SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW2
-	{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW3
+	{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOW1
+	{SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOW2
+	{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SNOW3
 
 	// Water Splish
-	{SPR_SPLH, FF_TRANS50  , 2, {NULL}, 0, 0, S_SPLISH2}, // S_SPLISH1
-	{SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3}, // S_SPLISH2
-	{SPR_SPLH, FF_TRANS50|2, 2, {NULL}, 0, 0, S_SPLISH4}, // S_SPLISH3
-	{SPR_SPLH, FF_TRANS50|3, 2, {NULL}, 0, 0, S_SPLISH5}, // S_SPLISH4
-	{SPR_SPLH, FF_TRANS50|4, 2, {NULL}, 0, 0, S_SPLISH6}, // S_SPLISH5
-	{SPR_SPLH, FF_TRANS50|5, 2, {NULL}, 0, 0, S_SPLISH7}, // S_SPLISH6
-	{SPR_SPLH, FF_TRANS50|6, 2, {NULL}, 0, 0, S_SPLISH8}, // S_SPLISH7
-	{SPR_SPLH, FF_TRANS50|7, 2, {NULL}, 0, 0, S_SPLISH9}, // S_SPLISH8
-	{SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL},    // S_SPLISH9
+	{SPR_SPLH, FF_TRANS50  , 2, {NULL}, 0, 0, S_SPLISH2, 0}, // S_SPLISH1
+	{SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3, 0}, // S_SPLISH2
+	{SPR_SPLH, FF_TRANS50|2, 2, {NULL}, 0, 0, S_SPLISH4, 0}, // S_SPLISH3
+	{SPR_SPLH, FF_TRANS50|3, 2, {NULL}, 0, 0, S_SPLISH5, 0}, // S_SPLISH4
+	{SPR_SPLH, FF_TRANS50|4, 2, {NULL}, 0, 0, S_SPLISH6, 0}, // S_SPLISH5
+	{SPR_SPLH, FF_TRANS50|5, 2, {NULL}, 0, 0, S_SPLISH7, 0}, // S_SPLISH6
+	{SPR_SPLH, FF_TRANS50|6, 2, {NULL}, 0, 0, S_SPLISH8, 0}, // S_SPLISH7
+	{SPR_SPLH, FF_TRANS50|7, 2, {NULL}, 0, 0, S_SPLISH9, 0}, // S_SPLISH8
+	{SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL, 0},    // S_SPLISH9
 
 	// Lava splish
-	{SPR_LSPL, FF_ANIMATE, 16, {NULL}, 7, 2, S_NULL}, // S_LAVASPLISH
+	{SPR_LSPL, FF_ANIMATE, 16, {NULL}, 7, 2, S_NULL, 0}, // S_LAVASPLISH
 
 	// Water Splash
-	{SPR_SPLA, FF_TRANS50  , 3, {NULL}, 0, 0, S_SPLASH2},    // S_SPLASH1
-	{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3},    // S_SPLASH2
-	{SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN}, // S_SPLASH3
+	{SPR_SPLA, FF_TRANS50  , 3, {NULL}, 0, 0, S_SPLASH2, 0},    // S_SPLASH1
+	{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3, 0},    // S_SPLASH2
+	{SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN, 0}, // S_SPLASH3
 
 	// Smoke
-	{SPR_SMOK, FF_TRANS50  , 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1
-	{SPR_SMOK, FF_TRANS50|1, 5, {NULL}, 0, 0, S_SMOKE3}, // S_SMOKE2
-	{SPR_SMOK, FF_TRANS50|2, 6, {NULL}, 0, 0, S_SMOKE4}, // S_SMOKE3
-	{SPR_SMOK, FF_TRANS50|3, 7, {NULL}, 0, 0, S_SMOKE5}, // S_SMOKE4
-	{SPR_SMOK, FF_TRANS50|4, 8, {NULL}, 0, 0, S_NULL},   // S_SMOKE5
+	{SPR_SMOK, FF_TRANS50  , 4, {NULL}, 0, 0, S_SMOKE2, 0}, // S_SMOKE1
+	{SPR_SMOK, FF_TRANS50|1, 5, {NULL}, 0, 0, S_SMOKE3, 0}, // S_SMOKE2
+	{SPR_SMOK, FF_TRANS50|2, 6, {NULL}, 0, 0, S_SMOKE4, 0}, // S_SMOKE3
+	{SPR_SMOK, FF_TRANS50|3, 7, {NULL}, 0, 0, S_SMOKE5, 0}, // S_SMOKE4
+	{SPR_SMOK, FF_TRANS50|4, 8, {NULL}, 0, 0, S_NULL, 0},   // S_SMOKE5
 
 	// Bubbles
-	{SPR_BUBL, FF_TRANS50,   1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE},  // S_SMALLBUBBLE
-	{SPR_BUBL, FF_TRANS50|1, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE}, // S_MEDIUMBUBBLE
+	{SPR_BUBL, FF_TRANS50,   1, {A_BubbleRise}, 0, 1024, S_SMALLBUBBLE, 0},  // S_SMALLBUBBLE
+	{SPR_BUBL, FF_TRANS50|1, 1, {A_BubbleRise}, 0, 1024, S_MEDIUMBUBBLE, 0}, // S_MEDIUMBUBBLE
 
 	// Extra Large Bubble (breathable)
-	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|2,   8, {A_BubbleRise}, 0, 1024, S_LARGEBUBBLE2}, // S_LARGEBUBBLE1
-	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|3,   8, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_LARGEBUBBLE2
-	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|4,  16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE}, // S_EXTRALARGEBUBBLE
+	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|2,   8, {A_BubbleRise}, 0, 1024, S_LARGEBUBBLE2, 0}, // S_LARGEBUBBLE1
+	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|3,   8, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE, 0}, // S_LARGEBUBBLE2
+	{SPR_BUBL, FF_TRANS50|FF_FULLBRIGHT|4,  16, {A_BubbleRise}, 0, 1024, S_EXTRALARGEBUBBLE, 0}, // S_EXTRALARGEBUBBLE
 
 	// Extra Large Bubble goes POP!
-	{SPR_BUBL, 5, 16, {NULL}, 0, 0, S_NULL}, // S_POP1
+	{SPR_BUBL, 5, 16, {NULL}, 0, 0, S_NULL, 0}, // S_POP1
 
-	{SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL},  // S_WATERZAP
+	{SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL, 0},  // S_WATERZAP
 
 	// Spindash dust
-	{SPR_DUST,                          0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1
-	{SPR_DUST,                          1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2
-	{SPR_DUST,               FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3
-	{SPR_DUST,               FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4
-	{SPR_BUBL,                          0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1
-	{SPR_BUBL,                          0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2
-	{SPR_BUBL,               FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3
-	{SPR_BUBL,               FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4
-	{SPR_FPRT,            FF_FULLBRIGHT|0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1
-	{SPR_FPRT,            FF_FULLBRIGHT|0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2
-	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3
-	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4
-
-
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50,    2, {NULL}, 0, 0, S_FOG2},  // S_FOG1
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|1,  2, {NULL}, 0, 0, S_FOG3},  // S_FOG2
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|2,  2, {NULL}, 0, 0, S_FOG4},  // S_FOG3
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|3,  2, {NULL}, 0, 0, S_FOG5},  // S_FOG4
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|4,  2, {NULL}, 0, 0, S_FOG6},  // S_FOG5
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|5,  2, {NULL}, 0, 0, S_FOG7},  // S_FOG6
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|6,  2, {NULL}, 0, 0, S_FOG8},  // S_FOG7
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|7,  2, {NULL}, 0, 0, S_FOG9},  // S_FOG8
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|8,  2, {NULL}, 0, 0, S_FOG10}, // S_FOG9
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|9,  2, {NULL}, 0, 0, S_FOG11}, // S_FOG10
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|10, 2, {NULL}, 0, 0, S_FOG12}, // S_FOG11
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|11, 2, {NULL}, 0, 0, S_FOG13}, // S_FOG12
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|12, 2, {NULL}, 0, 0, S_FOG14}, // S_FOG13
-	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|13, 2, {NULL}, 0, 0, S_NULL},  // S_FOG14
+	{SPR_DUST,                          0, 7, {NULL}, 0, 0, S_SPINDUST2, 0}, // S_SPINDUST1
+	{SPR_DUST,                          1, 6, {NULL}, 0, 0, S_SPINDUST3, 0}, // S_SPINDUST2
+	{SPR_DUST,               FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4, 0}, // S_SPINDUST3
+	{SPR_DUST,               FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL, 0}, // S_SPINDUST4
+	{SPR_BUBL,                          0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2, 0}, // S_SPINDUST_BUBBLE1
+	{SPR_BUBL,                          0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3, 0}, // S_SPINDUST_BUBBLE2
+	{SPR_BUBL,               FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4, 0}, // S_SPINDUST_BUBBLE3
+	{SPR_BUBL,               FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL, 0}, // S_SPINDUST_BUBBLE4
+	{SPR_FPRT,            FF_FULLBRIGHT|0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2, 0}, // S_SPINDUST_FIRE1
+	{SPR_FPRT,            FF_FULLBRIGHT|0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3, 0}, // S_SPINDUST_FIRE2
+	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4, 0}, // S_SPINDUST_FIRE3
+	{SPR_FPRT, FF_FULLBRIGHT|FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL, 0}, // S_SPINDUST_FIRE4
+
+
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50,    2, {NULL}, 0, 0, S_FOG2, 0},  // S_FOG1
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|1,  2, {NULL}, 0, 0, S_FOG3, 0},  // S_FOG2
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|2,  2, {NULL}, 0, 0, S_FOG4, 0},  // S_FOG3
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|3,  2, {NULL}, 0, 0, S_FOG5, 0},  // S_FOG4
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|4,  2, {NULL}, 0, 0, S_FOG6, 0},  // S_FOG5
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|5,  2, {NULL}, 0, 0, S_FOG7, 0},  // S_FOG6
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|6,  2, {NULL}, 0, 0, S_FOG8, 0},  // S_FOG7
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|7,  2, {NULL}, 0, 0, S_FOG9, 0},  // S_FOG8
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|8,  2, {NULL}, 0, 0, S_FOG10, 0}, // S_FOG9
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|9,  2, {NULL}, 0, 0, S_FOG11, 0}, // S_FOG10
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|10, 2, {NULL}, 0, 0, S_FOG12, 0}, // S_FOG11
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|11, 2, {NULL}, 0, 0, S_FOG13, 0}, // S_FOG12
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|12, 2, {NULL}, 0, 0, S_FOG14, 0}, // S_FOG13
+	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|13, 2, {NULL}, 0, 0, S_NULL, 0},  // S_FOG14
 
 	// Flower Seed
-	{SPR_SEED, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 2, 2, S_NULL}, // S_SEED
+	{SPR_SEED, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 2, 2, S_NULL, 0}, // S_SEED
 
 	// Particle sprite
-	{SPR_PRTL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE
-
-	{SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRA  - 100
-	{SPR_SCOR, 1, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRB  - 200
-	{SPR_SCOR, 2, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRC  - 500
-	{SPR_SCOR, 3, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRD  - 1000
-	{SPR_SCOR, 4, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRE  - 10000
-	{SPR_SCOR, 5, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRF  - 400 (mario mode)
-	{SPR_SCOR, 6, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRG  - 800 (mario mode)
-	{SPR_SCOR, 7, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRH  - 2000 (mario mode)
-	{SPR_SCOR, 8, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRI  - 4000 (mario mode)
-	{SPR_SCOR, 9, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRJ  - 8000 (mario mode)
-	{SPR_SCOR, 10, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRK - 1UP (mario mode)
-	{SPR_SCOR, 11, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRL - 10
+	{SPR_PRTL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL, 0}, // S_PARTICLE
+
+	{SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRA  - 100
+	{SPR_SCOR, 1, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRB  - 200
+	{SPR_SCOR, 2, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRC  - 500
+	{SPR_SCOR, 3, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRD  - 1000
+	{SPR_SCOR, 4, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRE  - 10000
+	{SPR_SCOR, 5, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRF  - 400 (mario mode)
+	{SPR_SCOR, 6, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRG  - 800 (mario mode)
+	{SPR_SCOR, 7, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRH  - 2000 (mario mode)
+	{SPR_SCOR, 8, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRI  - 4000 (mario mode)
+	{SPR_SCOR, 9, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRJ  - 8000 (mario mode)
+	{SPR_SCOR, 10, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRK - 1UP (mario mode)
+	{SPR_SCOR, 11, 32, {A_ScoreRise}, 0, 0, S_NULL, 0}, // S_SCRL - 10
 
 	// Drowning Timer Numbers
-	{SPR_DRWN, 0, 40, {NULL}, 0, 0, S_NULL}, // S_ZERO1
-	{SPR_DRWN, 1, 40, {NULL}, 0, 0, S_NULL}, // S_ONE1
-	{SPR_DRWN, 2, 40, {NULL}, 0, 0, S_NULL}, // S_TWO1
-	{SPR_DRWN, 3, 40, {NULL}, 0, 0, S_NULL}, // S_THREE1
-	{SPR_DRWN, 4, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR1
-	{SPR_DRWN, 5, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE1
-
-	{SPR_DRWN,  6, 40, {NULL}, 0, 0, S_NULL}, // S_ZERO2
-	{SPR_DRWN,  7, 40, {NULL}, 0, 0, S_NULL}, // S_ONE2
-	{SPR_DRWN,  8, 40, {NULL}, 0, 0, S_NULL}, // S_TWO2
-	{SPR_DRWN,  9, 40, {NULL}, 0, 0, S_NULL}, // S_THREE2
-	{SPR_DRWN, 10, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR2
-	{SPR_DRWN, 11, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE2
+	{SPR_DRWN, 0, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ZERO1
+	{SPR_DRWN, 1, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ONE1
+	{SPR_DRWN, 2, 40, {NULL}, 0, 0, S_NULL, 0}, // S_TWO1
+	{SPR_DRWN, 3, 40, {NULL}, 0, 0, S_NULL, 0}, // S_THREE1
+	{SPR_DRWN, 4, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FOUR1
+	{SPR_DRWN, 5, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FIVE1
+
+	{SPR_DRWN,  6, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ZERO2
+	{SPR_DRWN,  7, 40, {NULL}, 0, 0, S_NULL, 0}, // S_ONE2
+	{SPR_DRWN,  8, 40, {NULL}, 0, 0, S_NULL, 0}, // S_TWO2
+	{SPR_DRWN,  9, 40, {NULL}, 0, 0, S_NULL, 0}, // S_THREE2
+	{SPR_DRWN, 10, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FOUR2
+	{SPR_DRWN, 11, 40, {NULL}, 0, 0, S_NULL, 0}, // S_FIVE2
 
 	// Flight indicator
-	{SPR_FLII, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 4, S_NULL}, // S_FLIGHTINDICATOR
+	{SPR_FLII, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 4, S_NULL, 0}, // S_FLIGHTINDICATOR
 
-	{SPR_LCKN,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON1
-	{SPR_LCKN, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON2
-	{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON3
-	{SPR_LCKN, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON4
+	{SPR_LCKN,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON1
+	{SPR_LCKN, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON2
+	{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON3
+	{SPR_LCKN, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKON4
 
-	{SPR_LCKN,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF1
-	{SPR_LCKN, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF2
-	{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF3
-	{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF4
+	{SPR_LCKN,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF1
+	{SPR_LCKN, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF2
+	{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF3
+	{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LOCKONINF4
 
-	{SPR_TTAG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_TTAG
+	{SPR_TTAG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL, 0}, // S_TTAG
 
 	// CTF Sign
-	{SPR_GFLG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
+	{SPR_GFLG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL, 0}, // S_GOTFLAG
 
 	// Finish flag
-	{SPR_FNSF,    FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_FINISHFLAG
+	{SPR_FNSF,    FF_TRANS30, -1, {NULL}, 0, 0, S_NULL, 0}, // S_FINISHFLAG
 
-	{SPR_CORK,             0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
-	{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LHRT
+	{SPR_CORK,             0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CORK
+	{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_LHRT
 
 	// Red Rings (thrown)
-	{SPR_RRNG, FF_FULLBRIGHT,   1, {A_ThrownRing}, 0, 0, S_RRNG2}, // S_RRNG1
-	{SPR_RRNG, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_RRNG3}, // S_RRNG2
-	{SPR_RRNG, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_RRNG4}, // S_RRNG3
-	{SPR_RRNG, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_RRNG5}, // S_RRNG4
-	{SPR_RRNG, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_RRNG6}, // S_RRNG5
-	{SPR_RRNG, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_RRNG7}, // S_RRNG6
-	{SPR_RRNG, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_RRNG1}, // S_RRNG7
+	{SPR_RRNG, FF_FULLBRIGHT,   1, {A_ThrownRing}, 0, 0, S_RRNG2, 0}, // S_RRNG1
+	{SPR_RRNG, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_RRNG3, 0}, // S_RRNG2
+	{SPR_RRNG, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_RRNG4, 0}, // S_RRNG3
+	{SPR_RRNG, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_RRNG5, 0}, // S_RRNG4
+	{SPR_RRNG, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_RRNG6, 0}, // S_RRNG5
+	{SPR_RRNG, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_RRNG7, 0}, // S_RRNG6
+	{SPR_RRNG, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_RRNG1, 0}, // S_RRNG7
 
 	// Weapon Ring Ammo
-	{SPR_RNGB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_BOUNCERINGAMMO},    // S_BOUNCERINGAMMO
-	{SPR_RNGR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_RAILRINGAMMO},      // S_RAILRINGAMMO
-	{SPR_RNGI, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_INFINITYRINGAMMO},  // S_INFINITYRINGAMMO
-	{SPR_RNGA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_AUTOMATICRINGAMMO}, // S_AUTOMATICRINGAMMO
-	{SPR_RNGE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_EXPLOSIONRINGAMMO}, // S_EXPLOSIONRINGAMMO
-	{SPR_RNGS, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_SCATTERRINGAMMO},   // S_SCATTERRINGAMMO
-	{SPR_RNGG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_GRENADERINGAMMO},   // S_GRENADERINGAMMO
+	{SPR_RNGB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_BOUNCERINGAMMO, 0},    // S_BOUNCERINGAMMO
+	{SPR_RNGR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_RAILRINGAMMO, 0},      // S_RAILRINGAMMO
+	{SPR_RNGI, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_INFINITYRINGAMMO, 0},  // S_INFINITYRINGAMMO
+	{SPR_RNGA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_AUTOMATICRINGAMMO, 0}, // S_AUTOMATICRINGAMMO
+	{SPR_RNGE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_EXPLOSIONRINGAMMO, 0}, // S_EXPLOSIONRINGAMMO
+	{SPR_RNGS, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_SCATTERRINGAMMO, 0},   // S_SCATTERRINGAMMO
+	{SPR_RNGG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 34, 1, S_GRENADERINGAMMO, 0},   // S_GRENADERINGAMMO
 
 	// Bounce Ring Pickup
-	{SPR_PIKB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_BOUNCEPICKUP},  // S_BOUNCEPICKUP
+	{SPR_PIKB, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_BOUNCEPICKUP, 0},  // S_BOUNCEPICKUP
 
-	{SPR_PIKB,  0, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE2}, // S_BOUNCEPICKUPFADE1
-	{SPR_PIKB,  2, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE3}, // S_BOUNCEPICKUPFADE2
-	{SPR_PIKB,  4, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE4}, // S_BOUNCEPICKUPFADE3
-	{SPR_PIKB,  6, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE5}, // S_BOUNCEPICKUPFADE4
-	{SPR_PIKB,  8, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE6}, // S_BOUNCEPICKUPFADE5
-	{SPR_PIKB, 10, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE7}, // S_BOUNCEPICKUPFADE6
-	{SPR_PIKB, 12, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE8}, // S_BOUNCEPICKUPFADE7
-	{SPR_PIKB, 14, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE1}, // S_BOUNCEPICKUPFADE8
+	{SPR_PIKB,  0, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE2, 0}, // S_BOUNCEPICKUPFADE1
+	{SPR_PIKB,  2, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE3, 0}, // S_BOUNCEPICKUPFADE2
+	{SPR_PIKB,  4, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE4, 0}, // S_BOUNCEPICKUPFADE3
+	{SPR_PIKB,  6, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE5, 0}, // S_BOUNCEPICKUPFADE4
+	{SPR_PIKB,  8, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE6, 0}, // S_BOUNCEPICKUPFADE5
+	{SPR_PIKB, 10, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE7, 0}, // S_BOUNCEPICKUPFADE6
+	{SPR_PIKB, 12, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE8, 0}, // S_BOUNCEPICKUPFADE7
+	{SPR_PIKB, 14, 1, {NULL}, 0, 0, S_BOUNCEPICKUPFADE1, 0}, // S_BOUNCEPICKUPFADE8
 
 	// Rail Ring Pickup
-	{SPR_PIKR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_RAILPICKUP},  // S_RAILPICKUP
+	{SPR_PIKR, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_RAILPICKUP, 0},  // S_RAILPICKUP
 
-	{SPR_PIKR,  0, 1, {NULL}, 0, 0, S_RAILPICKUPFADE2}, // S_RAILPICKUPFADE1
-	{SPR_PIKR,  2, 1, {NULL}, 0, 0, S_RAILPICKUPFADE3}, // S_RAILPICKUPFADE2
-	{SPR_PIKR,  4, 1, {NULL}, 0, 0, S_RAILPICKUPFADE4}, // S_RAILPICKUPFADE3
-	{SPR_PIKR,  6, 1, {NULL}, 0, 0, S_RAILPICKUPFADE5}, // S_RAILPICKUPFADE4
-	{SPR_PIKR,  8, 1, {NULL}, 0, 0, S_RAILPICKUPFADE6}, // S_RAILPICKUPFADE5
-	{SPR_PIKR, 10, 1, {NULL}, 0, 0, S_RAILPICKUPFADE7}, // S_RAILPICKUPFADE6
-	{SPR_PIKR, 12, 1, {NULL}, 0, 0, S_RAILPICKUPFADE8}, // S_RAILPICKUPFADE7
-	{SPR_PIKR, 14, 1, {NULL}, 0, 0, S_RAILPICKUPFADE1}, // S_RAILPICKUPFADE8
+	{SPR_PIKR,  0, 1, {NULL}, 0, 0, S_RAILPICKUPFADE2, 0}, // S_RAILPICKUPFADE1
+	{SPR_PIKR,  2, 1, {NULL}, 0, 0, S_RAILPICKUPFADE3, 0}, // S_RAILPICKUPFADE2
+	{SPR_PIKR,  4, 1, {NULL}, 0, 0, S_RAILPICKUPFADE4, 0}, // S_RAILPICKUPFADE3
+	{SPR_PIKR,  6, 1, {NULL}, 0, 0, S_RAILPICKUPFADE5, 0}, // S_RAILPICKUPFADE4
+	{SPR_PIKR,  8, 1, {NULL}, 0, 0, S_RAILPICKUPFADE6, 0}, // S_RAILPICKUPFADE5
+	{SPR_PIKR, 10, 1, {NULL}, 0, 0, S_RAILPICKUPFADE7, 0}, // S_RAILPICKUPFADE6
+	{SPR_PIKR, 12, 1, {NULL}, 0, 0, S_RAILPICKUPFADE8, 0}, // S_RAILPICKUPFADE7
+	{SPR_PIKR, 14, 1, {NULL}, 0, 0, S_RAILPICKUPFADE1, 0}, // S_RAILPICKUPFADE8
 
 	// Auto Ring Pickup
-	{SPR_PIKA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_AUTOPICKUP},  // S_AUTOPICKUP
+	{SPR_PIKA, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_AUTOPICKUP, 0},  // S_AUTOPICKUP
 
-	{SPR_PIKA,  0, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE2}, // S_AUTOPICKUPFADE1
-	{SPR_PIKA,  2, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE3}, // S_AUTOPICKUPFADE2
-	{SPR_PIKA,  4, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE4}, // S_AUTOPICKUPFADE3
-	{SPR_PIKA,  6, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE5}, // S_AUTOPICKUPFADE4
-	{SPR_PIKA,  8, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE6}, // S_AUTOPICKUPFADE5
-	{SPR_PIKA, 10, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE7}, // S_AUTOPICKUPFADE6
-	{SPR_PIKA, 12, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE8}, // S_AUTOPICKUPFADE7
-	{SPR_PIKA, 14, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE1}, // S_AUTOPICKUPFADE8
+	{SPR_PIKA,  0, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE2, 0}, // S_AUTOPICKUPFADE1
+	{SPR_PIKA,  2, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE3, 0}, // S_AUTOPICKUPFADE2
+	{SPR_PIKA,  4, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE4, 0}, // S_AUTOPICKUPFADE3
+	{SPR_PIKA,  6, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE5, 0}, // S_AUTOPICKUPFADE4
+	{SPR_PIKA,  8, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE6, 0}, // S_AUTOPICKUPFADE5
+	{SPR_PIKA, 10, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE7, 0}, // S_AUTOPICKUPFADE6
+	{SPR_PIKA, 12, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE8, 0}, // S_AUTOPICKUPFADE7
+	{SPR_PIKA, 14, 1, {NULL}, 0, 0, S_AUTOPICKUPFADE1, 0}, // S_AUTOPICKUPFADE8
 
 	// Explode Ring Pickup
-	{SPR_PIKE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_EXPLODEPICKUP},  // S_EXPLODEPICKUP
+	{SPR_PIKE, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_EXPLODEPICKUP, 0},  // S_EXPLODEPICKUP
 
-	{SPR_PIKE,  0, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE2}, // S_EXPLODEPICKUPFADE1
-	{SPR_PIKE,  2, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE3}, // S_EXPLODEPICKUPFADE2
-	{SPR_PIKE,  4, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE4}, // S_EXPLODEPICKUPFADE3
-	{SPR_PIKE,  6, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE5}, // S_EXPLODEPICKUPFADE4
-	{SPR_PIKE,  8, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE6}, // S_EXPLODEPICKUPFADE5
-	{SPR_PIKE, 10, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE7}, // S_EXPLODEPICKUPFADE6
-	{SPR_PIKE, 12, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE8}, // S_EXPLODEPICKUPFADE7
-	{SPR_PIKE, 14, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE1}, // S_EXPLODEPICKUPFADE8
+	{SPR_PIKE,  0, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE2, 0}, // S_EXPLODEPICKUPFADE1
+	{SPR_PIKE,  2, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE3, 0}, // S_EXPLODEPICKUPFADE2
+	{SPR_PIKE,  4, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE4, 0}, // S_EXPLODEPICKUPFADE3
+	{SPR_PIKE,  6, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE5, 0}, // S_EXPLODEPICKUPFADE4
+	{SPR_PIKE,  8, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE6, 0}, // S_EXPLODEPICKUPFADE5
+	{SPR_PIKE, 10, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE7, 0}, // S_EXPLODEPICKUPFADE6
+	{SPR_PIKE, 12, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE8, 0}, // S_EXPLODEPICKUPFADE7
+	{SPR_PIKE, 14, 1, {NULL}, 0, 0, S_EXPLODEPICKUPFADE1, 0}, // S_EXPLODEPICKUPFADE8
 
 	// Scatter Ring Pickup
-	{SPR_PIKS,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_SCATTERPICKUP},  // S_SCATTERPICKUP
+	{SPR_PIKS,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_SCATTERPICKUP, 0},  // S_SCATTERPICKUP
 
-	{SPR_PIKS,  0, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE2}, // S_SCATTERPICKUPFADE1
-	{SPR_PIKS,  2, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE3}, // S_SCATTERPICKUPFADE2
-	{SPR_PIKS,  4, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE4}, // S_SCATTERPICKUPFADE3
-	{SPR_PIKS,  6, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE5}, // S_SCATTERPICKUPFADE4
-	{SPR_PIKS,  8, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE6}, // S_SCATTERPICKUPFADE5
-	{SPR_PIKS, 10, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE7}, // S_SCATTERPICKUPFADE6
-	{SPR_PIKS, 12, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE8}, // S_SCATTERPICKUPFADE7
-	{SPR_PIKS, 14, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE1}, // S_SCATTERPICKUPFADE8
+	{SPR_PIKS,  0, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE2, 0}, // S_SCATTERPICKUPFADE1
+	{SPR_PIKS,  2, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE3, 0}, // S_SCATTERPICKUPFADE2
+	{SPR_PIKS,  4, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE4, 0}, // S_SCATTERPICKUPFADE3
+	{SPR_PIKS,  6, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE5, 0}, // S_SCATTERPICKUPFADE4
+	{SPR_PIKS,  8, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE6, 0}, // S_SCATTERPICKUPFADE5
+	{SPR_PIKS, 10, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE7, 0}, // S_SCATTERPICKUPFADE6
+	{SPR_PIKS, 12, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE8, 0}, // S_SCATTERPICKUPFADE7
+	{SPR_PIKS, 14, 1, {NULL}, 0, 0, S_SCATTERPICKUPFADE1, 0}, // S_SCATTERPICKUPFADE8
 
 	// Grenade Ring Pickup
-	{SPR_PIKG,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_GRENADEPICKUP},  // S_GRENADEPICKUP
+	{SPR_PIKG,  FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 15, 1, S_GRENADEPICKUP, 0},  // S_GRENADEPICKUP
 
-	{SPR_PIKG,  0, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE2}, // S_GRENADEPICKUPFADE1
-	{SPR_PIKG,  2, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE3}, // S_GRENADEPICKUPFADE2
-	{SPR_PIKG,  4, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE4}, // S_GRENADEPICKUPFADE3
-	{SPR_PIKG,  6, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE5}, // S_GRENADEPICKUPFADE4
-	{SPR_PIKG,  8, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE6}, // S_GRENADEPICKUPFADE5
-	{SPR_PIKG, 10, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE7}, // S_GRENADEPICKUPFADE6
-	{SPR_PIKG, 12, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE8}, // S_GRENADEPICKUPFADE7
-	{SPR_PIKG, 14, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE1}, // S_GRENADEPICKUPFADE8
+	{SPR_PIKG,  0, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE2, 0}, // S_GRENADEPICKUPFADE1
+	{SPR_PIKG,  2, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE3, 0}, // S_GRENADEPICKUPFADE2
+	{SPR_PIKG,  4, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE4, 0}, // S_GRENADEPICKUPFADE3
+	{SPR_PIKG,  6, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE5, 0}, // S_GRENADEPICKUPFADE4
+	{SPR_PIKG,  8, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE6, 0}, // S_GRENADEPICKUPFADE5
+	{SPR_PIKG, 10, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE7, 0}, // S_GRENADEPICKUPFADE6
+	{SPR_PIKG, 12, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE8, 0}, // S_GRENADEPICKUPFADE7
+	{SPR_PIKG, 14, 1, {NULL}, 0, 0, S_GRENADEPICKUPFADE1, 0}, // S_GRENADEPICKUPFADE8
 
 	// Thrown Weapon Rings
-	{SPR_RNGB, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE2}, // S_THROWNBOUNCE1
-	{SPR_RNGB, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE3}, // S_THROWNBOUNCE2
-	{SPR_RNGB, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE4}, // S_THROWNBOUNCE3
-	{SPR_RNGB, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE5}, // S_THROWNBOUNCE4
-	{SPR_RNGB, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE6}, // S_THROWNBOUNCE5
-	{SPR_RNGB, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE7}, // S_THROWNBOUNCE6
-	{SPR_RNGB, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE1}, // S_THROWNBOUNCE7
-
-	{SPR_RNGI, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY2}, // S_THROWNINFINITY1
-	{SPR_RNGI, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY3}, // S_THROWNINFINITY2
-	{SPR_RNGI, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY4}, // S_THROWNINFINITY3
-	{SPR_RNGI, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY5}, // S_THROWNINFINITY4
-	{SPR_RNGI, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY6}, // S_THROWNINFINITY5
-	{SPR_RNGI, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY7}, // S_THROWNINFINITY6
-	{SPR_RNGI, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY1}, // S_THROWNINFINITY7
-
-	{SPR_TAUT, FF_FULLBRIGHT  , 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC2}, // S_THROWNAUTOMATIC1
-	{SPR_TAUT, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC3}, // S_THROWNAUTOMATIC2
-	{SPR_TAUT, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC4}, // S_THROWNAUTOMATIC3
-	{SPR_TAUT, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC5}, // S_THROWNAUTOMATIC4
-	{SPR_TAUT, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC6}, // S_THROWNAUTOMATIC5
-	{SPR_TAUT, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC7}, // S_THROWNAUTOMATIC6
-	{SPR_TAUT, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC1}, // S_THROWNAUTOMATIC7
-
-	{SPR_RNGE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION2}, // S_THROWNEXPLOSION1
-	{SPR_RNGE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION3}, // S_THROWNEXPLOSION2
-	{SPR_RNGE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION4}, // S_THROWNEXPLOSION3
-	{SPR_RNGE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION5}, // S_THROWNEXPLOSION4
-	{SPR_RNGE, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION6}, // S_THROWNEXPLOSION5
-	{SPR_RNGE, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION7}, // S_THROWNEXPLOSION6
-	{SPR_RNGE, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION1}, // S_THROWNEXPLOSION7
-
-	{SPR_TGRE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE2},  // S_THROWNGRENADE1
-	{SPR_TGRE, FF_FULLBRIGHT| 1, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE3},  // S_THROWNGRENADE2
-	{SPR_TGRE, FF_FULLBRIGHT| 2, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE4},  // S_THROWNGRENADE3
-	{SPR_TGRE, FF_FULLBRIGHT| 3, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE5},  // S_THROWNGRENADE4
-	{SPR_TGRE, FF_FULLBRIGHT| 4, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE6},  // S_THROWNGRENADE5
-	{SPR_TGRE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE7},  // S_THROWNGRENADE6
-	{SPR_TGRE, FF_FULLBRIGHT| 6, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE8},  // S_THROWNGRENADE7
-	{SPR_TGRE, FF_FULLBRIGHT| 7, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE9},  // S_THROWNGRENADE8
-	{SPR_TGRE, FF_FULLBRIGHT| 8, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE10}, // S_THROWNGRENADE9
-	{SPR_TGRE, FF_FULLBRIGHT| 9, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE11}, // S_THROWNGRENADE10
-	{SPR_TGRE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE12}, // S_THROWNGRENADE11
-	{SPR_TGRE, FF_FULLBRIGHT|11, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE13}, // S_THROWNGRENADE12
-	{SPR_TGRE, FF_FULLBRIGHT|12, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE14}, // S_THROWNGRENADE13
-	{SPR_TGRE, FF_FULLBRIGHT|13, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE15}, // S_THROWNGRENADE14
-	{SPR_TGRE, FF_FULLBRIGHT|14, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE16}, // S_THROWNGRENADE15
-	{SPR_TGRE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE17}, // S_THROWNGRENADE16
-	{SPR_TGRE, FF_FULLBRIGHT|16, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE18}, // S_THROWNGRENADE17
-	{SPR_TGRE, FF_FULLBRIGHT|17, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE1},  // S_THROWNGRENADE18
-
-	{SPR_TSCR, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_THROWNSCATTER}, // S_THROWNSCATTER
-
-	{SPR_NULL, 0, 1, {A_RingExplode}, 0, 0, S_XPLD1}, // S_RINGEXPLODE
+	{SPR_RNGB, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE2, 0}, // S_THROWNBOUNCE1
+	{SPR_RNGB, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE3, 0}, // S_THROWNBOUNCE2
+	{SPR_RNGB, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE4, 0}, // S_THROWNBOUNCE3
+	{SPR_RNGB, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE5, 0}, // S_THROWNBOUNCE4
+	{SPR_RNGB, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE6, 0}, // S_THROWNBOUNCE5
+	{SPR_RNGB, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE7, 0}, // S_THROWNBOUNCE6
+	{SPR_RNGB, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNBOUNCE1, 0}, // S_THROWNBOUNCE7
+
+	{SPR_RNGI, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY2, 0}, // S_THROWNINFINITY1
+	{SPR_RNGI, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY3, 0}, // S_THROWNINFINITY2
+	{SPR_RNGI, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY4, 0}, // S_THROWNINFINITY3
+	{SPR_RNGI, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY5, 0}, // S_THROWNINFINITY4
+	{SPR_RNGI, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY6, 0}, // S_THROWNINFINITY5
+	{SPR_RNGI, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY7, 0}, // S_THROWNINFINITY6
+	{SPR_RNGI, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNINFINITY1, 0}, // S_THROWNINFINITY7
+
+	{SPR_TAUT, FF_FULLBRIGHT  , 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC2, 0}, // S_THROWNAUTOMATIC1
+	{SPR_TAUT, FF_FULLBRIGHT|1, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC3, 0}, // S_THROWNAUTOMATIC2
+	{SPR_TAUT, FF_FULLBRIGHT|2, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC4, 0}, // S_THROWNAUTOMATIC3
+	{SPR_TAUT, FF_FULLBRIGHT|3, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC5, 0}, // S_THROWNAUTOMATIC4
+	{SPR_TAUT, FF_FULLBRIGHT|4, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC6, 0}, // S_THROWNAUTOMATIC5
+	{SPR_TAUT, FF_FULLBRIGHT|5, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC7, 0}, // S_THROWNAUTOMATIC6
+	{SPR_TAUT, FF_FULLBRIGHT|6, 1, {A_ThrownRing}, 0, 0, S_THROWNAUTOMATIC1, 0}, // S_THROWNAUTOMATIC7
+
+	{SPR_RNGE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION2, 0}, // S_THROWNEXPLOSION1
+	{SPR_RNGE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION3, 0}, // S_THROWNEXPLOSION2
+	{SPR_RNGE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION4, 0}, // S_THROWNEXPLOSION3
+	{SPR_RNGE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION5, 0}, // S_THROWNEXPLOSION4
+	{SPR_RNGE, FF_FULLBRIGHT|20, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION6, 0}, // S_THROWNEXPLOSION5
+	{SPR_RNGE, FF_FULLBRIGHT|25, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION7, 0}, // S_THROWNEXPLOSION6
+	{SPR_RNGE, FF_FULLBRIGHT|30, 1, {A_ThrownRing}, 0, 0, S_THROWNEXPLOSION1, 0}, // S_THROWNEXPLOSION7
+
+	{SPR_TGRE, FF_FULLBRIGHT   , 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE2, 0},  // S_THROWNGRENADE1
+	{SPR_TGRE, FF_FULLBRIGHT| 1, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE3, 0},  // S_THROWNGRENADE2
+	{SPR_TGRE, FF_FULLBRIGHT| 2, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE4, 0},  // S_THROWNGRENADE3
+	{SPR_TGRE, FF_FULLBRIGHT| 3, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE5, 0},  // S_THROWNGRENADE4
+	{SPR_TGRE, FF_FULLBRIGHT| 4, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE6, 0},  // S_THROWNGRENADE5
+	{SPR_TGRE, FF_FULLBRIGHT| 5, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE7, 0},  // S_THROWNGRENADE6
+	{SPR_TGRE, FF_FULLBRIGHT| 6, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE8, 0},  // S_THROWNGRENADE7
+	{SPR_TGRE, FF_FULLBRIGHT| 7, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE9, 0},  // S_THROWNGRENADE8
+	{SPR_TGRE, FF_FULLBRIGHT| 8, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE10, 0}, // S_THROWNGRENADE9
+	{SPR_TGRE, FF_FULLBRIGHT| 9, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE11, 0}, // S_THROWNGRENADE10
+	{SPR_TGRE, FF_FULLBRIGHT|10, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE12, 0}, // S_THROWNGRENADE11
+	{SPR_TGRE, FF_FULLBRIGHT|11, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE13, 0}, // S_THROWNGRENADE12
+	{SPR_TGRE, FF_FULLBRIGHT|12, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE14, 0}, // S_THROWNGRENADE13
+	{SPR_TGRE, FF_FULLBRIGHT|13, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE15, 0}, // S_THROWNGRENADE14
+	{SPR_TGRE, FF_FULLBRIGHT|14, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE16, 0}, // S_THROWNGRENADE15
+	{SPR_TGRE, FF_FULLBRIGHT|15, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE17, 0}, // S_THROWNGRENADE16
+	{SPR_TGRE, FF_FULLBRIGHT|16, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE18, 0}, // S_THROWNGRENADE17
+	{SPR_TGRE, FF_FULLBRIGHT|17, 1, {A_ThrownRing}, 0, 0, S_THROWNGRENADE1, 0},  // S_THROWNGRENADE18
+
+	{SPR_TSCR, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_THROWNSCATTER, 0}, // S_THROWNSCATTER
+
+	{SPR_NULL, 0, 1, {A_RingExplode}, 0, 0, S_XPLD1, 0}, // S_RINGEXPLODE
 
 	// Coin
-	{SPR_COIN, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_COIN2}, // S_COIN1
-	{SPR_COIN, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COIN3}, // S_COIN2
-	{SPR_COIN, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COIN1}, // S_COIN3
+	{SPR_COIN, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_COIN2, 0}, // S_COIN1
+	{SPR_COIN, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COIN3, 0}, // S_COIN2
+	{SPR_COIN, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COIN1, 0}, // S_COIN3
 
 	// Coin Sparkle
-	{SPR_CPRK, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_COINSPARKLE2}, // S_COINSPARKLE1
-	{SPR_CPRK, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COINSPARKLE3}, // S_COINSPARKLE2
-	{SPR_CPRK, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COINSPARKLE4}, // S_COINSPARKLE3
-	{SPR_CPRK, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL},         // S_COINSPARKLE4
+	{SPR_CPRK, FF_FULLBRIGHT,   5, {NULL}, 0, 0, S_COINSPARKLE2, 0}, // S_COINSPARKLE1
+	{SPR_CPRK, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_COINSPARKLE3, 0}, // S_COINSPARKLE2
+	{SPR_CPRK, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_COINSPARKLE4, 0}, // S_COINSPARKLE3
+	{SPR_CPRK, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL, 0},         // S_COINSPARKLE4
 
 	// Goomba
-	{SPR_GOOM, 0, 6, {A_Look}, 0, 0, S_GOOMBA1B}, // S_GOOMBA1
-	{SPR_GOOM, 1, 6, {A_Look}, 0, 0, S_GOOMBA1},  // S_GOOMBA1B
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA3}, // S_GOOMBA2
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA4}, // S_GOOMBA3
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA5}, // S_GOOMBA4
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA6}, // S_GOOMBA5
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA7}, // S_GOOMBA6
-	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA8}, // S_GOOMBA7
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA9}, // S_GOOMBA8
-	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA2}, // S_GOOMBA9
-	{SPR_GOOM, 2, 16, {A_Scream}, 0, 0, S_NULL},  // S_GOOMBA_DEAD
+	{SPR_GOOM, 0, 6, {A_Look}, 0, 0, S_GOOMBA1B, 0}, // S_GOOMBA1
+	{SPR_GOOM, 1, 6, {A_Look}, 0, 0, S_GOOMBA1, 0},  // S_GOOMBA1B
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA3, 0}, // S_GOOMBA2
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA4, 0}, // S_GOOMBA3
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA5, 0}, // S_GOOMBA4
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA6, 0}, // S_GOOMBA5
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA7, 0}, // S_GOOMBA6
+	{SPR_GOOM, 0, 3, {A_Chase}, 0, 0, S_GOOMBA8, 0}, // S_GOOMBA7
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA9, 0}, // S_GOOMBA8
+	{SPR_GOOM, 1, 3, {A_Chase}, 0, 0, S_GOOMBA2, 0}, // S_GOOMBA9
+	{SPR_GOOM, 2, 16, {A_Scream}, 0, 0, S_NULL, 0},  // S_GOOMBA_DEAD
 
 	// Blue Goomba
-	{SPR_BGOM, 0, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1B}, // BLUEGOOMBA1
-	{SPR_BGOM, 1, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1},  // BLUEGOOMBA1B
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA3}, // S_BLUEGOOMBA2
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA4}, // S_BLUEGOOMBA3
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA5}, // S_BLUEGOOMBA4
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA6}, // S_BLUEGOOMBA5
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA7}, // S_BLUEGOOMBA6
-	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA8}, // S_BLUEGOOMBA7
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA9}, // S_BLUEGOOMBA8
-	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA2}, // S_BLUEGOOMBA9
-	{SPR_BGOM, 2, 16, {A_Scream}, 0, 0, S_NULL},      // S_BLUEGOOMBA_DEAD
+	{SPR_BGOM, 0, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1B, 0}, // S_BLUEGOOMBA1
+	{SPR_BGOM, 1, 6, {A_Look}, 0, 0, S_BLUEGOOMBA1, 0},  // S_BLUEGOOMBA1B
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA3, 0}, // S_BLUEGOOMBA2
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA4, 0}, // S_BLUEGOOMBA3
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA5, 0}, // S_BLUEGOOMBA4
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA6, 0}, // S_BLUEGOOMBA5
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA7, 0}, // S_BLUEGOOMBA6
+	{SPR_BGOM, 0, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA8, 0}, // S_BLUEGOOMBA7
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA9, 0}, // S_BLUEGOOMBA8
+	{SPR_BGOM, 1, 3, {A_Chase}, 0, 0, S_BLUEGOOMBA2, 0}, // S_BLUEGOOMBA9
+	{SPR_BGOM, 2, 16, {A_Scream}, 0, 0, S_NULL, 0},      // S_BLUEGOOMBA_DEAD
 
 	// Fire Flower
-	{SPR_FFWR, 0, 3, {NULL}, 0, 0, S_FIREFLOWER2}, // S_FIREFLOWER1
-	{SPR_FFWR, 1, 3, {NULL}, 0, 0, S_FIREFLOWER3}, // S_FIREFLOWER2
-	{SPR_FFWR, 2, 3, {NULL}, 0, 0, S_FIREFLOWER4}, // S_FIREFLOWER3
-	{SPR_FFWR, 3, 3, {NULL}, 0, 0, S_FIREFLOWER1}, // S_FIREFLOWER4
+	{SPR_FFWR, 0, 3, {NULL}, 0, 0, S_FIREFLOWER2, 0}, // S_FIREFLOWER1
+	{SPR_FFWR, 1, 3, {NULL}, 0, 0, S_FIREFLOWER3, 0}, // S_FIREFLOWER2
+	{SPR_FFWR, 2, 3, {NULL}, 0, 0, S_FIREFLOWER4, 0}, // S_FIREFLOWER3
+	{SPR_FFWR, 3, 3, {NULL}, 0, 0, S_FIREFLOWER1, 0}, // S_FIREFLOWER4
 
 	// Thrown Mario Fireball
-	{SPR_FBLL, FF_FULLBRIGHT,   1, {A_SpawnObjectRelative}, 0, MT_FIREBALLTRAIL, S_FIREBALL},   // S_FIREBALL
-	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 1, {A_SetScale}, FRACUNIT*3/4, 0, S_FIREBALLTRAIL2}, // S_FIREBALLTRAIL1
-	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 8, {A_SetScale}, FRACUNIT/6, 1, S_NULL},             // S_FIREBALLTRAIL2
+	{SPR_FBLL, FF_FULLBRIGHT,   1, {A_SpawnObjectRelative}, 0, MT_FIREBALLTRAIL, S_FIREBALL, 0},   // S_FIREBALL
+	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 1, {A_SetScale}, FRACUNIT*3/4, 0, S_FIREBALLTRAIL2, 0}, // S_FIREBALLTRAIL1
+	{SPR_FBLL, 1|FF_FULLBRIGHT|FF_TRANS50, 8, {A_SetScale}, FRACUNIT/6, 1, S_NULL, 0},             // S_FIREBALLTRAIL2
 
 	// Turtle Shell
-	{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHELL
+	{SPR_SHLL, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHELL
 
 	// Puma (Mario fireball)
-	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2},   // S_PUMA_START1
-	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1 + (1<<16), S_PUMA_UP1},   // S_PUMA_START2
-	{SPR_PUMA, FF_FULLBRIGHT  , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2},   // S_PUMA_UP1
-	{SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3},   // S_PUMA_UP2
-	{SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1},   // S_PUMA_UP3
-	{SPR_PUMA, FF_FULLBRIGHT|3, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN2}, // S_PUMA_DOWN1
-	{SPR_PUMA, FF_FULLBRIGHT|4, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN3}, // S_PUMA_DOWN2
-	{SPR_PUMA, FF_FULLBRIGHT|5, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN1}, // S_PUMA_DOWN3
-
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS20|6, 4,       {NULL},        0, 0, S_PUMATRAIL2},   // S_PUMATRAIL1
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS40|6, 5, {A_SetScale}, FRACUNIT, 1, S_PUMATRAIL3},   // S_PUMATRAIL2
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS50|7, 4,       {NULL},        0, 0, S_PUMATRAIL4},   // S_PUMATRAIL3
-	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS60|8, 3,       {NULL},        0, 0, S_NULL},         // S_PUMATRAIL4
+	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2, 0},   // S_PUMA_START1
+	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1 + (1<<16), S_PUMA_UP1, 0},   // S_PUMA_START2
+	{SPR_PUMA, FF_FULLBRIGHT  , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2, 0},   // S_PUMA_UP1
+	{SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3, 0},   // S_PUMA_UP2
+	{SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1, 0},   // S_PUMA_UP3
+	{SPR_PUMA, FF_FULLBRIGHT|3, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN2, 0}, // S_PUMA_DOWN1
+	{SPR_PUMA, FF_FULLBRIGHT|4, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN3, 0}, // S_PUMA_DOWN2
+	{SPR_PUMA, FF_FULLBRIGHT|5, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_DOWN1, 0}, // S_PUMA_DOWN3
+
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS20|6, 4,       {NULL},        0, 0, S_PUMATRAIL2, 0},   // S_PUMATRAIL1
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS40|6, 5, {A_SetScale}, FRACUNIT, 1, S_PUMATRAIL3, 0},   // S_PUMATRAIL2
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS50|7, 4,       {NULL},        0, 0, S_PUMATRAIL4, 0},   // S_PUMATRAIL3
+	{SPR_PUMA, FF_FULLBRIGHT|FF_TRANS60|8, 3,       {NULL},        0, 0, S_NULL, 0},         // S_PUMATRAIL4
 
 	// Hammer
-	{SPR_HAMM, FF_ANIMATE, -1, {NULL}, 3, 3, S_NULL}, // S_HAMMER
+	{SPR_HAMM, FF_ANIMATE, -1, {NULL}, 3, 3, S_NULL, 0}, // S_HAMMER
 
 	// Koopa
-	{SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL},   // S_KOOPA1
-	{SPR_KOOP, 1, 24, {NULL}, 0, 0, S_KOOPA1}, // S_KOOPA2
+	{SPR_KOOP, 0, -1, {NULL}, 0, 0, S_NULL, 0},   // S_KOOPA1
+	{SPR_KOOP, 1, 24, {NULL}, 0, 0, S_KOOPA1, 0}, // S_KOOPA2
 
-	{SPR_BFLM, 0, 3,{NULL}, 0, 0, S_KOOPAFLAME2}, // S_KOOPAFLAME1
-	{SPR_BFLM, 1, 3,{NULL}, 0, 0, S_KOOPAFLAME3}, // S_KOOPAFLAME2
-	{SPR_BFLM, 2, 3,{NULL}, 0, 0, S_KOOPAFLAME1}, // S_KOOPAFLAME3
+	{SPR_BFLM, 0, 3,{NULL}, 0, 0, S_KOOPAFLAME2, 0}, // S_KOOPAFLAME1
+	{SPR_BFLM, 1, 3,{NULL}, 0, 0, S_KOOPAFLAME3, 0}, // S_KOOPAFLAME2
+	{SPR_BFLM, 2, 3,{NULL}, 0, 0, S_KOOPAFLAME1, 0}, // S_KOOPAFLAME3
 
 	// Axe
-	{SPR_MAXE, 0, 3, {NULL}, 0, 0, S_AXE2}, // S_AXE1
-	{SPR_MAXE, 1, 3, {NULL}, 0, 0, S_AXE3}, // S_AXE2
-	{SPR_MAXE, 2, 3, {NULL}, 0, 0, S_AXE1}, // S_AXE3
+	{SPR_MAXE, 0, 3, {NULL}, 0, 0, S_AXE2, 0}, // S_AXE1
+	{SPR_MAXE, 1, 3, {NULL}, 0, 0, S_AXE3, 0}, // S_AXE2
+	{SPR_MAXE, 2, 3, {NULL}, 0, 0, S_AXE1, 0}, // S_AXE3
 
-	{SPR_MUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MARIOBUSH1
-	{SPR_MUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MARIOBUSH2
-	{SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_TOAD
+	{SPR_MUS1, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MARIOBUSH1
+	{SPR_MUS2, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_MARIOBUSH2
+	{SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_TOAD
 
 	// Nights Drone
-	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN2}, // S_NIGHTSDRONE_MAN1
-	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN1}, // S_NIGHTSDRONE_MAN2
+	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN2, 0}, // S_NIGHTSDRONE_MAN1
+	{SPR_NDRN, 0, -1, {NULL}, 0, 0, S_NIGHTSDRONE_MAN1, 0}, // S_NIGHTSDRONE_MAN2
 
 	// Sparkling point (RETURN TO THE GOAL, etc)
-	{SPR_IVSP, 0, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING2},   // S_NIGHTSDRONE_SPARKLING1
-	{SPR_IVSP, 2, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING3},   // S_NIGHTSDRONE_SPARKLING2
-	{SPR_IVSP, 4, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING4},   // S_NIGHTSDRONE_SPARKLING3
-	{SPR_IVSP, 6, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING5},   // S_NIGHTSDRONE_SPARKLING4
-	{SPR_IVSP, 8, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING6},  // S_NIGHTSDRONE_SPARKLING5
-	{SPR_IVSP, 10, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING7}, // S_NIGHTSDRONE_SPARKLING6
-	{SPR_IVSP, 12, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING8}, // S_NIGHTSDRONE_SPARKLING7
-	{SPR_IVSP, 14, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING9}, // S_NIGHTSDRONE_SPARKLING8
-	{SPR_IVSP, 16, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING10}, // S_NIGHTSDRONE_SPARKLING9
-	{SPR_IVSP, 18, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING11}, // S_NIGHTSDRONE_SPARKLING10
-	{SPR_IVSP, 20, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING12}, // S_NIGHTSDRONE_SPARKLING11
-	{SPR_IVSP, 22, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING13}, // S_NIGHTSDRONE_SPARKLING12
-	{SPR_IVSP, 24, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING14}, // S_NIGHTSDRONE_SPARKLING13
-	{SPR_IVSP, 26, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING15}, // S_NIGHTSDRONE_SPARKLING14
-	{SPR_IVSP, 28, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING16}, // S_NIGHTSDRONE_SPARKLING15
-	{SPR_IVSP, 30, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING1}, // S_NIGHTSDRONE_SPARKLING16
+	{SPR_IVSP, 0, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING2, 0},   // S_NIGHTSDRONE_SPARKLING1
+	{SPR_IVSP, 2, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING3, 0},   // S_NIGHTSDRONE_SPARKLING2
+	{SPR_IVSP, 4, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING4, 0},   // S_NIGHTSDRONE_SPARKLING3
+	{SPR_IVSP, 6, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING5, 0},   // S_NIGHTSDRONE_SPARKLING4
+	{SPR_IVSP, 8, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING6, 0},  // S_NIGHTSDRONE_SPARKLING5
+	{SPR_IVSP, 10, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING7, 0}, // S_NIGHTSDRONE_SPARKLING6
+	{SPR_IVSP, 12, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING8, 0}, // S_NIGHTSDRONE_SPARKLING7
+	{SPR_IVSP, 14, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING9, 0}, // S_NIGHTSDRONE_SPARKLING8
+	{SPR_IVSP, 16, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING10, 0}, // S_NIGHTSDRONE_SPARKLING9
+	{SPR_IVSP, 18, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING11, 0}, // S_NIGHTSDRONE_SPARKLING10
+	{SPR_IVSP, 20, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING12, 0}, // S_NIGHTSDRONE_SPARKLING11
+	{SPR_IVSP, 22, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING13, 0}, // S_NIGHTSDRONE_SPARKLING12
+	{SPR_IVSP, 24, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING14, 0}, // S_NIGHTSDRONE_SPARKLING13
+	{SPR_IVSP, 26, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING15, 0}, // S_NIGHTSDRONE_SPARKLING14
+	{SPR_IVSP, 28, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING16, 0}, // S_NIGHTSDRONE_SPARKLING15
+	{SPR_IVSP, 30, 1, {A_GhostMe}, 0, 0, S_NIGHTSDRONE_SPARKLING1, 0}, // S_NIGHTSDRONE_SPARKLING16
 
 	// NiGHTS GOAL banner (inside the sparkles!)
-	{SPR_GOAL, 0, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL2}, // S_NIGHTSDRONE_GOAL1
-	{SPR_GOAL, 1, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL3}, // S_NIGHTSDRONE_GOAL2
-	{SPR_GOAL, 2, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL4}, // S_NIGHTSDRONE_GOAL3
-	{SPR_GOAL, 3, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL1}, // S_NIGHTSDRONE_GOAL4
+	{SPR_GOAL, 0, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL2, 0}, // S_NIGHTSDRONE_GOAL1
+	{SPR_GOAL, 1, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL3, 0}, // S_NIGHTSDRONE_GOAL2
+	{SPR_GOAL, 2, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL4, 0}, // S_NIGHTSDRONE_GOAL3
+	{SPR_GOAL, 3, 4, {NULL}, 0, 0, S_NIGHTSDRONE_GOAL1, 0}, // S_NIGHTSDRONE_GOAL4
 
 	// Nights Sparkle
-	{SPR_NSPK, FF_FULLBRIGHT, 140, {NULL}, 0, 0, S_NIGHTSPARKLE2},   // S_NIGHTSPARKLE1
-	{SPR_NSPK, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_NIGHTSPARKLE3},   // S_NIGHTSPARKLE2
-	{SPR_NSPK, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_NIGHTSPARKLE4},   // S_NIGHTSPARKLE3
-	{SPR_NSPK, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_NULL},            // S_NIGHTSPARKLE4
+	{SPR_NSPK, FF_FULLBRIGHT, 140, {NULL}, 0, 0, S_NIGHTSPARKLE2, 0},   // S_NIGHTSPARKLE1
+	{SPR_NSPK, FF_FULLBRIGHT|1, 7, {NULL}, 0, 0, S_NIGHTSPARKLE3, 0},   // S_NIGHTSPARKLE2
+	{SPR_NSPK, FF_FULLBRIGHT|2, 7, {NULL}, 0, 0, S_NIGHTSPARKLE4, 0},   // S_NIGHTSPARKLE3
+	{SPR_NSPK, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_NULL, 0},            // S_NIGHTSPARKLE4
 
 	// Red Sparkle
-	{SPR_NSPK, FF_FULLBRIGHT|4, 140, {NULL}, 0, 0, S_NIGHTSPARKLESUPER2}, // S_NIGHTSPARKLESUPER1
-	{SPR_NSPK, FF_FULLBRIGHT|5, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER3},   // S_NIGHTSPARKLESUPER2
-	{SPR_NSPK, FF_FULLBRIGHT|6, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER4},   // S_NIGHTSPARKLESUPER3
-	{SPR_NSPK, FF_FULLBRIGHT|7, 7, {NULL}, 0, 0, S_NULL},                 // S_NIGHTSPARKLESUPER4
+	{SPR_NSPK, FF_FULLBRIGHT|4, 140, {NULL}, 0, 0, S_NIGHTSPARKLESUPER2, 0}, // S_NIGHTSPARKLESUPER1
+	{SPR_NSPK, FF_FULLBRIGHT|5, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER3, 0},   // S_NIGHTSPARKLESUPER2
+	{SPR_NSPK, FF_FULLBRIGHT|6, 7, {NULL}, 0, 0, S_NIGHTSPARKLESUPER4, 0},   // S_NIGHTSPARKLESUPER3
+	{SPR_NSPK, FF_FULLBRIGHT|7, 7, {NULL}, 0, 0, S_NULL, 0},                 // S_NIGHTSPARKLESUPER4
 
 	// Paraloop helper -- THIS IS WHAT DETERMINES THE TIMER NOW
-	{SPR_NULL, 0, 160, {NULL}, 0, 0, S_NULL}, // S_NIGHTSLOOPHELPER
+	{SPR_NULL, 0, 160, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSLOOPHELPER
 
 	// NiGHTS bumper
-	{SPR_NBMP, 0, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER1
-	{SPR_NBMP, 1, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER2
-	{SPR_NBMP, 2, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER3
-	{SPR_NBMP, 3, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER4
-	{SPR_NBMP, 4, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER5
-	{SPR_NBMP, 5, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER6
-	{SPR_NBMP, 6, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER7
-	{SPR_NBMP, 7, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER8
-	{SPR_NBMP, 8, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER9
-	{SPR_NBMP, 9, -1, {NULL}, 0, 0, S_NULL},  // S_NIGHTSBUMPER10
-	{SPR_NBMP, 10, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSBUMPER11
-	{SPR_NBMP, 11, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSBUMPER12
-
-	{SPR_HOOP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HOOP
-	{SPR_HOOP, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HOOP_XMASA
-	{SPR_HOOP, 2, -1, {NULL}, 0, 0, S_NULL}, // S_HOOP_XMASB
-
-	{SPR_NSCR, FF_FULLBRIGHT,    -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE10
-	{SPR_NSCR, FF_FULLBRIGHT|1,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE20
-	{SPR_NSCR, FF_FULLBRIGHT|2,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE30
-	{SPR_NSCR, FF_FULLBRIGHT|3,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE40
-	{SPR_NSCR, FF_FULLBRIGHT|4,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE50
-	{SPR_NSCR, FF_FULLBRIGHT|5,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE60
-	{SPR_NSCR, FF_FULLBRIGHT|6,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE70
-	{SPR_NSCR, FF_FULLBRIGHT|7,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE80
-	{SPR_NSCR, FF_FULLBRIGHT|8,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90
-	{SPR_NSCR, FF_FULLBRIGHT|9,  -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100
-	{SPR_NSCR, FF_FULLBRIGHT|10, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE10_2
-	{SPR_NSCR, FF_FULLBRIGHT|11, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE20_2
-	{SPR_NSCR, FF_FULLBRIGHT|12, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE30_2
-	{SPR_NSCR, FF_FULLBRIGHT|13, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE40_2
-	{SPR_NSCR, FF_FULLBRIGHT|14, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE50_2
-	{SPR_NSCR, FF_FULLBRIGHT|15, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE60_2
-	{SPR_NSCR, FF_FULLBRIGHT|16, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE70_2
-	{SPR_NSCR, FF_FULLBRIGHT|17, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE80_2
-	{SPR_NSCR, FF_FULLBRIGHT|18, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90_2
-	{SPR_NSCR, FF_FULLBRIGHT|19, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100_2
+	{SPR_NBMP, 0, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER1
+	{SPR_NBMP, 1, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER2
+	{SPR_NBMP, 2, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER3
+	{SPR_NBMP, 3, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER4
+	{SPR_NBMP, 4, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER5
+	{SPR_NBMP, 5, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER6
+	{SPR_NBMP, 6, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER7
+	{SPR_NBMP, 7, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER8
+	{SPR_NBMP, 8, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER9
+	{SPR_NBMP, 9, -1, {NULL}, 0, 0, S_NULL, 0},  // S_NIGHTSBUMPER10
+	{SPR_NBMP, 10, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSBUMPER11
+	{SPR_NBMP, 11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSBUMPER12
+
+	{SPR_HOOP, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HOOP
+	{SPR_HOOP, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HOOP_XMASA
+	{SPR_HOOP, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_HOOP_XMASB
+
+	{SPR_NSCR, FF_FULLBRIGHT,    -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE10
+	{SPR_NSCR, FF_FULLBRIGHT|1,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE20
+	{SPR_NSCR, FF_FULLBRIGHT|2,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE30
+	{SPR_NSCR, FF_FULLBRIGHT|3,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE40
+	{SPR_NSCR, FF_FULLBRIGHT|4,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE50
+	{SPR_NSCR, FF_FULLBRIGHT|5,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE60
+	{SPR_NSCR, FF_FULLBRIGHT|6,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE70
+	{SPR_NSCR, FF_FULLBRIGHT|7,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE80
+	{SPR_NSCR, FF_FULLBRIGHT|8,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE90
+	{SPR_NSCR, FF_FULLBRIGHT|9,  -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE100
+	{SPR_NSCR, FF_FULLBRIGHT|10, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE10_2
+	{SPR_NSCR, FF_FULLBRIGHT|11, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE20_2
+	{SPR_NSCR, FF_FULLBRIGHT|12, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE30_2
+	{SPR_NSCR, FF_FULLBRIGHT|13, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE40_2
+	{SPR_NSCR, FF_FULLBRIGHT|14, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE50_2
+	{SPR_NSCR, FF_FULLBRIGHT|15, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE60_2
+	{SPR_NSCR, FF_FULLBRIGHT|16, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE70_2
+	{SPR_NSCR, FF_FULLBRIGHT|17, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE80_2
+	{SPR_NSCR, FF_FULLBRIGHT|18, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE90_2
+	{SPR_NSCR, FF_FULLBRIGHT|19, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSCORE100_2
 
 	// NiGHTS Paraloop Powerups
-	{SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSUPERLOOP
-	{SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSDRILLREFILL
-	{SPR_NPRU, 2, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSHELPER
-	{SPR_NPRU, 3, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSEXTRATIME
-	{SPR_NPRU, 4, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSLINKFREEZE
+	{SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSSUPERLOOP
+	{SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSDRILLREFILL
+	{SPR_NPRU, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSHELPER
+	{SPR_NPRU, 3, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSEXTRATIME
+	{SPR_NPRU, 4, -1, {NULL}, 0, 0, S_NULL, 0}, // S_NIGHTSLINKFREEZE
 
-	{SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGCAPSULE
+	{SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_EGGCAPSULE
 
 	// Orbiting Chaos Emeralds/Ideya for NiGHTS
-	{SPR_CEMG, FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1
-	{SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2
-	{SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3
-	{SPR_CEMG, FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4
-	{SPR_CEMG, FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5
-	{SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6
-	{SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7
-	{SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1}, // S_ORBIDYA1
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2}, // S_ORBIDYA2
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3}, // S_ORBIDYA3
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA4}, // S_ORBIDYA4
-	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA5}, // S_ORBIDYA5
+	{SPR_CEMG, FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1, 0}, // S_ORBITEM1
+	{SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2, 0}, // S_ORBITEM2
+	{SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3, 0}, // S_ORBITEM3
+	{SPR_CEMG, FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4, 0}, // S_ORBITEM4
+	{SPR_CEMG, FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5, 0}, // S_ORBITEM5
+	{SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6, 0}, // S_ORBITEM6
+	{SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7, 0}, // S_ORBITEM7
+	{SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8, 0}, // S_ORBITEM8
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT,   1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1, 0}, // S_ORBIDYA1
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2, 0}, // S_ORBIDYA2
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3, 0}, // S_ORBIDYA3
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA4, 0}, // S_ORBIDYA4
+	{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA5, 0}, // S_ORBIDYA5
 
 	// Flicky helper for NiGHTS
-	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER2}, // S_NIGHTOPIANHELPER1
-	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER3}, // S_NIGHTOPIANHELPER2
-	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER4}, // S_NIGHTOPIANHELPER3
-	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER5}, // S_NIGHTOPIANHELPER4
-	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER6}, // S_NIGHTOPIANHELPER5
-	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER7}, // S_NIGHTOPIANHELPER6
-	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER8}, // S_NIGHTOPIANHELPER7
-	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER9}, // S_NIGHTOPIANHELPER8
-	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1}, // S_NIGHTOPIANHELPER9
+	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER2, 0}, // S_NIGHTOPIANHELPER1
+	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER3, 0}, // S_NIGHTOPIANHELPER2
+	{SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER4, 0}, // S_NIGHTOPIANHELPER3
+	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER5, 0}, // S_NIGHTOPIANHELPER4
+	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER6, 0}, // S_NIGHTOPIANHELPER5
+	{SPR_FL01, 2, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER7, 0}, // S_NIGHTOPIANHELPER6
+	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER8, 0}, // S_NIGHTOPIANHELPER7
+	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER9, 0}, // S_NIGHTOPIANHELPER8
+	{SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1, 0}, // S_NIGHTOPIANHELPER9
 
 	// Nightopian
-	{SPR_NTPN, 0, 2, {A_Look}, 1, 1, S_PIAN_LOOK2}, // S_PIAN_LOOK1
-	{SPR_NTPN, 1, 2, {A_Look}, 1, 1, S_PIAN_LOOK3}, // S_PIAN_LOOK2
-	{SPR_NTPN, 2, 2, {A_Look}, 1, 1, S_PIAN_LOOK1}, // S_PIAN_LOOK3
-	{SPR_NTPN, 0, 2, {A_JetgThink}, 0, 0, S_PIAN_FLY2}, // S_PIAN_FLY1
-	{SPR_NTPN, 1, 2, {NULL}, 0, 0, S_PIAN_FLY3}, // S_PIAN_FLY2
-	{SPR_NTPN, 2, 2, {NULL}, 0, 0, S_PIAN_FLY1}, // S_PIAN_FLY3
-	{SPR_NTPN, 3|FF_ANIMATE, 24, {NULL}, 2, 2, S_PIAN_FLY1}, // S_PIAN_SING
+	{SPR_NTPN, 0, 2, {A_Look}, 1, 1, S_PIAN_LOOK2, 0}, // S_PIAN_LOOK1
+	{SPR_NTPN, 1, 2, {A_Look}, 1, 1, S_PIAN_LOOK3, 0}, // S_PIAN_LOOK2
+	{SPR_NTPN, 2, 2, {A_Look}, 1, 1, S_PIAN_LOOK1, 0}, // S_PIAN_LOOK3
+	{SPR_NTPN, 0, 2, {A_JetgThink}, 0, 0, S_PIAN_FLY2, 0}, // S_PIAN_FLY1
+	{SPR_NTPN, 1, 2, {NULL}, 0, 0, S_PIAN_FLY3, 0}, // S_PIAN_FLY2
+	{SPR_NTPN, 2, 2, {NULL}, 0, 0, S_PIAN_FLY1, 0}, // S_PIAN_FLY3
+	{SPR_NTPN, 3|FF_ANIMATE, 24, {NULL}, 2, 2, S_PIAN_FLY1, 0}, // S_PIAN_SING
 
 	// Shleep
-	{SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2}, // S_SHLEEP1
-	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP3}, // S_SHLEEP2
-	{SPR_SHLP, 2, 15, {NULL}, 0, 0, S_SHLEEP4}, // S_SHLEEP3
-	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP1}, // S_SHLEEP4
-	{SPR_SHLP, 3, 1, {A_Scream},  0, 0, S_SHLEEPBOUNCE2}, // S_SHLEEPBOUNCE1
-	{SPR_SHLP, 3, 1, {A_ZThrust}, 9, 0, S_SHLEEPBOUNCE3}, // S_SHLEEPBOUNCE2
-	{SPR_SHLP, 3, 400, {A_SetObjectFlags}, MF_SLIDEME|MF_ENEMY|MF_BOUNCE|MF_NOCLIP|MF_NOCLIPHEIGHT, 0, S_NULL}, // S_SHLEEPBOUNCE3
+	{SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2, 0}, // S_SHLEEP1
+	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP3, 0}, // S_SHLEEP2
+	{SPR_SHLP, 2, 15, {NULL}, 0, 0, S_SHLEEP4, 0}, // S_SHLEEP3
+	{SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP1, 0}, // S_SHLEEP4
+	{SPR_SHLP, 3, 1, {A_Scream},  0, 0, S_SHLEEPBOUNCE2, 0}, // S_SHLEEPBOUNCE1
+	{SPR_SHLP, 3, 1, {A_ZThrust}, 9, 0, S_SHLEEPBOUNCE3, 0}, // S_SHLEEPBOUNCE2
+	{SPR_SHLP, 3, 400, {A_SetObjectFlags}, MF_SLIDEME|MF_ENEMY|MF_BOUNCE|MF_NOCLIP|MF_NOCLIPHEIGHT, 0, S_NULL, 0}, // S_SHLEEPBOUNCE3
 
 	// Secret badniks and hazards, shhhh
-	{SPR_PENG, 0, 2, {A_Look},  0, 0, S_PENGUINATOR_LOOK},    // S_PENGUINATOR_LOOK
-	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE2}, // S_PENGUINATOR_WADDLE1
-	{SPR_PENG, 1, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE3}, // S_PENGUINATOR_WADDLE2
-	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE4}, // S_PENGUINATOR_WADDLE3
-	{SPR_PENG, 2, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE1}, // S_PENGUINATOR_WADDLE4
-	{SPR_PENG, 0,  0, {A_FaceTarget},      0,  0, S_PENGUINATOR_SLIDE2}, // S_PENGUINATOR_SLIDE1
-	{SPR_PENG, 3,  5, {A_BunnyHop},        4, 10, S_PENGUINATOR_SLIDE3}, // S_PENGUINATOR_SLIDE2
-	{SPR_PENG, 4, 90, {A_PlayAttackSound}, 0,  0, S_PENGUINATOR_SLIDE4}, // S_PENGUINATOR_SLIDE3
-	{SPR_PENG, 3,  5, {A_Thrust},          0,  1, S_PENGUINATOR_SLIDE5}, // S_PENGUINATOR_SLIDE4
-	{SPR_PENG, 0,  5, {A_FaceTarget},      0,  0, S_PENGUINATOR_LOOK},   // S_PENGUINATOR_SLIDE5
-
-	{SPR_POPH, 0,  2, {A_Look},  (2048<<16)|1,           0, S_POPHAT_LOOK},   // S_POPHAT_LOOK
-	{SPR_POPH, 1,  0, {A_MultiShotDist}, (MT_SPINDUST<<16)|4, 24, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1
-	{SPR_POPH, 1,  2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2
-	{SPR_POPH, 2,  1, {NULL},               0,           0, S_POPHAT_SHOOT4}, // S_POPHAT_SHOOT3
-	{SPR_POPH, 0, 57, {NULL},               0,           0, S_POPHAT_LOOK},   // S_POPHAT_SHOOT4
-	{SPR_POPH, 3,  3, {A_SpawnObjectRelative}, 0, MT_POPSHOT_TRAIL, S_POPSHOT},   // S_POPSHOT
-	{SPR_NULL, 0,  2, {NULL},                  0, 0,                S_SPINDUST1}, // S_POPSHOT_TRAIL
-
-	{SPR_HIVE, 0,  5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK
-	{SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1
-	{SPR_HIVE, 0,  6, {A_PlaySound}, sfx_s3k8c, 1, S_HIVEELEMENTAL_SHOOT1}, // S_HIVEELEMENTAL_PREPARE2
-	{SPR_HIVE, 1,  4, {A_WhoCaresIfYourSonIsABee}, (MT_BUMBLEBORE<<16)|4, (1<<16)|32, S_HIVEELEMENTAL_SHOOT2}, // S_HIVEELEMENTAL_SHOOT1
-	{SPR_HIVE, 2,  2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_SHOOT2
-	{SPR_HIVE, 0,  5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_DORMANT
-	{SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_PAIN
-	{SPR_HIVE, 3,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE2}, // S_HIVEELEMENTAL_DIE1
-	{SPR_NULL, 0,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE3}, // S_HIVEELEMENTAL_DIE2
-	{SPR_NULL, 0,  0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY}, // S_HIVEELEMENTAL_DIE3
-
-	{SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_SPAWN
-	{SPR_BUMB, 0,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK2}, // S_BUMBLEBORE_LOOK1
-	{SPR_BUMB, 1,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_LOOK2
-	{SPR_BUMB, 0,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY2}, // S_BUMBLEBORE_FLY1
-	{SPR_BUMB, 1,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY1}, // S_BUMBLEBORE_FLY2
-	{SPR_BUMB, 2|FF_FULLBRIGHT,  12, {A_ZThrust},  4, (1<<16)|1, S_BUMBLEBORE_FALL1},  // S_BUMBLEBORE_RAISE
-	{SPR_BUMB, 2|FF_FULLBRIGHT,   0, {A_ZThrust}, -8, (1<<16)|1, S_BUMBLEBORE_FALL2},  // S_BUMBLEBORE_FALL1
-	{SPR_BUMB, 2|FF_FULLBRIGHT, 300, {NULL},       0,         0, S_BUMBLEBORE_DIE},    // S_BUMBLEBORE_FALL2
-	{SPR_BUMB, 4, 3, {A_MultiShotDist}, (MT_DUST<<16)|6, -40, S_BUMBLEBORE_STUCK2},    // S_BUMBLEBORE_STUCK1
-	{SPR_BUMB, 5, 120, {NULL}, 0, 0, S_BUMBLEBORE_DIE}, // S_BUMBLEBORE_STUCK2
-	{SPR_BUMB, 5, 0, {A_CryingToMomma}, 0, 0, S_XPLD1}, // S_BUMBLEBORE_DIE
-
-	{SPR_BBUZ,          0, -1, {NULL}, 0, 0, S_NULL}, // S_BUGGLEIDLE
-	{SPR_BBUZ, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL}, // S_BUGGLEFLY
-
-	{SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT
-	{SPR_FMCE, 0,  4, {A_ZThrust},  4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1
-	{SPR_FMCE, 0,  4, {A_ZThrust},  0, (1<<16)|1, S_SMASHSPIKE_FALL},  // S_SMASHSPIKE_EASE2
-	{SPR_FMCE, 0,  2, {A_ZThrust}, -6,         1, S_SMASHSPIKE_FALL},  // S_SMASHSPIKE_FALL
-	{SPR_FMCE, 1,  2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1
-	{SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2
-	{SPR_FMCE, 1,  2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1
-	{SPR_FMCE, 0,  2, {A_ZThrust}, 6, (1<<16)|1, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE2
-
-	{SPR_CACO, 0,  5, {A_Look}, (1100<<16)|1, 0, S_CACO_LOOK}, // S_CACO_LOOK
-	{SPR_CACO, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|7, -48, S_CACO_WAKE2}, // S_CACO_WAKE1
-	{SPR_CACO, 1, 10, {A_ZThrust}, 4, (1<<16)|1, S_CACO_WAKE3}, // S_CACO_WAKE2
-	{SPR_CACO, 2,  8, {A_ZThrust}, 2, (1<<16)|1, S_CACO_WAKE4}, // S_CACO_WAKE3
-	{SPR_CACO, 2,  4, {A_ZThrust}, 0, (1<<16)|1, S_CACO_ROAR},  // S_CACO_WAKE4
-	{SPR_CACO, 2, 10, {A_PlayActiveSound}, 0, 0, S_CACO_CHASE}, // S_CACO_ROAR
-	{SPR_CACO, 2,  5, {A_JetChase}, 0, 0, S_CACO_CHASE_REPEAT}, // S_CACO_CHASE
-	{SPR_CACO, 2,  0, {A_Repeat}, 5, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_CHASE_REPEAT
-	{SPR_CACO, 2,  0, {A_RandomState}, S_CACO_PREPARE_SOUND, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_RANDOM
-	{SPR_CACO, 2,  8, {A_PlaySound}, sfx_s3k95, 1, S_CACO_PREPARE1},  // S_CACO_PREPARE_SOUND
-	{SPR_CACO, 3,               8, {NULL}, 0, 0, S_CACO_PREPARE2},    // S_CACO_PREPARE1
-	{SPR_CACO, 4|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_PREPARE3},    // S_CACO_PREPARE2
-	{SPR_CACO, 5|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_SHOOT_SOUND}, // S_CACO_PREPARE3
-	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_PlaySound}, sfx_s3k4e, 1, S_CACO_SHOOT1}, // S_CACO_SHOOT_SOUND
-	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_CACOFIRE_EXPLODE1, S_CACO_SHOOT2}, // S_CACO_SHOOT1
-	{SPR_CACO, 4|FF_FULLBRIGHT, 6, {A_FireShot}, MT_CACOFIRE, -24, S_CACO_CLOSE}, // S_CACO_SHOOT2
-	{SPR_CACO, 3,              15, {NULL}, 0, 0, S_CACO_CHASE}, // S_CACO_CLOSE
-	{SPR_CACO, 10, 0, {A_SetObjectFlags}, MF_NOBLOCKMAP, 0, S_CACO_DIE_GIB1}, // S_CACO_DIE_FLAGS
-	{SPR_CACO, 10, 0, {A_NapalmScatter}, (7<<16)|MT_CACOSHARD, (30<<16)|20, S_CACO_DIE_GIB2}, // S_CACO_DIE_GIB1
-	{SPR_CACO, 10, 0, {A_NapalmScatter}, (10<<16)|MT_CACOSHARD, (24<<16)|32, S_CACO_DIE_SCREAM}, // S_CACO_DIE_GIB2
-	{SPR_CACO, 10, 0, {A_Scream}, 0, 0, S_CACO_DIE_SHATTER}, // S_CACO_DIE_SCREAM
-	{SPR_CACO, 10, 0, {A_PlaySound}, sfx_pumpkn, 1, S_CACO_DIE_FALL}, // S_CACO_DIE_SHATTER
-	{SPR_CACO, 10, 250, {A_FlickySpawn}, (1<<16), 0, S_NULL}, // S_CACO_DIE_FALL
-
-	{SPR_CACO, 6, 0, {A_RandomState}, S_CACOSHARD1_1, S_CACOSHARD2_1, S_NULL}, // S_CACOSHARD_RANDOMIZE
-	{SPR_CACO, 6, 3, {NULL}, 0, 0, S_CACOSHARD1_2}, // S_CACOSHARD1_1
-	{SPR_CACO, 7, 3, {NULL}, 0, 0, S_CACOSHARD1_1}, // S_CACOSHARD1_2
-	{SPR_CACO, 8, 3, {NULL}, 0, 0, S_CACOSHARD2_2}, // S_CACOSHARD2_1
-	{SPR_CACO, 9, 3, {NULL}, 0, 0, S_CACOSHARD2_1}, // S_CACOSHARD2_2
-	{SPR_BAL2,   FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE2}, // S_CACOFIRE1
-	{SPR_BAL2, 1|FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE3}, // S_CACOFIRE2
-	{SPR_BAL2,   FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CACOFIRE1}, // S_CACOFIRE3
-	{SPR_BAL2, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE2}, // S_CACOFIRE_EXPLODE1
-	{SPR_BAL2, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE3}, // S_CACOFIRE_EXPLODE2
-	{SPR_BAL2, 4|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE4}, // S_CACOFIRE_EXPLODE3
-	{SPR_BAL2, 5|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL},      // S_CACOFIRE_EXPLODE4
-
-	{SPR_SBOB, 1, 10, {A_ZThrust}, -2, (1<<16)|1, S_SPINBOBERT_MOVE_UP},       // S_SPINBOBERT_MOVE_FLIPUP
-	{SPR_SBOB, 0, 45, {A_ZThrust},  4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPDOWN}, // S_SPINBOBERT_MOVE_UP
-	{SPR_SBOB, 1, 10, {A_ZThrust},  2, (1<<16)|1, S_SPINBOBERT_MOVE_DOWN},     // S_SPINBOBERT_MOVE_FLIPDOWN
-	{SPR_SBOB, 2, 45, {A_ZThrust}, -4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPUP},   // S_SPINBOBERT_MOVE_DOWN
-	{SPR_SBSK, FF_FULLBRIGHT, 1, {A_RotateSpikeBall},       0,                        0, S_SPINBOBERT_FIRE_GHOST}, // S_SPINBOBERT_FIRE_MOVE
-	{SPR_SBSK, FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_SPINBOBERT_FIRE_TRAIL1, S_SPINBOBERT_FIRE_MOVE},  // S_SPINBOBERT_FIRE_GHOST
-	{SPR_SBFL, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL2}, // S_SPINBOBERT_FIRE_TRAIL1
-	{SPR_SBFL, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL3}, // S_SPINBOBERT_FIRE_TRAIL2
-	{SPR_SBFL,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL},                   // S_SPINBOBERT_FIRE_TRAIL3
-
-	{SPR_HBAT, 0,  5, {A_Look}, (900<<16)|1, 0, S_HANGSTER_LOOK}, // S_HANGSTER_LOOK
-	{SPR_HBAT, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|10, -34, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP1
-	{SPR_HBAT, 1,  2, {A_ZThrust}, -8, (1<<16)|1, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP2
-	{SPR_HBAT, 1,  6, {A_ZThrust}, -5, (1<<16), S_HANGSTER_ARC2}, // S_HANGSTER_ARC1
-	{SPR_HBAT, 1,  5, {A_ZThrust}, -2, (1<<16), S_HANGSTER_ARC3}, // S_HANGSTER_ARC2
-	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_FLY1}, // S_HANGSTER_ARC3
-	{SPR_HBAT, 1,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY2}, // S_HANGSTER_FLY1
-	{SPR_HBAT, 2,  1, {A_PlaySound}, sfx_s3k52, 1, S_HANGSTER_FLY3}, // S_HANGSTER_FLY2
-	{SPR_HBAT, 3,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY4}, // S_HANGSTER_FLY3
-	{SPR_HBAT, 2,  1, {A_Thrust}, 6, 1, S_HANGSTER_FLYREPEAT}, // S_HANGSTER_FLY4
-	{SPR_HBAT, 2,  0, {A_Repeat}, 12, S_HANGSTER_FLY1, S_HANGSTER_ARCUP1}, // S_HANGSTER_FLYREPEAT
-	{SPR_HBAT, 1,  5, {A_ZThrust},  2, (1<<16), S_HANGSTER_ARCUP2}, // S_HANGSTER_ARCUP1
-	{SPR_HBAT, 1,  6, {A_ZThrust},  5, (1<<16), S_HANGSTER_ARCUP3}, // S_HANGSTER_ARCUP2
-	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_RETURN1}, // S_HANGSTER_ARCUP3
-	{SPR_HBAT, 1,  1, {A_ZThrust},  8, (1<<16), S_HANGSTER_RETURN2}, // S_HANGSTER_RETURN1
-	{SPR_HBAT, 3,  1, {NULL}, 0, 0, S_HANGSTER_RETURN1}, // S_HANGSTER_RETURN2
-	{SPR_HBAT, 0, 15, {NULL}, 0, 0, S_HANGSTER_LOOK}, // S_HANGSTER_RETURN3
-
-	{SPR_NULL, 0,  35, {NULL}, 0, 0, S_CRUMBLE2}, // S_CRUMBLE1
-	{SPR_NULL, 0, 105, {A_Scream}, 0, 0, S_NULL}, // S_CRUMBLE2
+	{SPR_PENG, 0, 2, {A_Look},  0, 0, S_PENGUINATOR_LOOK, 0},    // S_PENGUINATOR_LOOK
+	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE2, 0}, // S_PENGUINATOR_WADDLE1
+	{SPR_PENG, 1, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE3, 0}, // S_PENGUINATOR_WADDLE2
+	{SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE4, 0}, // S_PENGUINATOR_WADDLE3
+	{SPR_PENG, 2, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE1, 0}, // S_PENGUINATOR_WADDLE4
+	{SPR_PENG, 0,  0, {A_FaceTarget},      0,  0, S_PENGUINATOR_SLIDE2, 0}, // S_PENGUINATOR_SLIDE1
+	{SPR_PENG, 3,  5, {A_BunnyHop},        4, 10, S_PENGUINATOR_SLIDE3, 0}, // S_PENGUINATOR_SLIDE2
+	{SPR_PENG, 4, 90, {A_PlayAttackSound}, 0,  0, S_PENGUINATOR_SLIDE4, 0}, // S_PENGUINATOR_SLIDE3
+	{SPR_PENG, 3,  5, {A_Thrust},          0,  1, S_PENGUINATOR_SLIDE5, 0}, // S_PENGUINATOR_SLIDE4
+	{SPR_PENG, 0,  5, {A_FaceTarget},      0,  0, S_PENGUINATOR_LOOK, 0},   // S_PENGUINATOR_SLIDE5
+
+	{SPR_POPH, 0,  2, {A_Look},  (2048<<16)|1,           0, S_POPHAT_LOOK, 0},   // S_POPHAT_LOOK
+	{SPR_POPH, 1,  0, {A_MultiShotDist}, (MT_SPINDUST<<16)|4, 24, S_POPHAT_SHOOT2, 0}, // S_POPHAT_SHOOT1
+	{SPR_POPH, 1,  2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT3, 0}, // S_POPHAT_SHOOT2
+	{SPR_POPH, 2,  1, {NULL},               0,           0, S_POPHAT_SHOOT4, 0}, // S_POPHAT_SHOOT3
+	{SPR_POPH, 0, 57, {NULL},               0,           0, S_POPHAT_LOOK, 0},   // S_POPHAT_SHOOT4
+	{SPR_POPH, 3,  3, {A_SpawnObjectRelative}, 0, MT_POPSHOT_TRAIL, S_POPSHOT, 0},   // S_POPSHOT
+	{SPR_NULL, 0,  2, {NULL},                  0, 0,                S_SPINDUST1, 0}, // S_POPSHOT_TRAIL
+
+	{SPR_HIVE, 0,  5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK, 0}, // S_HIVEELEMENTAL_LOOK
+	{SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2, 0}, // S_HIVEELEMENTAL_PREPARE1
+	{SPR_HIVE, 0,  6, {A_PlaySound}, sfx_s3k8c, 1, S_HIVEELEMENTAL_SHOOT1, 0}, // S_HIVEELEMENTAL_PREPARE2
+	{SPR_HIVE, 1,  4, {A_WhoCaresIfYourSonIsABee}, (MT_BUMBLEBORE<<16)|4, (1<<16)|32, S_HIVEELEMENTAL_SHOOT2, 0}, // S_HIVEELEMENTAL_SHOOT1
+	{SPR_HIVE, 2,  2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT, 0}, // S_HIVEELEMENTAL_SHOOT2
+	{SPR_HIVE, 0,  5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT, 0}, // S_HIVEELEMENTAL_DORMANT
+	{SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK, 0}, // S_HIVEELEMENTAL_PAIN
+	{SPR_HIVE, 3,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE2, 0}, // S_HIVEELEMENTAL_DIE1
+	{SPR_NULL, 0,  2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE3, 0}, // S_HIVEELEMENTAL_DIE2
+	{SPR_NULL, 0,  0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY, 0}, // S_HIVEELEMENTAL_DIE3
+
+	{SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1, 0}, // S_BUMBLEBORE_SPAWN
+	{SPR_BUMB, 0,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK2, 0}, // S_BUMBLEBORE_LOOK1
+	{SPR_BUMB, 1,  4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK1, 0}, // S_BUMBLEBORE_LOOK2
+	{SPR_BUMB, 0,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY2, 0}, // S_BUMBLEBORE_FLY1
+	{SPR_BUMB, 1,  4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY1, 0}, // S_BUMBLEBORE_FLY2
+	{SPR_BUMB, 2|FF_FULLBRIGHT,  12, {A_ZThrust},  4, (1<<16)|1, S_BUMBLEBORE_FALL1, 0},  // S_BUMBLEBORE_RAISE
+	{SPR_BUMB, 2|FF_FULLBRIGHT,   0, {A_ZThrust}, -8, (1<<16)|1, S_BUMBLEBORE_FALL2, 0},  // S_BUMBLEBORE_FALL1
+	{SPR_BUMB, 2|FF_FULLBRIGHT, 300, {NULL},       0,         0, S_BUMBLEBORE_DIE, 0},    // S_BUMBLEBORE_FALL2
+	{SPR_BUMB, 4, 3, {A_MultiShotDist}, (MT_DUST<<16)|6, -40, S_BUMBLEBORE_STUCK2, 0},    // S_BUMBLEBORE_STUCK1
+	{SPR_BUMB, 5, 120, {NULL}, 0, 0, S_BUMBLEBORE_DIE, 0}, // S_BUMBLEBORE_STUCK2
+	{SPR_BUMB, 5, 0, {A_CryingToMomma}, 0, 0, S_XPLD1, 0}, // S_BUMBLEBORE_DIE
+
+	{SPR_BBUZ,          0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BUGGLEIDLE
+	{SPR_BBUZ, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL, 0}, // S_BUGGLEFLY
+
+	{SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1, 0}, // S_SMASHSPIKE_FLOAT
+	{SPR_FMCE, 0,  4, {A_ZThrust},  4, (1<<16)|1, S_SMASHSPIKE_EASE2, 0}, // S_SMASHSPIKE_EASE1
+	{SPR_FMCE, 0,  4, {A_ZThrust},  0, (1<<16)|1, S_SMASHSPIKE_FALL, 0},  // S_SMASHSPIKE_EASE2
+	{SPR_FMCE, 0,  2, {A_ZThrust}, -6,         1, S_SMASHSPIKE_FALL, 0},  // S_SMASHSPIKE_FALL
+	{SPR_FMCE, 1,  2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2, 0}, // S_SMASHSPIKE_STOMP1
+	{SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1, 0}, // S_SMASHSPIKE_STOMP2
+	{SPR_FMCE, 1,  2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2, 0}, // S_SMASHSPIKE_RISE1
+	{SPR_FMCE, 0,  2, {A_ZThrust}, 6, (1<<16)|1, S_SMASHSPIKE_RISE2, 0}, // S_SMASHSPIKE_RISE2
+
+	{SPR_CACO, 0,  5, {A_Look}, (1100<<16)|1, 0, S_CACO_LOOK, 0}, // S_CACO_LOOK
+	{SPR_CACO, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|7, -48, S_CACO_WAKE2, 0}, // S_CACO_WAKE1
+	{SPR_CACO, 1, 10, {A_ZThrust}, 4, (1<<16)|1, S_CACO_WAKE3, 0}, // S_CACO_WAKE2
+	{SPR_CACO, 2,  8, {A_ZThrust}, 2, (1<<16)|1, S_CACO_WAKE4, 0}, // S_CACO_WAKE3
+	{SPR_CACO, 2,  4, {A_ZThrust}, 0, (1<<16)|1, S_CACO_ROAR, 0},  // S_CACO_WAKE4
+	{SPR_CACO, 2, 10, {A_PlayActiveSound}, 0, 0, S_CACO_CHASE, 0}, // S_CACO_ROAR
+	{SPR_CACO, 2,  5, {A_JetChase}, 0, 0, S_CACO_CHASE_REPEAT, 0}, // S_CACO_CHASE
+	{SPR_CACO, 2,  0, {A_Repeat}, 5, S_CACO_CHASE, S_CACO_RANDOM, 0}, // S_CACO_CHASE_REPEAT
+	{SPR_CACO, 2,  0, {A_RandomState}, S_CACO_PREPARE_SOUND, S_CACO_CHASE, S_CACO_RANDOM, 0}, // S_CACO_RANDOM
+	{SPR_CACO, 2,  8, {A_PlaySound}, sfx_s3k95, 1, S_CACO_PREPARE1, 0},  // S_CACO_PREPARE_SOUND
+	{SPR_CACO, 3,               8, {NULL}, 0, 0, S_CACO_PREPARE2, 0},    // S_CACO_PREPARE1
+	{SPR_CACO, 4|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_PREPARE3, 0},    // S_CACO_PREPARE2
+	{SPR_CACO, 5|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_SHOOT_SOUND, 0}, // S_CACO_PREPARE3
+	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_PlaySound}, sfx_s3k4e, 1, S_CACO_SHOOT1, 0}, // S_CACO_SHOOT_SOUND
+	{SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_CACOFIRE_EXPLODE1, S_CACO_SHOOT2, 0}, // S_CACO_SHOOT1
+	{SPR_CACO, 4|FF_FULLBRIGHT, 6, {A_FireShot}, MT_CACOFIRE, -24, S_CACO_CLOSE, 0}, // S_CACO_SHOOT2
+	{SPR_CACO, 3,              15, {NULL}, 0, 0, S_CACO_CHASE, 0}, // S_CACO_CLOSE
+	{SPR_CACO, 10, 0, {A_SetObjectFlags}, MF_NOBLOCKMAP, 0, S_CACO_DIE_GIB1, 0}, // S_CACO_DIE_FLAGS
+	{SPR_CACO, 10, 0, {A_NapalmScatter}, (7<<16)|MT_CACOSHARD, (30<<16)|20, S_CACO_DIE_GIB2, 0}, // S_CACO_DIE_GIB1
+	{SPR_CACO, 10, 0, {A_NapalmScatter}, (10<<16)|MT_CACOSHARD, (24<<16)|32, S_CACO_DIE_SCREAM, 0}, // S_CACO_DIE_GIB2
+	{SPR_CACO, 10, 0, {A_Scream}, 0, 0, S_CACO_DIE_SHATTER, 0}, // S_CACO_DIE_SCREAM
+	{SPR_CACO, 10, 0, {A_PlaySound}, sfx_pumpkn, 1, S_CACO_DIE_FALL, 0}, // S_CACO_DIE_SHATTER
+	{SPR_CACO, 10, 250, {A_FlickySpawn}, (1<<16), 0, S_NULL, 0}, // S_CACO_DIE_FALL
+
+	{SPR_CACO, 6, 0, {A_RandomState}, S_CACOSHARD1_1, S_CACOSHARD2_1, S_NULL, 0}, // S_CACOSHARD_RANDOMIZE
+	{SPR_CACO, 6, 3, {NULL}, 0, 0, S_CACOSHARD1_2, 0}, // S_CACOSHARD1_1
+	{SPR_CACO, 7, 3, {NULL}, 0, 0, S_CACOSHARD1_1, 0}, // S_CACOSHARD1_2
+	{SPR_CACO, 8, 3, {NULL}, 0, 0, S_CACOSHARD2_2, 0}, // S_CACOSHARD2_1
+	{SPR_CACO, 9, 3, {NULL}, 0, 0, S_CACOSHARD2_1, 0}, // S_CACOSHARD2_2
+	{SPR_BAL2,   FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE2, 0}, // S_CACOFIRE1
+	{SPR_BAL2, 1|FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE3, 0}, // S_CACOFIRE2
+	{SPR_BAL2,   FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CACOFIRE1, 0}, // S_CACOFIRE3
+	{SPR_BAL2, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE2, 0}, // S_CACOFIRE_EXPLODE1
+	{SPR_BAL2, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE3, 0}, // S_CACOFIRE_EXPLODE2
+	{SPR_BAL2, 4|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE4, 0}, // S_CACOFIRE_EXPLODE3
+	{SPR_BAL2, 5|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0},      // S_CACOFIRE_EXPLODE4
+
+	{SPR_SBOB, 1, 10, {A_ZThrust}, -2, (1<<16)|1, S_SPINBOBERT_MOVE_UP, 0},       // S_SPINBOBERT_MOVE_FLIPUP
+	{SPR_SBOB, 0, 45, {A_ZThrust},  4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPDOWN, 0}, // S_SPINBOBERT_MOVE_UP
+	{SPR_SBOB, 1, 10, {A_ZThrust},  2, (1<<16)|1, S_SPINBOBERT_MOVE_DOWN, 0},     // S_SPINBOBERT_MOVE_FLIPDOWN
+	{SPR_SBOB, 2, 45, {A_ZThrust}, -4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPUP, 0},   // S_SPINBOBERT_MOVE_DOWN
+	{SPR_SBSK, FF_FULLBRIGHT, 1, {A_RotateSpikeBall},       0,                        0, S_SPINBOBERT_FIRE_GHOST, 0}, // S_SPINBOBERT_FIRE_MOVE
+	{SPR_SBSK, FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_SPINBOBERT_FIRE_TRAIL1, S_SPINBOBERT_FIRE_MOVE, 0},  // S_SPINBOBERT_FIRE_GHOST
+	{SPR_SBFL, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL2, 0}, // S_SPINBOBERT_FIRE_TRAIL1
+	{SPR_SBFL, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL3, 0}, // S_SPINBOBERT_FIRE_TRAIL2
+	{SPR_SBFL,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL, 0},                   // S_SPINBOBERT_FIRE_TRAIL3
+
+	{SPR_HBAT, 0,  5, {A_Look}, (900<<16)|1, 0, S_HANGSTER_LOOK, 0}, // S_HANGSTER_LOOK
+	{SPR_HBAT, 1,  0, {A_MultiShotDist}, (MT_DUST<<16)|10, -34, S_HANGSTER_SWOOP2, 0}, // S_HANGSTER_SWOOP1
+	{SPR_HBAT, 1,  2, {A_ZThrust}, -8, (1<<16)|1, S_HANGSTER_SWOOP2, 0}, // S_HANGSTER_SWOOP2
+	{SPR_HBAT, 1,  6, {A_ZThrust}, -5, (1<<16), S_HANGSTER_ARC2, 0}, // S_HANGSTER_ARC1
+	{SPR_HBAT, 1,  5, {A_ZThrust}, -2, (1<<16), S_HANGSTER_ARC3, 0}, // S_HANGSTER_ARC2
+	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_FLY1, 0}, // S_HANGSTER_ARC3
+	{SPR_HBAT, 1,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY2, 0}, // S_HANGSTER_FLY1
+	{SPR_HBAT, 2,  1, {A_PlaySound}, sfx_s3k52, 1, S_HANGSTER_FLY3, 0}, // S_HANGSTER_FLY2
+	{SPR_HBAT, 3,  4, {A_Thrust}, 6, 1, S_HANGSTER_FLY4, 0}, // S_HANGSTER_FLY3
+	{SPR_HBAT, 2,  1, {A_Thrust}, 6, 1, S_HANGSTER_FLYREPEAT, 0}, // S_HANGSTER_FLY4
+	{SPR_HBAT, 2,  0, {A_Repeat}, 12, S_HANGSTER_FLY1, S_HANGSTER_ARCUP1, 0}, // S_HANGSTER_FLYREPEAT
+	{SPR_HBAT, 1,  5, {A_ZThrust},  2, (1<<16), S_HANGSTER_ARCUP2, 0}, // S_HANGSTER_ARCUP1
+	{SPR_HBAT, 1,  6, {A_ZThrust},  5, (1<<16), S_HANGSTER_ARCUP3, 0}, // S_HANGSTER_ARCUP2
+	{SPR_HBAT, 1,  1, {A_ZThrust},  0, (1<<16), S_HANGSTER_RETURN1, 0}, // S_HANGSTER_ARCUP3
+	{SPR_HBAT, 1,  1, {A_ZThrust},  8, (1<<16), S_HANGSTER_RETURN2, 0}, // S_HANGSTER_RETURN1
+	{SPR_HBAT, 3,  1, {NULL}, 0, 0, S_HANGSTER_RETURN1, 0}, // S_HANGSTER_RETURN2
+	{SPR_HBAT, 0, 15, {NULL}, 0, 0, S_HANGSTER_LOOK, 0}, // S_HANGSTER_RETURN3
+
+	{SPR_NULL, 0,  35, {NULL}, 0, 0, S_CRUMBLE2, 0}, // S_CRUMBLE1
+	{SPR_NULL, 0, 105, {A_Scream}, 0, 0, S_NULL, 0}, // S_CRUMBLE2
 
 	// Spark
-	{SPR_NULL, 0, 1, {A_ModuloToState}, 2, S_SPRK2, S_SPRK3},  // S_SPRK1
-	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|0, 18, {NULL}, 8, 2, S_NULL},  // S_SPRK2
-	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|9, 18, {NULL}, 8, 2, S_NULL},  // S_SPRK3
+	{SPR_NULL, 0, 1, {A_ModuloToState}, 2, S_SPRK2, S_SPRK3, 0},  // S_SPRK1
+	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|0, 18, {NULL}, 8, 2, S_NULL, 0},  // S_SPRK2
+	{SPR_SPRK, FF_TRANS20|FF_ANIMATE|9, 18, {NULL}, 8, 2, S_NULL, 0},  // S_SPRK3
 
 	// Robot Explosion
-	{SPR_BOM1, 0, 0, {A_FlickySpawn},  0, 0, S_XPLD1}, // S_XPLD_FLICKY
-	{SPR_BOM1, 0, 2, {A_ShadowScream}, 0, 0, S_XPLD2}, // S_XPLD1
-	{SPR_BOM1, 1, 2, {NULL},           0, 0, S_XPLD3}, // S_XPLD2
-	{SPR_BOM1, 2, 3, {NULL},           0, 0, S_XPLD4}, // S_XPLD3
-	{SPR_BOM1, 3, 3, {NULL},           0, 0, S_XPLD5}, // S_XPLD4
-	{SPR_BOM1, 4, 4, {NULL},           0, 0, S_XPLD6}, // S_XPLD5
-	{SPR_BOM1, 5, 4, {NULL},           0, 0, S_NULL},  // S_XPLD6
+	{SPR_BOM1, 0, 0, {A_FlickySpawn},  0, 0, S_XPLD1, 0}, // S_XPLD_FLICKY
+	{SPR_BOM1, 0, 2, {A_ShadowScream}, 0, 0, S_XPLD2, 0}, // S_XPLD1
+	{SPR_BOM1, 1, 2, {NULL},           0, 0, S_XPLD3, 0}, // S_XPLD2
+	{SPR_BOM1, 2, 3, {NULL},           0, 0, S_XPLD4, 0}, // S_XPLD3
+	{SPR_BOM1, 3, 3, {NULL},           0, 0, S_XPLD5, 0}, // S_XPLD4
+	{SPR_BOM1, 4, 4, {NULL},           0, 0, S_XPLD6, 0}, // S_XPLD5
+	{SPR_BOM1, 5, 4, {NULL},           0, 0, S_NULL, 0},  // S_XPLD6
 
-	{SPR_BOM1, FF_ANIMATE,   21, {NULL},          5, 4, S_INVISIBLE}, // S_XPLD_EGGTRAP
+	{SPR_BOM1, FF_ANIMATE,   21, {NULL},          5, 4, S_INVISIBLE, 0}, // S_XPLD_EGGTRAP
 
 	// Underwater Explosion
-	{SPR_BOM4, 0, 3, {A_ShadowScream}, 0, 0, S_WPLD2}, // S_WPLD1
-	{SPR_BOM4, 1, 3, {NULL},           0, 0, S_WPLD3}, // S_WPLD2
-	{SPR_BOM4, 2, 3, {NULL},           0, 0, S_WPLD4}, // S_WPLD3
-	{SPR_BOM4, 3, 3, {NULL},           0, 0, S_WPLD5}, // S_WPLD4
-	{SPR_BOM4, 4, 3, {NULL},           0, 0, S_WPLD6}, // S_WPLD5
-	{SPR_BOM4, 5, 3, {NULL},           0, 0, S_NULL},  // S_WPLD6
-
-	{SPR_DUST,   FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2}, // S_DUST1
-	{SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3}, // S_DUST2
-	{SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4}, // S_DUST3
-	{SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL},  // S_DUST4
-
-	{SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN
-
-	{SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA
-	{SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEB
-	{SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEC
-	{SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLED
-	{SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEE
-	{SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEF
-	{SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEG
-	{SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEH
-	{SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEI
-	{SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEJ
-	{SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEK
-	{SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEL
-	{SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEM
-	{SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEN
-	{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEO
-	{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEP
-
-	{SPR_GFZD, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_GFZDEBRIS
-	{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS
-	{SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_WOODDEBRIS
-	{SPR_BRIR, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_REDBRICKDEBRIS
-	{SPR_BRIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_BLUEBRICKDEBRIS
-	{SPR_BRIY, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL}, // S_YELLOWBRICKDEBRIS
-
-	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
+	{SPR_BOM4, 0, 3, {A_ShadowScream}, 0, 0, S_WPLD2, 0}, // S_WPLD1
+	{SPR_BOM4, 1, 3, {NULL},           0, 0, S_WPLD3, 0}, // S_WPLD2
+	{SPR_BOM4, 2, 3, {NULL},           0, 0, S_WPLD4, 0}, // S_WPLD3
+	{SPR_BOM4, 3, 3, {NULL},           0, 0, S_WPLD5, 0}, // S_WPLD4
+	{SPR_BOM4, 4, 3, {NULL},           0, 0, S_WPLD6, 0}, // S_WPLD5
+	{SPR_BOM4, 5, 3, {NULL},           0, 0, S_NULL, 0},  // S_WPLD6
+
+	{SPR_DUST,   FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2, 0}, // S_DUST1
+	{SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3, 0}, // S_DUST2
+	{SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4, 0}, // S_DUST3
+	{SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL, 0},  // S_DUST4
+
+	{SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN, 0}, // S_ROCKSPAWN
+
+	{SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEA
+	{SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEB
+	{SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEC
+	{SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLED
+	{SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEE
+	{SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEF
+	{SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEG
+	{SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEH
+	{SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEI
+	{SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEJ
+	{SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL, 0}, // S_ROCKCRUMBLEK
+	{SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEL
+	{SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEM
+	{SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEN
+	{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEO
+	{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL, 0}, // S_ROCKCRUMBLEP
+
+	{SPR_GFZD, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_GFZDEBRIS
+	{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL, 0}, // S_BRICKDEBRIS
+	{SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL, 0}, // S_WOODDEBRIS
+	{SPR_BRIR, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_REDBRICKDEBRIS
+	{SPR_BRIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_BLUEBRICKDEBRIS
+	{SPR_BRIY, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 31, 1, S_NULL, 0}, // S_YELLOWBRICKDEBRIS
+
+	{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL, 0}, // S_NAMECHECK
 };
 
 mobjinfo_t mobjinfo[NUMMOBJTYPES] =
@@ -7493,12 +7494,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		sfx_steam1,     // deathsound
 		0,              // speed
 		32*FRACUNIT,    // radius
-		1*FRACUNIT,     // height
+		16*FRACUNIT,    // height
 		0,              // display offset
 		20*FRACUNIT,    // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_SOLID,       // flags
+		MF_SPECIAL,     // flags
 		S_NULL          // raisestate
 	},
 
diff --git a/src/info.h b/src/info.h
index e8963cd3cdbdb28d2a498bb95cb63b9b5376a354..0361f64281150bec03676bd1b8a4baa36a18de22 100644
--- a/src/info.h
+++ b/src/info.h
@@ -575,6 +575,7 @@ extern int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION];
 #define NUMMOBJFREESLOTS 1024
 #define NUMSPRITEFREESLOTS NUMMOBJFREESLOTS
 #define NUMSTATEFREESLOTS (NUMMOBJFREESLOTS*8)
+#define MAXSPRITENAME 64
 
 // Hey, moron! If you change this table, don't forget about sprnames in info.c and the sprite lights in hw_light.c!
 typedef enum sprite
@@ -1078,9 +1079,6 @@ typedef enum sprite
 	NUMSPRITES
 } spritenum_t;
 
-// Make sure to be conscious of FF_FRAMEMASK and the fact sprite2 is stored as a UINT8 whenever you change this table.
-// Currently, FF_FRAMEMASK is 0xff, or 255 - but the second half is used by FF_SPR2SUPER, so the limitation is 0x7f.
-// Since this is zero-based, there can be at most 128 different SPR2_'s without changing that.
 typedef enum playersprite
 {
 	SPR2_STND = 0,
@@ -1160,15 +1158,17 @@ typedef enum playersprite
 	SPR2_XTRA, // stuff that isn't in-map - "would this ever need an md2 or variable length animation?"
 
 	SPR2_FIRSTFREESLOT,
-	SPR2_LASTFREESLOT = 0x7f,
+	SPR2_LASTFREESLOT = 1024, // Do not make higher than SPR2F_MASK (currently 0x3FF) plus one
 	NUMPLAYERSPRITES
 } playersprite_t;
 
-// SPR2_XTRA
-#define XTRA_LIFEPIC    0                 // Life icon patch
-#define XTRA_CHARSEL    1                 // Character select picture
-#define XTRA_CONTINUE   2                 // Continue icon
-#define XTRA_ENDING     3                 // Ending finale patches
+enum
+{
+	XTRA_LIFEPIC,
+	XTRA_CHARSEL,
+	XTRA_CONTINUE,
+	XTRA_ENDING
+};
 
 typedef enum state
 {
@@ -4380,11 +4380,12 @@ typedef struct
 	INT32 var1;
 	INT32 var2;
 	statenum_t nextstate;
+	UINT16 sprite2;
 } state_t;
 
 extern state_t states[NUMSTATES];
-extern char sprnames[NUMSPRITES + 1][5];
-extern char spr2names[NUMPLAYERSPRITES][5];
+extern char sprnames[NUMSPRITES + 1][MAXSPRITENAME + 1];
+extern char spr2names[NUMPLAYERSPRITES][MAXSPRITENAME + 1];
 extern playersprite_t spr2defaults[NUMPLAYERSPRITES];
 extern state_t *astate;
 extern playersprite_t free_spr2;
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index e75a911eef51f6f47b9d9bef756ca1401d9ac351..dc6a26c81cad44756c0af27c044de79c16ce69de 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -345,6 +345,18 @@ static int lib_reserveLuabanks(lua_State *L)
 	return 1;
 }
 
+static int lib_tofixed(lua_State *L)
+{
+	const char *arg = luaL_checkstring(L, 1);
+	char *end;
+	float f = strtof(arg, &end);
+	if (*end != '\0')
+		lua_pushnil(L);
+	else
+		lua_pushnumber(L, FLOAT_TO_FIXED(f));
+	return 1;
+}
+
 // M_MENU
 //////////////
 
@@ -674,17 +686,15 @@ static int lib_pRemoveMobj(lua_State *L)
 	return 0;
 }
 
-// P_IsValidSprite2 technically doesn't exist, and probably never should... but too much would need to be exposed to allow this to be checked by other methods.
-
 static int lib_pIsValidSprite2(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	UINT8 spr2 = (UINT8)luaL_checkinteger(L, 2);
+	UINT16 spr2 = (UINT16)luaL_checkinteger(L, 2);
 	//HUDSAFE
 	INLEVEL
 	if (!mobj)
 		return LUA_ErrInvalid(L, "mobj_t");
-	lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes)));
+	lua_pushboolean(L, mobj->skin && P_IsValidSprite2(mobj->skin, spr2));
 	return 1;
 }
 
@@ -3032,6 +3042,9 @@ static int lib_rFrame2Char(lua_State *L)
 	//HUDSAFE
 
 	c[0] = R_Frame2Char(ch);
+	if (c[0] == '\xFF')
+		return luaL_error(L, "frame %u cannot be represented by a character", ch);
+
 	c[1] = 0;
 
 	lua_pushstring(L, c);
@@ -3039,6 +3052,9 @@ static int lib_rFrame2Char(lua_State *L)
 	return 2;
 }
 
+// R_SKINS
+////////////
+
 // R_SetPlayerSkin technically doesn't exist either, although it's basically just SetPlayerSkin and SetPlayerSkinByNum handled in one place for convenience
 static int lib_rSetPlayerSkin(lua_State *L)
 {
@@ -3101,6 +3117,47 @@ static int lib_rSkinUsable(lua_State *L)
 	return 1;
 }
 
+static int lib_pGetStateSprite2(lua_State *L)
+{
+	int statenum = luaL_checkinteger(L, 1);
+	if (statenum < 0 || statenum >= NUMSTATES)
+		return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
+
+	lua_pushinteger(L, P_GetStateSprite2(&states[statenum]));
+	return 1;
+}
+
+static int lib_pGetSprite2StateFrame(lua_State *L)
+{
+	int statenum = luaL_checkinteger(L, 1);
+	if (statenum < 0 || statenum >= NUMSTATES)
+		return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
+
+	lua_pushinteger(L, P_GetSprite2StateFrame(&states[statenum]));
+	return 1;
+}
+
+static int lib_pIsStateSprite2Super(lua_State *L)
+{
+	int statenum = luaL_checkinteger(L, 1);
+	if (statenum < 0 || statenum >= NUMSTATES)
+		return luaL_error(L, "state %d out of range (0 - %d)", statenum, NUMSTATES-1);
+
+	lua_pushboolean(L, P_IsStateSprite2Super(&states[statenum]));
+	return 1;
+}
+
+// Not a real function. Who cares? I know I don't.
+static int lib_pGetSuperSprite2(lua_State *L)
+{
+	int animID = luaL_checkinteger(L, 1) & SPR2F_MASK;
+	if (animID < 0 || animID >= NUMPLAYERSPRITES)
+		return luaL_error(L, "sprite2 %d out of range (0 - %d)", animID, NUMPLAYERSPRITES-1);
+
+	lua_pushinteger(L, animID | SPR2F_SUPER);
+	return 1;
+}
+
 // R_DATA
 ////////////
 
@@ -4288,6 +4345,7 @@ static luaL_Reg lib[] = {
 	{"userdataMetatable", lib_userdataMetatable},
 	{"IsPlayerAdmin", lib_isPlayerAdmin},
 	{"reserveLuabanks", lib_reserveLuabanks},
+	{"tofixed", lib_tofixed},
 
 	// m_menu
 	{"M_MoveColorAfter",lib_pMoveColorAfter},
@@ -4506,7 +4564,13 @@ static luaL_Reg lib[] = {
 	{"R_Char2Frame",lib_rChar2Frame},
 	{"R_Frame2Char",lib_rFrame2Char},
 	{"R_SetPlayerSkin",lib_rSetPlayerSkin},
+
+	// r_skins
 	{"R_SkinUsable",lib_rSkinUsable},
+	{"P_GetStateSprite2",lib_pGetStateSprite2},
+	{"P_GetSprite2StateFrame",lib_pGetSprite2StateFrame},
+	{"P_IsStateSprite2Super",lib_pIsStateSprite2Super},
+	{"P_GetSuperSprite2",lib_pGetSuperSprite2},
 
 	// r_data
 	{"R_CheckTextureNumForName",lib_rCheckTextureNumForName},
diff --git a/src/lua_hook.h b/src/lua_hook.h
index 026e5c4aaf97c54326a22d5de56f4e44cbddd09f..17e0e99a0787d43fa12f817018b29acaac723495 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -86,6 +86,8 @@ automatically.
 	X (title),/* titlescreen */\
 	X (titlecard),\
 	X (intermission),\
+	X (continue),\
+	X (playersetup),\
 
 /*
 I chose to access the hook enums through a macro as well. This could provide
@@ -117,6 +119,13 @@ extern boolean hook_cmd_running;
 
 void LUA_HookVoid(int hook);
 void LUA_HookHUD(int hook, huddrawlist_h drawlist);
+int LUA_HookCharacterHUD
+(
+	int hook, huddrawlist_h drawlist, player_t *player,
+	fixed_t x, fixed_t y, fixed_t scale,
+	INT32 skinIndex, UINT8 sprite2, UINT8 frame, UINT8 rotation, skincolornum_t color,
+	INT32 ticker, boolean mode
+);
 
 int  LUA_HookMobj(mobj_t *, int hook);
 int  LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook);
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 529c189ff7883bbd377327ad5b44d2ae5af4e196..54381e4aedc47a64d89190f5582c3c5856634ba6 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -375,6 +375,17 @@ static boolean prepare_string_hook
 		return false;
 }
 
+static boolean prepare_hud_hook
+(
+		Hook_State * hook,
+		int default_status,
+		int hook_type
+){
+	return init_hook_type(hook, default_status,
+			hook_type, 0, NULL,
+			hudHookIds[hook_type].numHooks);
+}
+
 static void init_hook_call
 (
 		Hook_State * hook,
@@ -490,6 +501,21 @@ static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type)
 	return call_mapped(hook, &mobjHookIds[mobj_type][hook->hook_type]);
 }
 
+static void call_hud_hooks
+(
+		Hook_State * hook,
+		int        results,
+		Hook_Callback results_handler
+){
+	hud_running = true; // local hook
+	init_hook_call(hook, results, results_handler);
+	call_mapped(hook, &hudHookIds[hook->hook_type]);
+	hud_running = false;
+
+	lua_pushnil(gL);
+	lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
+}
+
 static int call_hooks
 (
 		Hook_State * hook,
@@ -648,23 +674,39 @@ int LUA_HookKey(event_t *event, int hook_type)
 
 void LUA_HookHUD(int hook_type, huddrawlist_h list)
 {
-	const hook_t * map = &hudHookIds[hook_type];
 	Hook_State hook;
-	if (map->numHooks > 0)
+	if (prepare_hud_hook(&hook, 0, hook_type))
 	{
-		start_hook_stack();
-		begin_hook_values(&hook);
-
 		LUA_SetHudHook(hook_type, list);
+		call_hud_hooks(&hook, 0, res_none);
+	}
+}
 
-		hud_running = true; // local hook
-		init_hook_call(&hook, 0, res_none);
-		call_mapped(&hook, map);
-		hud_running = false;
-
-		lua_pushnil(gL);
-		lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
+int LUA_HookCharacterHUD
+(
+	int hook_type, huddrawlist_h list, player_t *player,
+	fixed_t x, fixed_t y, fixed_t scale,
+	INT32 skinIndex, UINT8 sprite2, UINT8 frame, UINT8 rotation, skincolornum_t color,
+	INT32 ticker, boolean mode
+){
+	Hook_State hook;
+	if (prepare_hud_hook(&hook, false, hook_type))
+	{
+		LUA_SetHudHook(hook_type, list);
+		LUA_PushUserdata(gL, player, META_PLAYER);
+		lua_pushfixed(gL, x);
+		lua_pushfixed(gL, y);
+		lua_pushfixed(gL, scale);
+		lua_pushstring(gL, skins[skinIndex]->name);
+		lua_pushinteger(gL, sprite2);
+		lua_pushinteger(gL, frame);
+		lua_pushinteger(gL, rotation);
+		lua_pushinteger(gL, color);
+		lua_pushinteger(gL, ticker);
+		lua_pushboolean(gL, mode);
+		call_hud_hooks(&hook, 1, res_true);
 	}
+	return hook.status;
 }
 
 /* =========================================================================
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 08e0367f9e2cd5a6c71eb0dcfaf57948194b0bea..d6771f1082a635e2bcb9e26ffb4349398113397c 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -492,9 +492,7 @@ static int libd_getSpritePatch(lua_State *L)
 	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "THOK"
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < NUMSPRITES; i++)
-			if (fastcmp(name, sprnames[i]))
-				break;
+		i = R_GetSpriteNumByName(name);
 		if (i >= NUMSPRITES)
 			return 0;
 	}
@@ -556,7 +554,7 @@ static int libd_getSprite2Patch(lua_State *L)
 	UINT8 angle = 0;
 	spritedef_t *sprdef;
 	spriteframe_t *sprframe;
-	boolean super = false; // add FF_SPR2SUPER to sprite2 if true
+	boolean super = false; // add SPR2F_SUPER to sprite2 if true
 	HUDONLY
 
 	// get skin first!
@@ -583,11 +581,12 @@ static int libd_getSprite2Patch(lua_State *L)
 	if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR2_STND
 	{
 		j = lua_tonumber(L, 1);
-		if (j & FF_SPR2SUPER) // e.g. SPR2_STND|FF_SPR2SUPER
+		if (j & SPR2F_SUPER) // e.g. SPR2_STND|SPR2F_SUPER
 		{
 			super = true;
-			j &= ~FF_SPR2SUPER; // remove flag so the next check doesn't fail
+			j &= ~SPR2F_SUPER; // remove flag so the next check doesn't fail
 		}
+
 		if (j >= free_spr2)
 			return 0;
 	}
@@ -606,17 +605,15 @@ static int libd_getSprite2Patch(lua_State *L)
 
 	if (lua_isboolean(L, 2)) // optional boolean for superness
 	{
-		super = lua_toboolean(L, 2); // note: this can override FF_SPR2SUPER from sprite number
+		super = lua_toboolean(L, 2); // note: this can override SPR2F_SUPER from sprite number
 		lua_remove(L, 2); // remove
 	}
 	// if it's not boolean then just assume it's the frame number
 
 	if (super)
-		j |= FF_SPR2SUPER;
-
-	j = P_GetSkinSprite2(skins[i], j, NULL); // feed skin and current sprite2 through to change sprite2 used if necessary
+		j |= SPR2F_SUPER;
 
-	sprdef = &skins[i]->sprites[j];
+	sprdef = P_GetSkinSpritedef(skins[i], j);
 
 	// set frame number
 	frame = luaL_optinteger(L, 2, 0);
@@ -644,7 +641,7 @@ static int libd_getSprite2Patch(lua_State *L)
 		INT32 rot = R_GetRollAngle(rollangle);
 
 		if (rot) {
-			patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), &skins[i]->sprinfo[j], rot);
+			patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), P_GetSkinSpriteInfo(skins[i], j), rot);
 			LUA_PushUserdata(L, rotsprite, META_PATCH);
 			lua_pushboolean(L, false);
 			lua_pushboolean(L, true);
diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c
index c518ba52540ff874480d7cda2c8314a31987e993..cb58e628ea005217c819ddea922f4952f70961f0 100644
--- a/src/lua_hudlib_drawlist.c
+++ b/src/lua_hudlib_drawlist.c
@@ -180,7 +180,8 @@ static const char *CopyString(huddrawlist_h list, const char* str)
 		const char *old_offset = list->strbuf;
 		size_t i;
 		if (list->strbuf_capacity == 0) list->strbuf_capacity = 256;
-		else list->strbuf_capacity *= 2;
+		while (list->strbuf_capacity <= list->strbuf_len + lenstr + 1)
+			list->strbuf_capacity *= 2;
 		list->strbuf = (char*) Z_Realloc(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL);
 
 		// align the string pointers to make sure old pointers don't point towards invalid addresses
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index 767477d0bac75e7b9bada5367cb223a37a33f8cd..511c20031f8ea82d74c70da608535146bfce8eb2 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -88,12 +88,12 @@ static int lib_getSprname(lua_State *L)
 	else if (lua_isstring(L, 1))
 	{
 		const char *name = lua_tostring(L, 1);
-		for (i = 0; i < NUMSPRITES; i++)
-			if (fastcmp(name, sprnames[i]))
-			{
-				lua_pushinteger(L, i);
-				return 1;
-			}
+		i = R_GetSpriteNumByName(name);
+		if (i != NUMSPRITES)
+		{
+			lua_pushinteger(L, i);
+			return 1;
+		}
 	}
 	return 0;
 }
@@ -165,7 +165,7 @@ static int lib_getSpr2default(lua_State *L)
 static int lib_setSpr2default(lua_State *L)
 {
 	playersprite_t i;
-	UINT8 j = 0;
+	UINT16 j = 0;
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!");
@@ -242,25 +242,13 @@ static int lib_getSpriteInfo(lua_State *L)
 	UINT32 i = NUMSPRITES;
 	lua_remove(L, 1);
 
-	if (lua_isstring(L, 1))
+	if (lua_type(L, 1) == LUA_TSTRING)
 	{
 		const char *name = lua_tostring(L, 1);
-		INT32 spr;
-		for (spr = 0; spr < NUMSPRITES; spr++)
-		{
-			if (fastcmp(name, sprnames[spr]))
-			{
-				i = spr;
-				break;
-			}
-		}
-		if (i == NUMSPRITES)
-		{
-			char *check;
-			i = strtol(name, &check, 10);
-			if (check == name || *check != '\0')
-				return luaL_error(L, "unknown sprite name %s", name);
-		}
+		INT32 spr = R_GetSpriteNumByName(name);
+		if (spr == NUMSPRITES)
+			return luaL_error(L, "unknown sprite name %s", name);
+		i = spr;
 	}
 	else
 		i = luaL_checkinteger(L, 1);
@@ -359,8 +347,8 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
 			default:
 				TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1));
 		}
-		if ((idx < 0) || (idx >= 64))
-			return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63);
+		if ((idx < 0) || (idx >= MAXFRAMENUM))
+			return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, MAXFRAMENUM - 1);
 		// the values in pivot[] are also tables
 		if (PopPivotSubTable(info->pivot, L, stk+2, idx))
 			info->available = true;
@@ -555,7 +543,7 @@ static int pivotlist_set(lua_State *L)
 
 static int pivotlist_num(lua_State *L)
 {
-	lua_pushinteger(L, 64);
+	lua_pushinteger(L, MAXFRAMENUM);
 	return 1;
 }
 
@@ -1747,7 +1735,7 @@ static int lib_setSkinColor(lua_State *L)
 		else if (i == 6 || (str && fastcmp(str,"accessible"))) {
 			boolean v = lua_toboolean(L, 3);
 			if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
-				CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum);
+				CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.\n", cnum);
 			else
 				info->accessible = v;
 		}
@@ -1842,7 +1830,7 @@ static int skincolor_set(lua_State *L)
 	else if (fastcmp(field,"accessible")) {
 		boolean v = lua_toboolean(L, 3);
 		if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
-			CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum);
+			CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.\n", cnum);
 		else
 			info->accessible = v;
 	} else
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 62b02ff3f679a50c7bd09df2807b8d11f5056276..de7065790abb137e82f505c961215ca6acb10429 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -564,7 +564,7 @@ static int mobj_set(lua_State *L)
 		mo->frame = (UINT32)luaL_checkinteger(L, 3);
 		break;
 	case mobj_sprite2:
-		mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT8)luaL_checkinteger(L, 3), mo->player);
+		mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT16)luaL_checkinteger(L, 3), mo->player);
 		break;
 	case mobj_anim_duration:
 		mo->anim_duration = (UINT16)luaL_checkinteger(L, 3);
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index b6ef2579c131d8de29a521615cb6a74acc94f5a0..744a56f7fe528031dd0777c06da35067fb59dde4 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -190,6 +190,7 @@ enum player_e
 	player_marelap,
 	player_marebonuslap,
 	player_marebegunat,
+	player_lastmaretime,
 	player_startedtime,
 	player_finishedtime,
 	player_lapbegunat,
@@ -337,6 +338,7 @@ static const char *const player_opt[] = {
 	"marelap",
 	"marebonuslap",
 	"marebegunat",
+	"lastmaretime",
 	"startedtime",
 	"finishedtime",
 	"lapbegunat",
@@ -725,6 +727,9 @@ static int player_get(lua_State *L)
 	case player_marebegunat:
 		lua_pushinteger(L, plr->marebegunat);
 		break;
+	case player_lastmaretime:
+		lua_pushinteger(L, plr->lastmaretime);
+		break;
 	case player_startedtime:
 		lua_pushinteger(L, plr->startedtime);
 		break;
@@ -1219,6 +1224,9 @@ static int player_set(lua_State *L)
 	case player_marebegunat:
 		plr->marebegunat = (tic_t)luaL_checkinteger(L, 3);
 		break;
+	case player_lastmaretime:
+		plr->lastmaretime = (tic_t)luaL_checkinteger(L, 3);
+		break;
 	case player_startedtime:
 		plr->startedtime = (tic_t)luaL_checkinteger(L, 3);
 		break;
diff --git a/src/lua_script.c b/src/lua_script.c
index b62fa675e2e7193da3a688d89d2f1cf377298a51..057899555480383611652c552e41bf41398b0e2b 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -622,9 +622,6 @@ static inline boolean LUA_LoadFile(MYFILE *f, char *name)
 	if (!gL) // Lua needs to be initialized
 		LUA_ClearState();
 
-	lua_pushinteger(gL, f->wad);
-	lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
-
 	lua_pushcfunction(gL, LUA_GetErrorMessage);
 	errorhandlerindex = lua_gettop(gL);
 
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index e183d8dda4a08b4c64dcc2429937cf919d743f67..24d948a6735c3c723dcbf86c285a23c8367090dd 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -55,6 +55,7 @@ enum skin {
 	skin_contangle,
 	skin_soundsid,
 	skin_sprites,
+	skin_supersprites,
 	skin_natkcolor
 };
 
@@ -95,6 +96,7 @@ static const char *const skin_opt[] = {
 	"contangle",
 	"soundsid",
 	"sprites",
+	"supersprites",
 	"natkcolor",
 	NULL};
 
@@ -220,6 +222,9 @@ static int skin_get(lua_State *L)
 	case skin_sprites:
 		LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
 		break;
+	case skin_supersprites:
+		LUA_PushUserdata(L, skin->super.sprites, META_SKINSPRITES);
+		break;
 	case skin_natkcolor:
 		lua_pushinteger(L, skin->natkcolor);
 		break;
@@ -347,17 +352,17 @@ static int lib_getSkinSprite(lua_State *L)
 	spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
 	playersprite_t i = luaL_checkinteger(L, 2);
 
-	if (i < 0 || i >= NUMPLAYERSPRITES*2)
-		return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
+	if (i < 0 || i >= NUMPLAYERSPRITES)
+		return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
 
 	LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST);
 	return 1;
 }
 
-// #skin.sprites -> NUMPLAYERSPRITES*2
+// #skin.sprites -> NUMPLAYERSPRITES
 static int lib_numSkinsSprites(lua_State *L)
 {
-	lua_pushinteger(L, NUMPLAYERSPRITES*2);
+	lua_pushinteger(L, NUMPLAYERSPRITES);
 	return 1;
 }
 
diff --git a/src/m_menu.c b/src/m_menu.c
index 7811a99ba3197ed9783431723dc4254fdf01f992..e0c240fecc773d2ef9f0931205f05a02315a74c2 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -184,6 +184,9 @@ static fixed_t char_scroll = 0;
 
 static tic_t keydown = 0;
 
+// Lua
+static huddrawlist_h luahuddrawlist_playersetup;
+
 //
 // PROTOTYPES
 //
@@ -260,7 +263,7 @@ static void M_ConfirmTeamScramble(INT32 choice);
 static void M_ConfirmTeamChange(INT32 choice);
 static void M_SecretsMenu(INT32 choice);
 static void M_SetupChoosePlayer(INT32 choice);
-static UINT16 M_SetupChoosePlayerDirect(INT32 choice);
+static INT32 M_SetupChoosePlayerDirect(INT32 choice);
 static void M_QuitSRB2(INT32 choice);
 menu_t SP_MainDef, OP_MainDef;
 menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
@@ -2099,6 +2102,12 @@ menu_t OP_PlaystyleDef = {
 	0, 0, 0, NULL
 };
 
+static void M_UpdateItemOn(void)
+{
+	I_SetTextInputMode((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING ||
+		(currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER);
+}
+
 static void M_VideoOptions(INT32 choice)
 {
 	(void)choice;
@@ -2326,6 +2335,7 @@ void Nextmap_OnChange(void)
 		{
 			currentMenu->lastOn = itemOn;
 			itemOn = nastart;
+			M_UpdateItemOn();
 		}
 	}
 	else if (currentMenu == &SP_TimeAttackDef)
@@ -2375,6 +2385,7 @@ void Nextmap_OnChange(void)
 		{
 			currentMenu->lastOn = itemOn;
 			itemOn = tastart;
+			M_UpdateItemOn();
 		}
 
 		if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0')
@@ -3125,6 +3136,7 @@ static void M_NextOpt(void)
 		else
 			itemOn++;
 	} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
+	M_UpdateItemOn();
 }
 
 static void M_PrevOpt(void)
@@ -3137,6 +3149,7 @@ static void M_PrevOpt(void)
 		else
 			itemOn--;
 	} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
+	M_UpdateItemOn();
 }
 
 // lock out further input in a tic when important buttons are pressed
@@ -3648,18 +3661,20 @@ void M_StartControlPanel(void)
 
 		currentMenu = &MainDef;
 		itemOn = singleplr;
+		M_UpdateItemOn();
 	}
 	else if (modeattacking)
 	{
 		currentMenu = &MAPauseDef;
 		MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 		itemOn = mapause_continue;
+		M_UpdateItemOn();
 	}
 	else if (!(netgame || multiplayer)) // Single Player
 	{
 		// Devmode unlocks Pandora's Box in the pause menu
 		boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) || cv_debug || devparm) && !marathonmode);
-		
+
 		if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff.
 		{
 			SPauseMenu[spause_pandora].status = (pandora) ? (IT_GRAYEDOUT) : (IT_DISABLED);
@@ -3700,6 +3715,7 @@ void M_StartControlPanel(void)
 
 		currentMenu = &SPauseDef;
 		itemOn = spause_continue;
+		M_UpdateItemOn();
 	}
 	else // multiplayer
 	{
@@ -3741,6 +3757,7 @@ void M_StartControlPanel(void)
 
 		currentMenu = &MPauseDef;
 		itemOn = mpause_continue;
+		M_UpdateItemOn();
 	}
 
 	CON_ToggleOff(); // move away console
@@ -3834,6 +3851,7 @@ void M_SetupNextMenu(menu_t *menudef)
 			}
 		}
 	}
+	M_UpdateItemOn();
 
 	hidetitlemap = false;
 }
@@ -4012,11 +4030,11 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv)
 	lumpnum_t leftlump, rightlump, centerlump[2], cursorlump;
 	patch_t *p;
 
-	leftlump = W_GetNumForName("M_THERML");
-	rightlump = W_GetNumForName("M_THERMR");
-	centerlump[0] = W_GetNumForName("M_THERMM");
-	centerlump[1] = W_GetNumForName("M_THERMM");
-	cursorlump = W_GetNumForName("M_THERMO");
+	leftlump = W_GetNumForPatchName("M_THERML");
+	rightlump = W_GetNumForPatchName("M_THERMR");
+	centerlump[0] = W_GetNumForPatchName("M_THERMM");
+	centerlump[1] = W_GetNumForPatchName("M_THERMM");
+	cursorlump = W_GetNumForPatchName("M_THERMO");
 
 	V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH));
 	xx += p->width - p->leftoffset;
@@ -4138,7 +4156,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_
 			temp = (gametic % temp) * h*2*FRACUNIT; // Which frame to draw
 
 		V_DrawCroppedPatch(x*FRACUNIT, y*FRACUNIT, (w*FRACUNIT) / 160, (h*FRACUNIT) / 100, flags, patch, NULL, 0, temp, w*2*FRACUNIT, h*2*FRACUNIT);
-		
+
 		W_UnlockCachedPatch(patch);
 		return;
 	}
@@ -4956,22 +4974,6 @@ static void M_DrawCenteredMenu(void)
 	}
 }
 
-//
-// M_StringHeight
-//
-// Find string height from hu_font chars
-//
-static inline size_t M_StringHeight(const char *string)
-{
-	size_t h = 8, i;
-
-	for (i = 0; i < strlen(string); i++)
-		if (string[i] == '\n')
-			h += 8;
-
-	return h;
-}
-
 // ==========================================================================
 // Extraneous menu patching functions
 // ==========================================================================
@@ -6089,56 +6091,16 @@ menu_t MessageDef =
 	NULL
 };
 
-
-void M_StartMessage(const char *string, void *routine,
-	menumessagetype_t itemtype)
+void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype)
 {
-	size_t max = 0, start = 0, i, strlines;
-	static char *message = NULL;
+	static char *message;
 	Z_Free(message);
-	message = Z_StrDup(string);
+	message = V_WordWrap(0,0,V_ALLOWLOWERCASE,string);
 	DEBFILE(message);
 
-	// Rudementary word wrapping.
-	// Simple and effective. Does not handle nonuniform letter sizes, colors, etc. but who cares.
-	strlines = 0;
-	for (i = 0; message[i]; i++)
-	{
-		if (message[i] == ' ')
-		{
-			start = i;
-			max += 4;
-		}
-		else if (message[i] == '\n')
-		{
-			strlines = i;
-			start = 0;
-			max = 0;
-			continue;
-		}
-		else
-			max += 8;
-
-		// Start trying to wrap if presumed length exceeds the screen width.
-		if (max >= BASEVIDWIDTH && start > 0)
-		{
-			message[start] = '\n';
-			max -= (start-strlines)*8;
-			strlines = start;
-			start = 0;
-		}
-	}
-
-	start = 0;
-	max = 0;
-
 	M_StartControlPanel(); // can't put menuactive to true
 
-	if (currentMenu == &MessageDef) // Prevent recursion
-		MessageDef.prevMenu = &MainDef;
-	else
-		MessageDef.prevMenu = currentMenu;
-
+	MessageDef.prevMenu = (currentMenu == &MessageDef) ? &MainDef : currentMenu; // Prevent recursion
 	MessageDef.menuitems[0].text     = message;
 	MessageDef.menuitems[0].alphaKey = (UINT8)itemtype;
 	if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING;
@@ -6157,51 +6119,18 @@ void M_StartMessage(const char *string, void *routine,
 			MessageDef.menuitems[0].itemaction = routine;
 			break;
 	}
-	//added : 06-02-98: now draw a textbox around the message
-	// compute lenght max and the numbers of lines
-	for (strlines = 0; *(message+start); strlines++)
-	{
-		for (i = 0;i < strlen(message+start);i++)
-		{
-			if (*(message+start+i) == '\n')
-			{
-				if (i > max)
-					max = i;
-				start += i;
-				i = (size_t)-1; //added : 07-02-98 : damned!
-				start++;
-				break;
-			}
-		}
-
-		if (i == strlen(message+start))
-			start += i;
-	}
-
-	MessageDef.x = (INT16)((BASEVIDWIDTH  - 8*max-16)/2);
-	MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2);
-
-	MessageDef.lastOn = (INT16)((strlines<<8)+max);
+	MessageDef.x = (INT16)((BASEVIDWIDTH  - V_StringWidth(message, 0)-32)/2);
+	MessageDef.y = (INT16)((BASEVIDHEIGHT - V_StringHeight(message, V_RETURN8))/2);
 
-	//M_SetupNextMenu();
 	currentMenu = &MessageDef;
 	itemOn = 0;
+	M_UpdateItemOn();
 }
 
-#define MAXMSGLINELEN 256
-
 static void M_DrawMessageMenu(void)
 {
-	INT32 y = currentMenu->y;
-	size_t i, start = 0;
-	INT16 max;
-	char string[MAXMSGLINELEN];
-	INT32 mlines;
 	const char *msg = currentMenu->menuitems[0].text;
 
-	mlines = currentMenu->lastOn>>8;
-	max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
-
 	// hack: draw RA background in RA menus
 	if (gamestate == GS_TIMEATTACK)
 	{
@@ -6225,51 +6154,8 @@ static void M_DrawMessageMenu(void)
 			V_DrawFadeScreen(0xFF00, curfadevalue);
 	}
 
-	M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
-
-	while (*(msg+start))
-	{
-		size_t len = strlen(msg+start);
-
-		for (i = 0; i < len; i++)
-		{
-			if (*(msg+start+i) == '\n')
-			{
-				memset(string, 0, MAXMSGLINELEN);
-				if (i >= MAXMSGLINELEN)
-				{
-					CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
-					return;
-				}
-				else
-				{
-					strncpy(string,msg+start, i);
-					string[i] = '\0';
-					start += i;
-					i = (size_t)-1; //added : 07-02-98 : damned!
-					start++;
-				}
-				break;
-			}
-		}
-
-		if (i == strlen(msg+start))
-		{
-			if (i >= MAXMSGLINELEN)
-			{
-				CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
-				return;
-			}
-			else
-			{
-				strcpy(string, msg + start);
-				start += i;
-			}
-		}
-
-		V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string);
-		y += 8; //hu_font[0]->height;
-	}
+	M_DrawTextBox(currentMenu->x, currentMenu->y - 8, 2+V_StringWidth(msg, 0)/8, V_StringHeight(msg, V_RETURN8)/8);
+	V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, V_ALLOWLOWERCASE|V_RETURN8, msg);
 }
 
 // default message handler
@@ -6313,6 +6199,7 @@ static void M_HandleImageDef(INT32 choice)
 			if (itemOn >= (INT16)(currentMenu->numitems-1))
 				itemOn = 0;
             else itemOn++;
+			M_UpdateItemOn();
 			break;
 
 		case KEY_LEFTARROW:
@@ -6323,6 +6210,7 @@ static void M_HandleImageDef(INT32 choice)
 			if (!itemOn)
 				itemOn = currentMenu->numitems - 1;
 			else itemOn--;
+			M_UpdateItemOn();
 			break;
 
 		case KEY_ESCAPE:
@@ -7112,7 +7000,10 @@ static void M_LevelSelectWarp(INT32 choice)
 	if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef)
 	{
 		if (cursaveslot > 0) // do we have a save slot to load?
+		{
+			CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
 			G_LoadGame((UINT32)cursaveslot, startmap); // reload from SP save data: this is needed to keep score/lives/continues from reverting to defaults
+		}
 		else // no save slot, start new game but keep the current skin
 		{
 			M_ClearMenus(true);
@@ -7519,6 +7410,7 @@ static void M_EmblemHints(INT32 choice)
 	SR_EmblemHintDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&SR_EmblemHintDef);
 	itemOn = 2; // always start on back.
+	M_UpdateItemOn();
 }
 
 static void M_DrawEmblemHints(void)
@@ -7956,7 +7848,7 @@ static void M_DrawSoundTest(void)
 				{
 					V_DrawFill(165+140-9, y-4, 8, 16, 150);
 					//V_DrawCharacter(165+140-8, y, '\x19' | V_YELLOWMAP, false);
-					V_DrawFixedPatch((165+140-9)<<FRACBITS, (y<<FRACBITS)-(bounce*4), FRACUNIT, 0, hu_font['\x19'-HU_FONTSTART], V_GetStringColormap(V_YELLOWMAP));
+					V_DrawFixedPatch((165+140-9)<<FRACBITS, (y<<FRACBITS)-(bounce*4), FRACUNIT, 0, hu_font.chars['\x19'-FONTSTART], V_GetStringColormap(V_YELLOWMAP));
 				}
 			}
 			t++;
@@ -8760,9 +8652,14 @@ static void M_LoadSelect(INT32 choice)
 		M_NewGame();
 	}
 	else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed
+	{
 		M_LoadGameLevelSelect(0);
+	}
 	else
+	{
+		CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
 		G_LoadGame((UINT32)saveSlotSelected, 0);
+	}
 
 	cursaveslot = saveSlotSelected;
 }
@@ -9183,7 +9080,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
 		description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH);
 }
 
-static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
+static INT32 M_SetupChoosePlayerDirect(INT32 choice)
 {
 	INT32 skinnum, botskinnum;
 	UINT16 i;
@@ -9272,7 +9169,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
 
 static void M_SetupChoosePlayer(INT32 choice)
 {
-	UINT16 skinset = M_SetupChoosePlayerDirect(choice);
+	INT32 skinset = M_SetupChoosePlayerDirect(choice);
 	if (skinset != MAXCHARACTERSLOTS)
 	{
 		M_ChoosePlayer(skinset);
@@ -9621,6 +9518,8 @@ static void M_ChoosePlayer(INT32 choice)
 	//lastmapsaved = 0;
 	gamecomplete = 0;
 
+	CV_StealthSet(&cv_skin, skins[skinnum]->name);
+
 	G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect);
 	COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
 
@@ -10180,6 +10079,7 @@ static void M_TimeAttack(INT32 choice)
 		Nextmap_OnChange();
 
 	itemOn = tastart; // "Start" is selected.
+	M_UpdateItemOn();
 }
 
 // Drawing function for Nights Attack
@@ -10296,7 +10196,7 @@ void M_DrawNightsAttackMenu(void)
 			skinnumber = 0; //Default to Sonic
 		else
 			skinnumber = (cv_chooseskin.value-1);
-			
+
 		spritedef_t *sprdef = &skins[skinnumber]->sprites[SPR2_NFLY]; //Make our patch the selected character's NFLY sprite
 		spritetimer = FixedInt(ntsatkdrawtimer/2) % skins[skinnumber]->sprites[SPR2_NFLY].numframes; //Make the sprite timer cycle though all the frames at 2 tics per frame
 		spriteframe_t *sprframe = &sprdef->spriteframes[spritetimer]; //Our animation frame is equal to the number on the timer
@@ -10309,11 +10209,11 @@ void M_DrawNightsAttackMenu(void)
 			color = skins[skinnumber]->supercolor+4;
 		else //If you don't go super in NiGHTS or at all, use prefcolor
 			color = skins[skinnumber]->prefcolor;
-				
+
 		angle_t fa = (FixedAngle(((FixedInt(ntsatkdrawtimer * 4)) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
 
 		V_DrawFixedPatch(270<<FRACBITS, (186<<FRACBITS) - 8*FINESINE(fa),
-						 FixedDiv(skins[skinnumber]->highresscale, skins[skinnumber]->shieldscale), 
+						 FixedDiv(skins[skinnumber]->highresscale, skins[skinnumber]->shieldscale),
 						 (sprframe->flip & 1<<6) ? V_FLIP : 0,
 						 natksprite,
 						 R_GetTranslationColormap(TC_BLINK, color, GTC_CACHE));
@@ -10418,6 +10318,7 @@ static void M_NightsAttack(INT32 choice)
 		Nextmap_OnChange();
 
 	itemOn = nastart; // "Start" is selected.
+	M_UpdateItemOn();
 }
 
 // Player has selected the "START" from the nights attack screen
@@ -10737,6 +10638,7 @@ static void M_ModeAttackEndGame(INT32 choice)
 		break;
 	}
 	itemOn = currentMenu->lastOn;
+	M_UpdateItemOn();
 	G_SetGamestate(GS_TIMEATTACK);
 	modeattacking = ATTACKING_NONE;
 	M_ChangeMenuMusic("_title", true);
@@ -10818,6 +10720,7 @@ static void M_Marathon(INT32 choice)
 	titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
 	M_SetupNextMenu(&SP_MarathonDef);
 	itemOn = marathonstart; // "Start" is selected.
+	M_UpdateItemOn();
 	recatkdrawtimer = (50-8) * FRACUNIT;
 	char_scroll = 0;
 }
@@ -11531,6 +11434,7 @@ static void M_ConnectMenu(INT32 choice)
 	else
 		M_SetupNextMenu(&MP_ConnectDef);
 	itemOn = 0;
+	M_UpdateItemOn();
 	M_Refresh(0);
 }
 
@@ -11790,6 +11694,7 @@ static void M_StartServerMenu(INT32 choice)
 	Newgametype_OnChange();
 	M_SetupNextMenu(&MP_ServerDef);
 	itemOn = 1;
+	M_UpdateItemOn();
 }
 
 // ==============
@@ -11972,15 +11877,21 @@ static void M_HandleConnectIP(INT32 choice)
 					case KEY_INS:
 					case 'c':
 					case 'C': // ctrl+c, ctrl+insert, copying
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+						}
 						break;
 
 					case 'x':
 					case 'X': // ctrl+x, cutting
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
-						setupm_ip[0] = 0;
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+							setupm_ip[0] = 0;
+						}
 						break;
 
 					default: // otherwise do nothing
@@ -12004,9 +11915,12 @@ static void M_HandleConnectIP(INT32 choice)
 							break;
 						}
 					case KEY_DEL: // shift+delete, cutting
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
-						setupm_ip[0] = 0;
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+							setupm_ip[0] = 0;
+						}
 						break;
 					default: // otherwise do nothing.
 						break;
@@ -12056,9 +11970,22 @@ static void M_HandleConnectIP(INT32 choice)
 
 static fixed_t    multi_tics;
 static UINT8      multi_frame;
-static UINT8      multi_spr2;
+static UINT16     multi_spr2;
 static boolean    multi_paused;
 static boolean    multi_invcolor;
+static boolean    multi_override;
+
+static spritedef_t *multi_followitem_sprdef;
+static INT32        multi_followitem_skinnum;
+static UINT8        multi_followitem_numframes;
+static UINT8        multi_followitem_startframe;
+static UINT8        multi_followitem_frame;
+static fixed_t      multi_followitem_duration;
+static fixed_t      multi_followitem_tics;
+static fixed_t      multi_followitem_scale;
+static fixed_t      multi_followitem_yoffset;
+
+#define MULTI_DURATION (4*FRACUNIT)
 
 // this is set before entering the MultiPlayer setup menu,
 // for either player 1 or 2
@@ -12203,9 +12130,92 @@ static menucolor_t *M_GridIndexToMenuColor(UINT16 index)
 	}
 }
 
+static void M_SetPlayerSetupFollowItem(void)
+{
+	const mobjtype_t followitem = skins[setupm_fakeskin]->followitem;
+
+	switch (followitem)
+	{
+		case MT_TAILSOVERLAY:
+		{
+			const state_t *state = &states[S_TAILSOVERLAY_MINUS30DEGREES];
+			const UINT8 sprite2 = P_GetSkinSprite2(skins[setupm_fakeskin], state->frame & FF_FRAMEMASK, NULL);
+
+			if (state->sprite != SPR_PLAY)
+				break;
+
+			multi_followitem_sprdef = &skins[setupm_fakeskin]->sprites[sprite2];
+			multi_followitem_skinnum = setupm_fakeskin;
+			multi_followitem_numframes = multi_followitem_sprdef->numframes;
+			multi_followitem_startframe = 0;
+			multi_followitem_frame = multi_frame;
+			multi_followitem_duration = MULTI_DURATION;
+			multi_followitem_tics = multi_tics;
+			multi_followitem_scale = FRACUNIT;
+			multi_followitem_yoffset = 0;
+
+			if ((state->frame & FF_SPR2MIDSTART) && (multi_followitem_numframes > 0) && M_RandomChance(FRACUNIT / 2))
+			{
+				multi_followitem_frame += multi_followitem_numframes / 2;
+			}
+			break;
+		}
+		case MT_METALJETFUME:
+		{
+			const state_t *state = &states[S_JETFUME1];
+
+			if (!(state->frame & FF_ANIMATE))
+				break;
+
+			multi_followitem_sprdef = &sprites[state->sprite];
+			multi_followitem_skinnum = TC_DEFAULT;
+			multi_followitem_numframes = state->var1 + 1;
+			multi_followitem_startframe = state->frame & FF_FRAMEMASK;
+			multi_followitem_frame = multi_followitem_startframe;
+			multi_followitem_duration = state->var2 * FRACUNIT;
+			multi_followitem_tics = multi_tics % multi_followitem_duration;
+			multi_followitem_scale = 2 * FRACUNIT / 3;
+			multi_followitem_yoffset = (skins[setupm_fakeskin]->height - FixedMul(mobjinfo[followitem].height, multi_followitem_scale)) >> 1;
+			break;
+		}
+		default:
+			multi_followitem_sprdef = NULL;
+			break;
+	}
+}
+
+static void M_DrawPlayerSetupFollowItem(INT32 x, INT32 y, fixed_t scale, INT32 flags)
+{
+	spriteframe_t *sprframe;
+	patch_t *patch;
+	UINT8 *colormap;
+
+	if (multi_followitem_sprdef == NULL)
+		return;
+
+	if (multi_followitem_frame >= multi_followitem_startframe + multi_followitem_numframes)
+		multi_followitem_frame = multi_followitem_startframe;
+
+	colormap = R_GetTranslationColormap(multi_followitem_skinnum, setupm_fakecolor->color, GTC_CACHE);
+
+	sprframe = &multi_followitem_sprdef->spriteframes[multi_followitem_frame];
+	patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
+	if (sprframe->flip & 1) // Only for first sprite
+		flags |= V_FLIP; // This sprite is left/right flipped!
+
+	x <<= FRACBITS;
+	y <<= FRACBITS;
+	y -= FixedMul(multi_followitem_yoffset, scale);
+
+	scale = FixedMul(scale, multi_followitem_scale);
+
+	V_DrawFixedPatch(x, y, scale, flags, patch, colormap);
+}
+
 static void M_DrawSetupMultiPlayerMenu(void)
 {
 	INT32 x, y, cursory = 0, flags = 0;
+	fixed_t scale;
 	spritedef_t *sprdef;
 	spriteframe_t *sprframe;
 	patch_t *patch;
@@ -12255,11 +12265,24 @@ static void M_DrawSetupMultiPlayerMenu(void)
 	y += 11;
 
 	// anim the player in the box
-	multi_tics -= renderdeltatics;
-	while (!multi_paused && multi_tics <= 0)
+	if (!multi_paused)
 	{
-		multi_frame++;
-		multi_tics += 4*FRACUNIT;
+		multi_tics -= renderdeltatics;
+		while (multi_tics <= 0)
+		{
+			multi_frame++;
+			multi_tics += MULTI_DURATION;
+		}
+
+		if (multi_followitem_sprdef != NULL)
+		{
+			multi_followitem_tics -= renderdeltatics;
+			while (multi_followitem_tics <= 0)
+			{
+				multi_followitem_frame++;
+				multi_followitem_tics += multi_followitem_duration;
+			}
+		}
 	}
 
 #define charw 74
@@ -12274,17 +12297,38 @@ static void M_DrawSetupMultiPlayerMenu(void)
 		goto faildraw;
 
 	// ok, draw player sprite for sure now
-	colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_CACHE);
-
 	if (multi_frame >= sprdef->numframes)
 		multi_frame = 0;
 
+	scale = FixedDiv(skins[setupm_fakeskin]->highresscale, skins[setupm_fakeskin]->shieldscale);
+
+#define chary (y+64)
+
+	if (renderisnewtic)
+	{
+		LUA_HUD_ClearDrawList(luahuddrawlist_playersetup);
+		multi_override = LUA_HookCharacterHUD
+		(
+			HUD_HOOK(playersetup), luahuddrawlist_playersetup, setupm_player,
+			x << FRACBITS, chary << FRACBITS, scale,
+			setupm_fakeskin, multi_spr2, multi_frame, 1, setupm_fakecolor->color,
+			(multi_tics >> FRACBITS) + 1, multi_paused
+		);
+	}
+
+	LUA_HUD_DrawList(luahuddrawlist_playersetup);
+
+	if (multi_override == true)
+		goto colordraw;
+
+	colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_CACHE);
+
 	sprframe = &sprdef->spriteframes[multi_frame];
 	patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
 	if (sprframe->flip & 1) // Only for first sprite
 		flags |= V_FLIP; // This sprite is left/right flipped!
 
-#define chary (y+64)
+	M_DrawPlayerSetupFollowItem(x, chary, scale, flags & ~V_FLIP);
 
 	V_DrawFixedPatch(
 		x<<FRACBITS,
@@ -12477,6 +12521,20 @@ static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t colo
 		V_DrawFill(x, y+(i*h), w, h, color.ramp[i]);
 }
 
+static void M_InitPlayerSetupLua(void)
+{
+	// I'd really like to assume that the drawlist has been destroyed,
+	// but it appears M_ClearMenus has options not to call exit routines...
+	// so that doesn't seem safe to me??
+	if (!LUA_HUD_IsDrawListValid(luahuddrawlist_playersetup))
+	{
+		LUA_HUD_DestroyDrawList(luahuddrawlist_playersetup);
+		luahuddrawlist_playersetup = LUA_HUD_CreateDrawList();
+	}
+	LUA_HUD_ClearDrawList(luahuddrawlist_playersetup);
+	multi_override = false;
+}
+
 // Handle 1P/2P MP Setup
 static void M_HandleSetupMultiPlayer(INT32 choice)
 {
@@ -12522,6 +12580,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
 				}
 				while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin)));
 				multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+				M_SetPlayerSetupFollowItem();
 			}
 			else if (itemOn == 2) // player color
 			{
@@ -12562,6 +12621,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
 				}
 				while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin)));
 				multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+				M_SetPlayerSetupFollowItem();
 			}
 			else if (itemOn == 2) // player color
 			{
@@ -12682,7 +12742,7 @@ static void M_SetupMultiPlayer(INT32 choice)
 	(void)choice;
 
 	multi_frame = 0;
-	multi_tics = 4*FRACUNIT;
+	multi_tics = MULTI_DURATION;
 
 	strcpy(setupm_name, cv_playername.string);
 
@@ -12712,6 +12772,10 @@ static void M_SetupMultiPlayer(INT32 choice)
 	MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
 
 	multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+	M_SetPlayerSetupFollowItem();
+
+	// allocate and/or clear Lua player setup draw list
+	M_InitPlayerSetupLua();
 
 	MP_PlayerSetupDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&MP_PlayerSetupDef);
@@ -12723,7 +12787,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
 	(void)choice;
 
 	multi_frame = 0;
-	multi_tics = 4*FRACUNIT;
+	multi_tics = MULTI_DURATION;
 
 	strcpy (setupm_name, cv_playername2.string);
 
@@ -12753,6 +12817,10 @@ static void M_SetupMultiPlayer2(INT32 choice)
 	MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
 
 	multi_spr2 = P_GetSkinSprite2(skins[setupm_fakeskin], SPR2_WALK, NULL);
+	M_SetPlayerSetupFollowItem();
+
+	// allocate and/or clear Lua player setup draw list
+	M_InitPlayerSetupLua();
 
 	MP_PlayerSetupDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&MP_PlayerSetupDef);
@@ -12774,6 +12842,12 @@ static boolean M_QuitMultiPlayerMenu(void)
 	// send color if changed
 	if (setupm_fakecolor->color != setupm_cvcolor->value)
 		COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor->color));
+
+	// de-allocate Lua player setup drawlist
+	LUA_HUD_DestroyDrawList(luahuddrawlist_playersetup);
+	luahuddrawlist_playersetup = NULL;
+	multi_override = false;
+
 	return true;
 }
 
@@ -13041,7 +13115,10 @@ static void M_SetupScreenshotMenu(void)
 	{
 		item->status = IT_GRAYEDOUT;
 		if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that
+		{
 			itemOn = op_screenshot_storagelocation;
+			M_UpdateItemOn();
+		}
 	}
 	else
 #endif
diff --git a/src/m_misc.c b/src/m_misc.c
index 55c5485a149a2b2c43e48fab973c5ad898091036..a60bbea98d2e2b47cf3fea0dae652d26b6aa4763 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2208,6 +2208,8 @@ int M_JumpWordReverse(const char *line, int offset)
 {
 	int (*is)(int);
 	int c;
+	if (offset == 0) // Don't let "--offset" later result in a negative value
+		return 0;
 	c = line[--offset];
 	if (isspace(c))
 		is = isspace;
diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c
index d735e8132172e66a5c808ef572b7edca1ae8a8cc..2bf9d2dde7cb60266687282748142af5e676c917 100644
--- a/src/netcode/d_clisrv.c
+++ b/src/netcode/d_clisrv.c
@@ -1362,7 +1362,7 @@ static void IdleUpdate(void)
 
 	for (i = 1; i < MAXPLAYERS; i++)
 	{
-		if (cv_idletime.value && playeringame[i] && playernode[i] != UINT8_MAX && !players[i].quittime && !players[i].spectator && !players[i].bot && !IsPlayerAdmin(i) && i != serverplayer)
+		if (cv_idletime.value && playeringame[i] && playernode[i] != UINT8_MAX && !players[i].quittime && !players[i].spectator && !players[i].bot && !IsPlayerAdmin(i) && i != serverplayer && gamestate == GS_LEVEL)
 		{
 			if (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons)
 				players[i].lastinputtime = 0;
diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c
index e073a863c90bbe88025fd6f7ed9f4d0decac23d0..f7b98c4dbaff55d58481b5c439623a92fcd4e4c4 100644
--- a/src/netcode/d_netcmd.c
+++ b/src/netcode/d_netcmd.c
@@ -691,6 +691,7 @@ void D_RegisterClientCommands(void)
 	COM_AddCommand("timedemo", Command_Timedemo_f, 0);
 	COM_AddCommand("stopdemo", Command_Stopdemo_f, COM_LUA);
 	COM_AddCommand("playintro", Command_Playintro_f, COM_LUA);
+	CV_RegisterVar(&cv_resyncdemo);
 
 	COM_AddCommand("resetcamera", Command_ResetCamera_f, COM_LUA);
 
@@ -1308,7 +1309,7 @@ static void SendNameAndColor(void)
 
 		SetColorLocal(consoleplayer, cv_playercolor.value);
 
-		if (splitscreen)
+		if (splitscreen || (!pickedchar && stricmp(cv_skin.string, skins[consoleplayer]->name) != 0))
 			SetSkinLocal(consoleplayer, R_SkinAvailable(cv_skin.string));
 		else
 			SetSkinLocal(consoleplayer, pickedchar);
@@ -4608,7 +4609,7 @@ static void Command_ExitLevel_f(void)
 			SendNetXCmd(XD_EXITLEVEL, NULL, 0);
 			return;
 		}
-		
+
 		// Allow exiting without cheating if at least one player beat the level
 		// Consistent with just setting playersforexit to one
 		if (splitscreen || multiplayer)
@@ -4622,7 +4623,7 @@ static void Command_ExitLevel_f(void)
 					continue;
 				if (players[i].lives <= 0)
 					continue;
-		
+
 				if ((players[i].pflags & PF_FINISHED) || players[i].exiting)
 				{
 					SendNetXCmd(XD_EXITLEVEL, NULL, 0);
@@ -4630,7 +4631,7 @@ static void Command_ExitLevel_f(void)
 				}
 			}
 		}
-		
+
 		// Only consider it a cheat if we're not allowed to go to the next map
 		if (M_CampaignWarpIsCheat(gametype, G_GetNextMap(true, true) + 1, serverGamedata))
 			CONS_Alert(CONS_NOTICE, M_GetText("Cheats must be enabled to force exit to a locked level!\n"));
@@ -4769,7 +4770,7 @@ static void Command_Cheats_f(void)
 			G_SetUsedCheats(false);
 		return;
 	}
-	
+
 	if (usedCheats)
 		CONS_Printf(M_GetText("Cheats are enabled, the game cannot be saved.\n"));
 	else
@@ -4941,6 +4942,8 @@ static boolean Skin2_CanChange(const char *valstr)
   */
 static void Skin_OnChange(void)
 {
+	pickedchar = R_SkinAvailable(cv_skin.string);
+
 	if (!Playing())
 		return;
 
diff --git a/src/netcode/i_tcp.c b/src/netcode/i_tcp.c
index 04018d84a81a353e2470a9f0ccdc1ab7b35fc18d..3600c47c9e5ce4f253e7114c584e1d0023ec1afa 100644
--- a/src/netcode/i_tcp.c
+++ b/src/netcode/i_tcp.c
@@ -114,16 +114,10 @@ typedef union
 } mysockaddr_t;
 
 	#ifdef HAVE_MINIUPNPC
-	#ifdef MINIUPNP_STATICLIB
-		#include "miniwget.h"
-		#include "miniupnpc.h"
-		#include "upnpcommands.h"
-	#else
-		#include "miniupnpc/miniwget.h"
-		#include "miniupnpc/miniupnpc.h"
-		#include "miniupnpc/upnpcommands.h"
-	#endif
-		static boolean UPNP_support = true;
+	#include "miniupnpc/miniwget.h"
+	#include "miniupnpc/miniupnpc.h"
+	#include "miniupnpc/upnpcommands.h"
+	static boolean UPNP_support = true;
 	#endif // HAVE_MINIUPNC
 
 #define MAXBANS 100
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 428c023ff3e6333b7f62cda4e3f528762b1d606e..59934aa40d01291d7686097fca5c6ad2da1e2193 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -4189,8 +4189,10 @@ static void P_DoBoss5Death(mobj_t *mo)
 			if (!P_MobjWasRemoved(pole))
 			{
 				P_SetScale(pole, 2*FRACUNIT, true);
+				pole->angle = mo->tracer->angle;
 				pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
 				pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
+				
 				P_SetTarget(&pole->tracer, P_SpawnMobj(
 					pole->x, pole->y,
 					pole->z - 256*FRACUNIT,
@@ -4199,7 +4201,7 @@ static void P_DoBoss5Death(mobj_t *mo)
 				{
 					pole->tracer->flags |= MF_NOCLIPTHING;
 					P_SetScale(pole->tracer, 2*FRACUNIT, true);
-					pole->angle = pole->tracer->angle = mo->tracer->angle;
+					pole->tracer->angle = mo->tracer->angle;
 					pole->tracer->momx = pole->momx;
 					pole->tracer->momy = pole->momy;
 
@@ -4863,7 +4865,7 @@ void A_AttractChase(mobj_t *actor)
 	else
 		actor->flags2 &= ~MF2_DONTDRAW;
 
-	// Turn flingrings back into regular rings if attracted.
+	// Turn rings into flingrings if shield is lost or out of range
 	if (actor->tracer && actor->tracer->player
 		&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
 	{
@@ -4895,8 +4897,9 @@ void A_AttractChase(mobj_t *actor)
 	// If a FlingRing gets attracted by a shield, change it into a normal ring.
 	if (actor->type == (mobjtype_t)actor->info->reactiontime)
 	{
-		P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance);
-		P_RemoveMobj(actor);
+		actor->type = mobjinfo[actor->type].painchance; // Become the regular version of the fling object.
+		actor->flags = mobjinfo[actor->type].flags;		// Reset actor flags.
+		P_SetMobjState(actor, actor->info->spawnstate); // Go to regular object's spawn state.
 		return;
 	}
 
@@ -5192,7 +5195,7 @@ void A_SetSolidSteam(mobj_t *actor)
 		return;
 
 	actor->flags &= ~MF_NOCLIP;
-	actor->flags |= MF_SOLID;
+	actor->flags |= MF_SPECIAL;
 	if (!(actor->flags2 & MF2_AMBUSH))
 	{
 		if (P_RandomChance(FRACUNIT/8))
@@ -5222,7 +5225,7 @@ void A_UnsetSolidSteam(mobj_t *actor)
 	if (LUA_CallAction(A_UNSETSOLIDSTEAM, actor))
 		return;
 
-	actor->flags &= ~MF_SOLID;
+	actor->flags &= ~MF_SPECIAL;
 	actor->flags |= MF_NOCLIP;
 }
 
@@ -14855,12 +14858,18 @@ void A_RolloutRock(mobj_t *actor)
 
 	if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health)
 		actor->flags |= MF_PUSHABLE;
+	else if (actor->tracer->eflags & MFE_VERTICALFLIP)
+	{
+		actor->flags2 |= MF2_OBJECTFLIP;
+		actor->eflags |= MFE_VERTICALFLIP;
+	}
 	else
 	{
-		actor->flags2 = (actor->flags2 & ~MF2_OBJECTFLIP) | (actor->tracer->flags2 & MF2_OBJECTFLIP);
-		actor->eflags = (actor->eflags & ~MFE_VERTICALFLIP) | (actor->tracer->eflags & MFE_VERTICALFLIP);
+		actor->flags2 &= ~MF2_OBJECTFLIP;
+		actor->eflags &= ~MFE_VERTICALFLIP;
 	}
 
+
 	actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves
 
 	if (actor->eflags & MFE_JUSTHITFLOOR)
diff --git a/src/p_inter.c b/src/p_inter.c
index 5534f7865c23afc2d70ceae209e6ea432f6223f8..e73cd1fce675ee17721e6236e7dc764ede8e9d69 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -392,17 +392,50 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 		}
 	}
 
+	// Ignore multihits in "ouchie" mode
+	if (special->flags & (MF_ENEMY | MF_BOSS) && special->flags2 & MF2_FRET)
+		return;
+
 	player = toucher->player;
-	I_Assert(player != NULL); // Only players can touch stuff!
 
-	if (player->spectator)
-		return;
+	if (player)
+	{
+		if (player->spectator)
+			return;
 
-	// Ignore multihits in "ouchie" mode
-	if (special->flags & (MF_ENEMY|MF_BOSS) && special->flags2 & MF2_FRET)
-		return;
+		// Some hooks may assume that the toucher is a player, so we keep it in here.
+		if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special))
+			return;
+	}
+
+	if (player || (toucher->flags & MF_PUSHABLE)) // Special area for objects that are interactable by both player AND MF_PUSHABLE.
+	{
+		if (special->type == MT_STEAM)
+		{
+			if (player && player->mo->state == &states[player->mo->info->painstate]) // can't use gas jets when player is in pain!
+				return;
 
-	if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special))
+			fixed_t speed = special->info->mass; // gas jets use this for the vertical thrust
+			SINT8 flipval = P_MobjFlip(special); // virtually everything here centers around the thruster's gravity, not the object's!
+
+			if (special->state != &states[S_STEAM1]) // Only when it bursts
+				return;
+
+			toucher->eflags |= MFE_SPRUNG;
+			toucher->momz = flipval * FixedMul(speed, FixedSqrt(FixedMul(special->scale, toucher->scale))); // scale the speed with both objects' scales, just like with springs!
+
+			if (player)
+			{
+				P_ResetPlayer(player);
+				if (player->panim != PA_FALL)
+					P_SetMobjState(toucher, S_PLAY_FALL);
+			}
+
+			return; // Don't collect it!
+		}
+	}
+
+	if (!player) // Only players can touch stuff!
 		return;
 
 	// 0 = none, 1 = elemental pierce, 2 = bubble bounce
@@ -1332,7 +1365,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			}
 			break;
 		case MT_NIGHTSEXTRATIME:
-			if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
+			if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE || (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS))))
 				return;
 			if (!G_IsSpecialStage(gamemap))
 			{
@@ -1344,7 +1377,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			else
 			{
 				for (i = 0; i < MAXPLAYERS; i++)
-					if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
+					if (playeringame[i] && (player->powers[pw_carry] == CR_NIGHTSMODE || (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS))))
 					{
 						players[i].nightstime += special->info->speed;
 						players[i].startedtime += special->info->speed;
@@ -1881,6 +1914,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				toucher->tracer->flags2 = (toucher->tracer->flags2 & ~MF2_AMBUSH) | destambush;
 			}
 			return;
+
 		default: // SOC or script pickup
 			if (player->bot && player->bot != BOT_MPAI)
 				return;
@@ -3606,7 +3640,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
 		if (player->nightstime > 5*TICRATE)
 			player->nightstime -= 5*TICRATE;
 		else
-			player->nightstime = 0;
+			player->nightstime = 1;
 	}
 
 	P_DoPlayerPain(player, inflictor, source);
diff --git a/src/p_local.h b/src/p_local.h
index 0bcd6da1dd7f42b5e56650d8a2cc70fd775f1e22..249c3cd4b6de5248140c00e2dfc2332081a5d00e 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -307,21 +307,19 @@ void P_PushableThinker(mobj_t *mobj);
 void P_SceneryThinker(mobj_t *mobj);
 
 
-fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(mobj, sector, NULL, x, y, line, false, false)
-#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(mobj, sector, NULL, x, y, line, true, false)
-#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
-#define P_GetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false)
-#define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(mobj, src, bound, mobj->x, mobj->y, NULL, src != bound, true)
-#define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(mobj, src, bound, mobj->x, mobj->y, NULL, src == bound, true)
-
-fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
-#define P_CameraGetFloorZ(mobj, sector, x, y, line) P_CameraFloorZ(mobj, sector, NULL, x, y, line, false, false)
-#define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_CameraCeilingZ(mobj, sector, NULL, x, y, line, true, false)
-#define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_CameraCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
-#define P_CameraGetFOFBottomZ(mobj, sector, fof, x, y, line) P_CameraFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false)
+fixed_t P_MobjFloorZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect);
+fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect);
+#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(sector, NULL, x, y, mobj->radius, line, false, false)
+#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(sector, NULL, x, y, mobj->radius, line, true, false)
+#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, false, false)
+#define P_GetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, true, false)
+#define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(src, bound, mobj->x, mobj->y, mobj->radius, NULL, src != bound, true)
+#define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(src, bound, mobj->x, mobj->y, mobj->radius, NULL, src == bound, true)
+
+#define P_CameraGetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(sector, NULL, x, y, mobj->radius, line, false, false)
+#define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(sector, NULL, x, y, mobj->radius, line, true, false)
+#define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, false, false)
+#define P_CameraGetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, true, false)
 
 boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
 boolean P_CheckDeathPitCollide(mobj_t *mo);
diff --git a/src/p_map.c b/src/p_map.c
index 7b64fe3bb782de111f0b70053306ce851a1ea190..668a8ab6413ccda17adccf994c18e7f2dc58f58d 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -389,7 +389,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 	{
 		INT32 pflags;
 		UINT8 secondjump;
-		boolean washoming;
 
 		if (spring->flags & MF_ENEMY) // Spring shells
 			P_SetTarget(&spring->target, object);
@@ -421,7 +420,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		{
 			boolean wasSpindashing = object->player->dashspeed > 0 && (object->player->charability2 == CA2_SPINDASH);
 
-			pflags = object->player->pflags & (PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_THOKKED | PF_BOUNCING); // I still need these.
+			pflags = object->player->pflags & (PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_BOUNCING); // I still need these.
 
 			if (wasSpindashing) // Ensure we're in the rolling state, and not spindash.
 				P_SetMobjState(object, S_PLAY_ROLL);
@@ -433,7 +432,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 			}
 		}
 		secondjump = object->player->secondjump;
-		washoming = object->player->homing;
 		P_ResetPlayer(object->player);
 
 		if (spring->info->painchance == 1) // For all those ancient, SOC'd abilities.
@@ -445,8 +443,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		{
 			object->player->pflags |= (pflags &~ PF_STARTJUMP);
 			object->player->secondjump = secondjump;
-			if (washoming)
-				object->player->pflags &= ~PF_THOKKED;
 		}
 		else if (!vertispeed)
 		{
@@ -502,72 +498,56 @@ springstate:
 	return final;
 }
 
-static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
+static void P_DoFan(mobj_t *fan, mobj_t *object)
 {
 	player_t *p = object->player; // will be NULL if not a player
 	fixed_t zdist; // distance between bottoms
-	fixed_t speed = spring->info->mass; // conveniently, both fans and gas jets use this for the vertical thrust
-	SINT8 flipval = P_MobjFlip(spring); // virtually everything here centers around the thruster's gravity, not the object's!
+	fixed_t speed = fan->info->mass; // fans use this for the vertical thrust
+	SINT8 flipval = P_MobjFlip(fan); // virtually everything here centers around the thruster's gravity, not the object's!
 
-	if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
+	if (p && object->state == &states[object->info->painstate]) // can't use fans when player is in pain!
 		return;
 
 	// is object's top below thruster's position? if not, calculate distance between their bottoms
-	if (spring->eflags & MFE_VERTICALFLIP)
+	if (fan->eflags & MFE_VERTICALFLIP)
 	{
-		if (object->z > spring->z + spring->height)
+		if (object->z > fan->z + fan->height)
 			return;
-		zdist = (spring->z + spring->height) - (object->z + object->height);
+		zdist = (fan->z + fan->height) - (object->z + object->height);
 	}
 	else
 	{
-		if (object->z + object->height < spring->z)
+		if (object->z + object->height < fan->z)
 			return;
-		zdist = object->z - spring->z;
+		zdist = object->z - fan->z;
 	}
 
 	object->standingslope = NULL; // No launching off at silly angles for you.
 
-	switch (spring->type)
+	switch (fan->type)
 	{
 		case MT_FAN: // fan
-			if (zdist > (spring->health << FRACBITS)) // max z distance determined by health (set by map thing args[0])
+			if (zdist > (fan->health << FRACBITS)) // max z distance determined by health (set by map thing args[0])
 				break;
-			if (flipval*object->momz >= FixedMul(speed, spring->scale)) // if object's already moving faster than your best, don't bother
+			if (flipval*object->momz >= FixedMul(speed, fan->scale)) // if object's already moving faster than your best, don't bother
 				break;
 			if (p && (p->climbing || p->pflags & PF_GLIDING)) // doesn't affect Knux when he's using his abilities!
 				break;
 
-			object->momz += flipval*FixedMul(speed/4, spring->scale);
+			object->momz += flipval*FixedMul(speed/4, fan->scale);
 
 			// limit the speed if too high
-			if (flipval*object->momz > FixedMul(speed, spring->scale))
-				object->momz = flipval*FixedMul(speed, spring->scale);
+			if (flipval*object->momz > FixedMul(speed, fan->scale))
+				object->momz = flipval*FixedMul(speed, fan->scale);
 
 			if (p && !p->powers[pw_tailsfly] && !p->powers[pw_carry]) // doesn't reset anim for Tails' flight
 			{
 				P_ResetPlayer(p);
 				P_SetMobjState(object, S_PLAY_FALL);
-				P_SetTarget(&object->tracer, spring);
+				P_SetTarget(&object->tracer, fan);
 				p->powers[pw_carry] = CR_FAN;
 			}
 			break;
-		case MT_STEAM: // Steam
-			if (zdist > FixedMul(16*FRACUNIT, spring->scale))
-				break;
-			if (spring->state != &states[S_STEAM1]) // Only when it bursts
-				break;
-
-			object->eflags |= MFE_SPRUNG;
-			object->momz = flipval*FixedMul(speed, FixedSqrt(FixedMul(spring->scale, object->scale))); // scale the speed with both objects' scales, just like with springs!
-
-			if (p)
-			{
-				P_ResetPlayer(p);
-				if (p->panim != PA_FALL)
-					P_SetMobjState(object, S_PLAY_FALL);
-			}
-			break;
 		default:
 			break;
 	}
@@ -1043,7 +1023,6 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 		if ((thing->flags & MF_PUSHABLE) // not carrying a player
 			&& (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something
 			&& !(tmthing->player->powers[pw_ignorelatch] & (1<<15))
-			&& ((tmthing->eflags & MFE_VERTICALFLIP) == (thing->eflags & MFE_VERTICALFLIP))
 			&& (P_MobjFlip(tmthing)*tmthing->momz <= 0)
 			&& ((!(tmthing->eflags & MFE_VERTICALFLIP) && abs(thing->z + thing->height - tmthing->z) < (thing->height>>2))
 				|| (tmthing->eflags & MFE_VERTICALFLIP && abs(tmthing->z + tmthing->height - thing->z) < (thing->height>>2))))
@@ -1057,6 +1036,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 			P_SetTarget(&tmthing->tracer, thing);
 			if (!P_IsObjectOnGround(thing))
 				thing->momz += tmthing->momz;
+
 			return CHECKTHING_COLLIDE;
 		}
 	}
@@ -1484,13 +1464,13 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 	}
 
 	// check for special pickup
-	if (thing->flags & MF_SPECIAL && tmthing->player)
+	if (thing->flags & MF_SPECIAL)
 	{
 		P_TouchSpecialThing(thing, tmthing, true); // can remove thing
 		return CHECKTHING_COLLIDE;
 	}
 	// check again for special pickup
-	if (tmthing->flags & MF_SPECIAL && thing->player)
+	if (tmthing->flags & MF_SPECIAL)
 	{
 		P_TouchSpecialThing(tmthing, thing, true); // can remove thing
 		return CHECKTHING_COLLIDE;
@@ -1578,15 +1558,15 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 
 	if (thing->flags & MF_PUSHABLE)
 	{
-		if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM)
-			P_DoFanAndGasJet(tmthing, thing);
+		if (tmthing->type == MT_FAN)
+			P_DoFan(tmthing, thing);
 	}
 
 	if (tmthing->flags & MF_PUSHABLE)
 	{
-		if (thing->type == MT_FAN || thing->type == MT_STEAM)
+		if (thing->type == MT_FAN)
 		{
-			P_DoFanAndGasJet(thing, tmthing);
+			P_DoFan(thing, tmthing);
 			return CHECKTHING_COLLIDE;
 		}
 		else if (thing->flags & MF_SPRING)
@@ -1679,8 +1659,8 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 			}
 		}
 
-		if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM)
-			P_DoFanAndGasJet(tmthing, thing);
+		if (tmthing->type == MT_FAN)
+			P_DoFan(tmthing, thing);
 	}
 
 	if (tmthing->player) // Is the moving/interacting object the player?
@@ -1688,8 +1668,8 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 		if (!tmthing->health)
 			return CHECKTHING_IGNORE;
 
-		if (thing->type == MT_FAN || thing->type == MT_STEAM)
-			P_DoFanAndGasJet(thing, tmthing);
+		if (thing->type == MT_FAN)
+			P_DoFan(thing, tmthing);
 		else if (thing->flags & MF_SPRING && tmthing->player->powers[pw_carry] != CR_MINECART)
 		{
 			if ( thing->z <= tmthing->z + tmthing->height
@@ -1755,8 +1735,8 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
 	// not solid not blocked
 	unsigned collide = CHECKTHING_NOCOLLIDE;
 
-	if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
-		; // springs, gas jets and springs should never be able to step up onto a player
+	if ((tmthing->flags & MF_SPRING || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
+		; // springs and spikes should never be able to step up onto a player
 	// z checking at last
 	// Treat noclip things as non-solid!
 	else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 82b86471522ee3b2cbeebbedfb1e28c1c4438501..200b89cff93c815bac281c8b270ae4975de219c6 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -500,8 +500,24 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 			INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
 
 			if (texnum) {
+				fixed_t scaley = abs(side->scaley_mid);
+				fixed_t offsetvalue = FixedDiv(side->rowoffset + side->offsety_mid, scaley);
+				fixed_t midopentop, midopenbottom;
+
+				if (linedef->flags & ML_NOSKEW)
+				{
+					// Use the sector's actual heights if the midtexture is not skewed
+					midopentop = min(front->ceilingheight, back->ceilingheight);
+					midopenbottom = max(front->floorheight, back->floorheight);
+				}
+				else
+				{
+					midopentop = opentop;
+					midopenbottom = openbottom;
+				}
+
 				// Get the midtexture's height
-				texheight = textures[texnum]->height << FRACBITS;
+				texheight = FixedDiv(textureheight[texnum], scaley);
 
 				// Set texbottom and textop to the Z coordinates of the texture's boundaries
 #if 0
@@ -509,26 +525,26 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 				// on non-solid polyobjects should NEVER happen in the future
 				if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
 					if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat
-						texbottom = back->floorheight + side->rowoffset + side->offsety_mid;
-						textop = back->ceilingheight + side->rowoffset + side->offsety_mid;
+						texbottom = back->floorheight + offsetvalue;
+						textop = back->ceilingheight + offsetvalue;
 					} else if (linedef->flags & ML_MIDTEX) {
-						texbottom = back->floorheight + side->rowoffset + side->offsety_mid;
+						texbottom = back->floorheight + offsetvalue;
 						textop = texbottom + texheight*(side->repeatcnt+1);
 					} else {
-						textop = back->ceilingheight + side->rowoffset + side->offsety_mid;
+						textop = back->ceilingheight + offsetvalue;
 						texbottom = textop - texheight*(side->repeatcnt+1);
 					}
 				} else
 #endif
 				{
 					if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat
-						texbottom = openbottom + side->rowoffset + side->offsety_mid;
-						textop = opentop + side->rowoffset + side->offsety_mid;
+						texbottom = midopenbottom + offsetvalue;
+						textop = midopentop + offsetvalue;
 					} else if (linedef->flags & ML_MIDPEG) {
-						texbottom = openbottom + side->rowoffset + side->offsety_mid;
+						texbottom = midopenbottom + offsetvalue;
 						textop = texbottom + texheight*(side->repeatcnt+1);
 					} else {
-						textop = opentop + side->rowoffset + side->offsety_mid;
+						textop = midopentop + offsetvalue;
 						texbottom = textop - texheight*(side->repeatcnt+1);
 					}
 				}
@@ -539,11 +555,21 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 				delta2 = abs(thingtop - texmid);
 
 				if (delta1 > delta2) { // Below
-					if (opentop > texbottom)
+					if (opentop > texbottom) {
 						opentop = texbottom;
+						if (linedef->flags & ML_NOSKEW)
+							opentopslope = NULL; // Object is not actually on a slope
+						else
+							opentopslope = linedef->midtexslope;
+					}
 				} else { // Above
-					if (openbottom < textop)
+					if (openbottom < textop) {
 						openbottom = textop;
+						if (linedef->flags & ML_NOSKEW)
+							openbottomslope = NULL; // Object is not actually on a slope
+						else
+							openbottomslope = linedef->midtexslope;
+					}
 				}
 			}
 		}
@@ -1026,23 +1052,35 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *))
 //
 boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *))
 {
-	mobj_t *mobj;
-	blocknode_t *block;
+	mobj_t *bnext = NULL;
+	blocknode_t *block, *next = NULL;
 
 	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
 		return true;
 
 	// Check interaction with the objects in the blockmap.
-	for (block = blocklinks[y*bmapwidth + x]; block; block = block->mnext)
+	for (block = blocklinks[y*bmapwidth + x]; block; block = next)
 	{
-		mobj = block->mobj;
+		next = block->mnext;
+		if (next)
+			P_SetTarget(&bnext, next->mobj); // We want to note our reference to bnext here in case it is MF_NOTHINK and gets removed!
 
-		if (!func(mobj))
+		if (!func(block->mobj))
+		{
+			P_SetTarget(&bnext, NULL);
 			return false;
-		if (P_MobjWasRemoved(tmthing)) // func just broke blockmap chain, cannot continue.
+		}
+
+		if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue.
+		|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
+		{
+			P_SetTarget(&bnext, NULL);
 			return true;
+		}
 	}
 
+	P_SetTarget(&bnext, NULL);
+
 	return true;
 }
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 55be8e54fc4e36684e20279ac134d7de4772780f..fbbae5a1e4b5cb122ff353591b037a91f284ceef 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -85,9 +85,15 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum)
 //
 static void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
 {
-	INT32 animlength = (mobj->sprite == SPR_PLAY && mobj->skin)
-		? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1
-		: st->var1;
+	INT32 animlength;
+
+	if (mobj->sprite == SPR_PLAY && mobj->skin)
+	{
+		spritedef_t *spritedef = P_GetSkinSpritedef(mobj->skin, mobj->sprite2);
+		animlength = (INT32)(spritedef->numframes);
+	}
+	else
+		animlength = st->var1;
 
 	if (!(st->frame & FF_ANIMATE))
 		return;
@@ -138,8 +144,13 @@ FUNCINLINE static ATTRINLINE void P_CycleStateAnimation(mobj_t *mobj)
 	}
 
 	// sprite2 version of above
-	if (mobj->skin && (((++mobj->frame) & FF_FRAMEMASK) >= (UINT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes)))
-		mobj->frame &= ~FF_FRAMEMASK;
+	if (mobj->skin)
+	{
+		spritedef_t *spritedef = P_GetSkinSpritedef(mobj->skin, mobj->sprite2);
+		UINT32 anim_length = (UINT32)(spritedef->numframes);
+		if (((++mobj->frame) & FF_FRAMEMASK) >= anim_length)
+			mobj->frame &= ~FF_FRAMEMASK;
+	}
 }
 
 //
@@ -395,31 +406,23 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 		{
 			skin_t *skin = ((skin_t *)mobj->skin);
 			UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
-			UINT8 numframes, spr2;
+			UINT8 numframes;
+			UINT16 spr2;
 
 			if (skin)
 			{
-				UINT16 stateframe = st->frame;
+				spr2 = P_GetStateSprite2(st);
 
-				// Add/Remove FF_SPR2SUPER based on certain conditions
-				if (player->charflags & SF_NOSUPERSPRITES || (player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & SF_NONIGHTSSUPER)))
-					stateframe = stateframe & ~FF_SPR2SUPER;
-				else if (player->powers[pw_super] || (player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & SF_SUPER)))
-					stateframe = stateframe | FF_SPR2SUPER;
+				// Add or remove SPR2F_SUPER based on certain conditions
+				spr2 = P_ApplySuperFlagToSprite2(spr2, mobj);
 
-				if (stateframe & FF_SPR2SUPER)
-				{
-					if (mobj->eflags & MFE_FORCENOSUPER)
-						stateframe = stateframe & ~FF_SPR2SUPER;
-				}
-				else if (mobj->eflags & MFE_FORCESUPER)
-					stateframe = stateframe | FF_SPR2SUPER;
+				// Get the needed sprite2 and frame number
+				spr2 = P_GetSkinSprite2(skin, spr2, mobj->player);
 
-				// Get the sprite2 and frame number
-				spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), mobj->player);
-				numframes = skin->sprites[spr2].numframes;
+				spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
+				numframes = sprdef->numframes;
 
-				if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0)
+				if (state == S_PLAY_STND && (spr2 & SPR2F_SUPER) && sprdef[SPR2_WAIT].numframes == 0)
 					mobj->tics = -1;	// If no super wait, don't wait at all
 			}
 			else
@@ -432,12 +435,19 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 			if (mobj->sprite != SPR_PLAY)
 			{
 				mobj->sprite = SPR_PLAY;
-				frame = 0;
+				frame = P_GetSprite2StateFrame(st);
 			}
 			else if (mobj->sprite2 != spr2)
 			{
-				if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2))
-					frame = numframes/2;
+				if (st->frame & FF_SPR2MIDSTART)
+				{
+					if (numframes && P_RandomChance(FRACUNIT/2))
+						frame = numframes/2;
+					else
+						frame = 0;
+				}
+				else if (numframes)
+					frame = P_GetSprite2StateFrame(st) % numframes;
 				else
 					frame = 0;
 			}
@@ -452,6 +462,7 @@ static boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 					{
 						if (mobj->frame & FF_FRAMEMASK)
 							mobj->frame--;
+
 						return P_SetPlayerMobjState(mobj, st->var1);
 					}
 				}
@@ -539,26 +550,23 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 		{
 			skin_t *skin = ((skin_t *)mobj->skin);
 			UINT16 frame = (mobj->frame & FF_FRAMEMASK)+1;
-			UINT8 numframes, spr2;
+			UINT8 numframes;
+			UINT16 spr2;
 
 			if (skin)
 			{
-				UINT16 stateframe = st->frame;
+				spr2 = P_GetStateSprite2(st);
 
-				// Add/Remove FF_SPR2SUPER based on certain conditions
-				if (stateframe & FF_SPR2SUPER)
-				{
-					if (mobj->eflags & MFE_FORCENOSUPER)
-						stateframe = stateframe & ~FF_SPR2SUPER;
-				}
-				else if (mobj->eflags & MFE_FORCESUPER)
-					stateframe = stateframe | FF_SPR2SUPER;
+				// Add or remove SPR2F_SUPER based on certain conditions
+				spr2 = P_ApplySuperFlagToSprite2(spr2, mobj);
+
+				// Get the needed sprite2 and frame number
+				spr2 = P_GetSkinSprite2(skin, spr2, NULL);
 
-				// Get the sprite2 and frame number
-				spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), NULL);
-				numframes = skin->sprites[spr2].numframes;
+				spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
+				numframes = sprdef->numframes;
 
-				if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0)
+				if (state == S_PLAY_STND && (spr2 & SPR2F_SUPER) && sprdef[SPR2_WAIT].numframes == 0)
 					mobj->tics = -1;	// If no super wait, don't wait at all
 			}
 			else
@@ -571,12 +579,19 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 			if (mobj->sprite != SPR_PLAY)
 			{
 				mobj->sprite = SPR_PLAY;
-				frame = 0;
+				frame = P_GetSprite2StateFrame(st);
 			}
 			else if (mobj->sprite2 != spr2)
 			{
-				if ((st->frame & FF_SPR2MIDSTART) && numframes && P_RandomChance(FRACUNIT/2))
-					frame = numframes/2;
+				if (st->frame & FF_SPR2MIDSTART)
+				{
+					if (numframes && P_RandomChance(FRACUNIT/2))
+						frame = numframes/2;
+					else
+						frame = 0;
+				}
+				else if (numframes)
+					frame = P_GetSprite2StateFrame(st) % numframes;
 				else
 					frame = 0;
 			}
@@ -591,6 +606,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 					{
 						if (mobj->frame & FF_FRAMEMASK)
 							mobj->frame--;
+
 						return P_SetMobjState(mobj, st->var1);
 					}
 				}
@@ -1092,9 +1108,8 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line,
 		);
 }
 
-fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+fixed_t P_MobjFloorZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect)
 {
-	I_Assert(mobj != NULL);
 	I_Assert(sector != NULL);
 
 	if (sector->f_slope) {
@@ -1103,14 +1118,14 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 
 		// Get the corner of the object that should be the highest on the slope
 		if (slope->d.x < 0)
-			testx = mobj->radius;
+			testx = radius;
 		else
-			testx = -mobj->radius;
+			testx = -radius;
 
 		if (slope->d.y < 0)
-			testy = mobj->radius;
+			testy = radius;
 		else
-			testy = -mobj->radius;
+			testy = -radius;
 
 		if ((slope->zdelta > 0) ^ !!(lowest)) {
 			testx = -testx;
@@ -1125,7 +1140,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 			return P_GetSlopeZAt(slope, testx, testy);
 
 		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
+		if (perfect && boundsec) {
 			size_t i;
 			line_t *ld;
 			fixed_t bbox[4];
@@ -1136,10 +1151,10 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 			else
 				finalheight = INT32_MIN;
 
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
+			bbox[BOXLEFT] = x-radius;
+			bbox[BOXRIGHT] = x+radius;
+			bbox[BOXTOP] = y+radius;
+			bbox[BOXBOTTOM] = y-radius;
 			for (i = 0; i < boundsec->linecount; i++) {
 				ld = boundsec->lines[i];
 
@@ -1151,9 +1166,9 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 					continue;
 
 				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+					finalheight = min(finalheight, HighestOnLine(radius, x, y, ld, slope, true));
 				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+					finalheight = max(finalheight, HighestOnLine(radius, x, y, ld, slope, false));
 			}
 
 			return finalheight;
@@ -1164,14 +1179,13 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 		if (line == NULL)
 			return P_GetSlopeZAt(slope, x, y);
 
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+		return HighestOnLine(radius, x, y, line, slope, lowest);
 	} else // Well, that makes it easy. Just get the floor height
 		return sector->floorheight;
 }
 
-fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect)
 {
-	I_Assert(mobj != NULL);
 	I_Assert(sector != NULL);
 
 	if (sector->c_slope) {
@@ -1180,14 +1194,14 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 
 		// Get the corner of the object that should be the highest on the slope
 		if (slope->d.x < 0)
-			testx = mobj->radius;
+			testx = radius;
 		else
-			testx = -mobj->radius;
+			testx = -radius;
 
 		if (slope->d.y < 0)
-			testy = mobj->radius;
+			testy = radius;
 		else
-			testy = -mobj->radius;
+			testy = -radius;
 
 		if ((slope->zdelta > 0) ^ !!(lowest)) {
 			testx = -testx;
@@ -1202,7 +1216,7 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 			return P_GetSlopeZAt(slope, testx, testy);
 
 		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
+		if (perfect && boundsec) {
 			size_t i;
 			line_t *ld;
 			fixed_t bbox[4];
@@ -1213,10 +1227,10 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 			else
 				finalheight = INT32_MIN;
 
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
+			bbox[BOXLEFT] = x-radius;
+			bbox[BOXRIGHT] = x+radius;
+			bbox[BOXTOP] = y+radius;
+			bbox[BOXBOTTOM] = y-radius;
 			for (i = 0; i < boundsec->linecount; i++) {
 				ld = boundsec->lines[i];
 
@@ -1228,9 +1242,9 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 					continue;
 
 				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+					finalheight = min(finalheight, HighestOnLine(radius, x, y, ld, slope, true));
 				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+					finalheight = max(finalheight, HighestOnLine(radius, x, y, ld, slope, false));
 			}
 
 			return finalheight;
@@ -1241,165 +1255,11 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 		if (line == NULL)
 			return P_GetSlopeZAt(slope, x, y);
 
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+		return HighestOnLine(radius, x, y, line, slope, lowest);
 	} else // Well, that makes it easy. Just get the ceiling height
 		return sector->ceilingheight;
 }
 
-// Now do the same as all above, but for cameras because apparently cameras are special?
-fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
-{
-	I_Assert(mobj != NULL);
-	I_Assert(sector != NULL);
-
-	if (sector->f_slope) {
-		fixed_t testx, testy;
-		pslope_t *slope = sector->f_slope;
-
-		// Get the corner of the object that should be the highest on the slope
-		if (slope->d.x < 0)
-			testx = mobj->radius;
-		else
-			testx = -mobj->radius;
-
-		if (slope->d.y < 0)
-			testy = mobj->radius;
-		else
-			testy = -mobj->radius;
-
-		if ((slope->zdelta > 0) ^ !!(lowest)) {
-			testx = -testx;
-			testy = -testy;
-		}
-
-		testx += x;
-		testy += y;
-
-		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
-		if (R_IsPointInSector(boundsec ? boundsec : sector, testx, testy))
-			return P_GetSlopeZAt(slope, testx, testy);
-
-		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
-			size_t i;
-			line_t *ld;
-			fixed_t bbox[4];
-			fixed_t finalheight;
-
-			if (lowest)
-				finalheight = INT32_MAX;
-			else
-				finalheight = INT32_MIN;
-
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
-			for (i = 0; i < boundsec->linecount; i++) {
-				ld = boundsec->lines[i];
-
-				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
-				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
-					continue;
-
-				if (P_BoxOnLineSide(bbox, ld) != -1)
-					continue;
-
-				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
-				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
-			}
-
-			return finalheight;
-		}
-
-		// If we're just testing for base sector location (no collision line), just go for the center's spot...
-		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
-		if (line == NULL)
-			return P_GetSlopeZAt(slope, x, y);
-
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
-	} else // Well, that makes it easy. Just get the floor height
-		return sector->floorheight;
-}
-
-fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
-{
-	I_Assert(mobj != NULL);
-	I_Assert(sector != NULL);
-
-	if (sector->c_slope) {
-		fixed_t testx, testy;
-		pslope_t *slope = sector->c_slope;
-
-		// Get the corner of the object that should be the highest on the slope
-		if (slope->d.x < 0)
-			testx = mobj->radius;
-		else
-			testx = -mobj->radius;
-
-		if (slope->d.y < 0)
-			testy = mobj->radius;
-		else
-			testy = -mobj->radius;
-
-		if ((slope->zdelta > 0) ^ !!(lowest)) {
-			testx = -testx;
-			testy = -testy;
-		}
-
-		testx += x;
-		testy += y;
-
-		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
-		if (R_IsPointInSector(boundsec ? boundsec : sector, testx, testy))
-			return P_GetSlopeZAt(slope, testx, testy);
-
-		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
-		if (perfect) {
-			size_t i;
-			line_t *ld;
-			fixed_t bbox[4];
-			fixed_t finalheight;
-
-			if (lowest)
-				finalheight = INT32_MAX;
-			else
-				finalheight = INT32_MIN;
-
-			bbox[BOXLEFT] = x-mobj->radius;
-			bbox[BOXRIGHT] = x+mobj->radius;
-			bbox[BOXTOP] = y+mobj->radius;
-			bbox[BOXBOTTOM] = y-mobj->radius;
-			for (i = 0; i < boundsec->linecount; i++) {
-				ld = boundsec->lines[i];
-
-				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
-				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
-					continue;
-
-				if (P_BoxOnLineSide(bbox, ld) != -1)
-					continue;
-
-				if (lowest)
-					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
-				else
-					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
-			}
-
-			return finalheight;
-		}
-
-		// If we're just testing for base sector location (no collision line), just go for the center's spot...
-		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
-		if (line == NULL)
-			return P_GetSlopeZAt(slope, x, y);
-
-		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
-	} else // Well, that makes it easy. Just get the ceiling height
-		return sector->ceilingheight;
-}
 static void P_PlayerFlip(mobj_t *mo)
 {
 	if (!mo->player)
@@ -1525,6 +1385,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 				case MT_WATERDROP:
 				case MT_CYBRAKDEMON:
 					gravityadd >>= 1;
+					break;
 				default:
 					break;
 			}
@@ -2331,8 +2192,8 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
 	if (mo->player && mo->player->pflags & PF_GODMODE)
 		return false;
 
-	fixed_t sectorFloor = P_GetSectorFloorZAt(mo->subsector->sector, mo->x, mo->y);
-	fixed_t sectorCeiling = P_GetSectorCeilingZAt(mo->subsector->sector, mo->x, mo->y);
+	fixed_t sectorFloor = P_GetSpecialBottomZ(mo, mo->subsector->sector, mo->subsector->sector);
+	fixed_t sectorCeiling = P_GetSpecialTopZ(mo, mo->subsector->sector, mo->subsector->sector);
 
 	if (((mo->z <= sectorFloor
 		&& ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_FLOOR))
@@ -11193,7 +11054,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 
 	if (mobj->skin) // correct inadequecies above.
 	{
-		mobj->sprite2 = P_GetSkinSprite2(mobj->skin, (mobj->frame & FF_FRAMEMASK), NULL);
+		mobj->sprite2 = P_GetSkinSprite2(mobj->skin, P_GetStateSprite2(mobj->state), NULL);
 		mobj->frame &= ~FF_FRAMEMASK;
 	}
 
diff --git a/src/p_mobj.h b/src/p_mobj.h
index fd75f75c6ef5e6022e55cfbe69a25043e1f0d6a5..2f013a2f30fac7f7d117cb190fcbc5bd1db17e54 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -308,7 +308,7 @@ typedef struct mobj_s
 	angle_t spriteroll, old_spriteroll, old_spriteroll2;
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
-	UINT8 sprite2; // player sprites
+	UINT16 sprite2; // player sprites
 	UINT16 anim_duration; // for FF_ANIMATE states
 
 	UINT32 renderflags; // render flags
@@ -451,7 +451,7 @@ typedef struct precipmobj_s
 	angle_t spriteroll, old_spriteroll, old_spriteroll2;
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
-	UINT8 sprite2; // player sprites
+	UINT16 sprite2; // player sprites
 	UINT16 anim_duration; // for FF_ANIMATE states
 
 	UINT32 renderflags; // render flags
diff --git a/src/p_pspr.h b/src/p_pspr.h
index 69e5eeeb3fc902e12782cf63672731aa5ebd0c36..6510190f118fb639c52a22576dd911023d3b134c 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -35,11 +35,11 @@
 #pragma interface
 #endif
 
-/// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 63, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER)
+/// \brief Frame flags: only the frame number - 0 to 256 (Frames from 0 to 255, Sprite2 number uses 0 to 127 plus FF_SPR2SUPER)
 #define FF_FRAMEMASK 0xff
 
 /// \brief Frame flags - SPR2: Super sprite2
-#define FF_SPR2SUPER 0x80
+#define FF_SPR2SUPER SPR2F_SUPER //TODO: 2.3: remove this backwards compat hack
 /// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation
 #define FF_SPR2ENDSTATE 0x100
 /// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation
@@ -97,6 +97,11 @@
 /// \brief Frame flags - Animate: Start at a random place in the animation (mutually exclusive with above)
 #define FF_RANDOMANIM 0x40000000
 
+/// \brief Animation flags: Bits used for the animation ID
+#define SPR2F_MASK 0x3FF
+/// \brief Animation flags: "Super" flag
+#define SPR2F_SUPER 0x400
+
 /**	\brief translucency tables
 
 	\todo add another asm routine which use the fg and bg indexes in the
diff --git a/src/p_saveg.c b/src/p_saveg.c
index c385bd8e1aff3a8b57b978e70ac1941878dcc764..5e4d6d0760441e6bc94c6815824b8b7e1ab38c80 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -261,6 +261,7 @@ static void P_NetArchivePlayers(void)
 		WRITEUINT8(save_p, players[i].marelap);
 		WRITEUINT8(save_p, players[i].marebonuslap);
 		WRITEUINT32(save_p, players[i].marebegunat);
+		WRITEUINT32(save_p, players[i].lastmaretime);
 		WRITEUINT32(save_p, players[i].startedtime);
 		WRITEUINT32(save_p, players[i].finishedtime);
 		WRITEUINT32(save_p, players[i].lapbegunat);
@@ -492,6 +493,7 @@ static void P_NetUnArchivePlayers(void)
 		players[i].marelap = READUINT8(save_p);
 		players[i].marebonuslap = READUINT8(save_p);
 		players[i].marebegunat = READUINT32(save_p);
+		players[i].lastmaretime = READUINT32(save_p);
 		players[i].startedtime = READUINT32(save_p);
 		players[i].finishedtime = READUINT32(save_p);
 		players[i].lapbegunat = READUINT32(save_p);
@@ -1882,7 +1884,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 		diff |= MD_TICS;
 	if (mobj->sprite != mobj->state->sprite)
 		diff |= MD_SPRITE;
-	if (mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK))
+	if (mobj->sprite == SPR_PLAY && mobj->sprite2 != P_GetStateSprite2(mobj->state))
 		diff |= MD_SPRITE;
 	if (mobj->frame != mobj->state->frame)
 		diff |= MD_FRAME;
@@ -2066,7 +2068,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 	if (diff & MD_SPRITE) {
 		WRITEUINT16(save_p, mobj->sprite);
 		if (mobj->sprite == SPR_PLAY)
-			WRITEUINT8(save_p, mobj->sprite2);
+			WRITEUINT16(save_p, mobj->sprite2);
 	}
 	if (diff & MD_FRAME)
 	{
@@ -3096,12 +3098,12 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 	if (diff & MD_SPRITE) {
 		mobj->sprite = READUINT16(save_p);
 		if (mobj->sprite == SPR_PLAY)
-			mobj->sprite2 = READUINT8(save_p);
+			mobj->sprite2 = READUINT16(save_p);
 	}
 	else {
 		mobj->sprite = mobj->state->sprite;
 		if (mobj->sprite == SPR_PLAY)
-			mobj->sprite2 = mobj->state->frame&FF_FRAMEMASK;
+			mobj->sprite2 = P_GetStateSprite2(mobj->state);
 	}
 	if (diff & MD_FRAME)
 	{
diff --git a/src/p_setup.c b/src/p_setup.c
index 93c4937c4d40118230bb128af9d4f345143816a0..c4b4a35b3610beeb973624035a4d5454f69f49db 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -358,6 +358,8 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
 	mapheaderinfo[num]->marathonnext = 0;
 	mapheaderinfo[num]->startrings = 0;
 	mapheaderinfo[num]->sstimer = 90;
+	for (UINT8 n = 0; n < 8; n++)
+		mapheaderinfo[num]->nightstimer[n] = 0;
 	mapheaderinfo[num]->ssspheres = 1;
 	mapheaderinfo[num]->gravity = FRACUNIT/2;
 	mapheaderinfo[num]->keywords[0] = '\0';
@@ -525,6 +527,29 @@ UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade)
 	return score;
 }
 
+void P_AddNiGHTSTimes(INT16 i, char *gtext)
+{
+	char *spos = gtext;
+	
+	for (UINT8 n = 0; n < 8; n++)
+	{
+		if (spos != NULL)
+		{
+			mapheaderinfo[i]->nightstimer[n] = atoi(spos);
+			CONS_Debug(DBG_SETUP, "%u ", atoi(spos));
+			// Grab next comma
+			spos = strchr(spos, ',');
+			if (spos)
+				++spos;
+		}
+		else
+		{
+			mapheaderinfo[i]->nightstimer[n] = 0;
+		}
+	}
+
+}
+
 //
 // levelflats
 //
@@ -806,13 +831,15 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
 
 static void P_SpawnEmeraldHunt(void)
 {
-	INT32 emer[3], num[MAXHUNTEMERALDS], i, randomkey;
+	INT32 emer[3], num[MAXHUNTEMERALDS], i, amount, randomkey;
 	fixed_t x, y, z;
 
 	for (i = 0; i < numhuntemeralds; i++)
 		num[i] = i;
 
-	for (i = 0; i < 3; i++)
+	amount = min(numhuntemeralds, 3);
+
+	for (i = 0; i < amount; i++)
 	{
 		// generate random index, shuffle afterwards
 		randomkey = P_RandomKey(numhuntemeralds--);
@@ -1088,6 +1115,8 @@ static void P_InitializeLinedef(line_t *ld)
 	ld->callcount = 0;
 	ld->secportal = UINT32_MAX;
 
+	ld->midtexslope = NULL;
+
 	// cph 2006/09/30 - fix sidedef errors right away.
 	// cph 2002/07/20 - these errors are fatal if not fixed, so apply them
 	for (j = 0; j < 2; j++)
@@ -1834,6 +1863,10 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
 		sectors[i].specialflags |= SSF_JUMPFLIP;
 	else if (fastcmp(param, "gravityoverride") && fastcmp("true", val))
 		sectors[i].specialflags |= SSF_GRAVITYOVERRIDE;
+	else if (fastcmp(param, "nophysics_floor") && fastcmp("true", val))
+		sectors[i].specialflags |= SSF_NOPHYSICSFLOOR;
+	else if (fastcmp(param, "nophysics_ceiling") && fastcmp("true", val))
+		sectors[i].specialflags |= SSF_NOPHYSICSCEILING;
 	else if (fastcmp(param, "friction"))
 		sectors[i].friction = FLOAT_TO_FIXED(atof(val));
 	else if (fastcmp(param, "gravity"))
@@ -2700,13 +2733,18 @@ static void P_WriteTextmap(void)
 			fprintf(f, "rotationfloor = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].floorangle)));
 		if (wsectors[i].ceilingangle != 0)
 			fprintf(f, "rotationceiling = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].ceilingangle)));
-        if (wsectors[i].extra_colormap)
+		if (wsectors[i].extra_colormap)
 		{
 			INT32 lightcolor = P_RGBAToColor(wsectors[i].extra_colormap->rgba);
 			UINT8 lightalpha = R_GetRgbaA(wsectors[i].extra_colormap->rgba);
 			INT32 fadecolor = P_RGBAToColor(wsectors[i].extra_colormap->fadergba);
 			UINT8 fadealpha = R_GetRgbaA(wsectors[i].extra_colormap->fadergba);
 
+			// For now, convert alpha from new (0-255) to old 'A-Z' (0-25) range
+			// TODO: remove this limitation in a backwards-compatible way (UDMF versioning?)
+			lightalpha /= 10;
+			fadealpha /= 10;
+
 			if (lightcolor != 0)
 				fprintf(f, "lightcolor = %d;\n", lightcolor);
 			if (lightalpha != 25)
@@ -2968,7 +3006,8 @@ static void P_LoadTextmap(void)
 		P_InitializeSector(sc);
 		if (textmap_colormap.used)
 		{
-			// Convert alpha values from old 0-25 (A-Z) range to 0-255 range
+			// Convert alpha values from old 'A-Z' (0-25) range to new UINT8 (0-255) range
+			// TODO: remove this limitation in a backwards-compatible way (UDMF versioning?)
 			UINT8 lightalpha = (textmap_colormap.lightalpha * 102) / 10;
 			UINT8 fadealpha = (textmap_colormap.fadealpha * 102) / 10;
 			
@@ -2981,13 +3020,17 @@ static void P_LoadTextmap(void)
 		{
 			sc->f_slope = P_MakeSlopeViaEquationConstants(textmap_planefloor.a, textmap_planefloor.b, textmap_planefloor.c, textmap_planefloor.d);
 			sc->hasslope = true;
+			if (sc->specialflags & SSF_NOPHYSICSFLOOR)
+				sc->f_slope->flags |= SL_NOPHYSICS;
 		}
 
 		if (textmap_planeceiling.defined == (PD_A|PD_B|PD_C|PD_D))
 		{
 			sc->c_slope = P_MakeSlopeViaEquationConstants(textmap_planeceiling.a, textmap_planeceiling.b, textmap_planeceiling.c, textmap_planeceiling.d);
 			sc->hasslope = true;
-		}
+			if (sc->specialflags & SSF_NOPHYSICSCEILING)
+				sc->c_slope->flags |= SL_NOPHYSICS;
+        }
 
 		TextmapFixFlatOffsets(sc);
 	}
diff --git a/src/p_setup.h b/src/p_setup.h
index 61c445c6523ba28a589c54364bd644e701282110..da38d4c08b152f87fab59517706c3ccbc7544339 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -87,5 +87,6 @@ UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare);
 UINT8 P_HasGrades(INT16 map, UINT8 mare);
 UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade);
 UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade);
+void P_AddNiGHTSTimes(INT16 i, char *gtext);
 
 #endif
diff --git a/src/p_slopes.c b/src/p_slopes.c
index e75d36edefe8d8484cb0c9bebb4d02d5f1b1e174..c2bacad9ed02ede75af92692d7b5e9ad0e6fb02d 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -28,6 +28,8 @@
 pslope_t *slopelist = NULL;
 UINT16 slopecount = 0;
 
+static void P_UpdateMidtextureSlopesForSector(sector_t *sector);
+
 // Calculate line normal
 void P_CalculateSlopeNormal(pslope_t *slope)
 {
@@ -212,6 +214,9 @@ void T_DynamicSlopeLine (dynlineplanethink_t* th)
 		slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta);
 		slope->moved = true;
 		P_CalculateSlopeNormal(slope);
+		P_UpdateMidtextureSlopesForSector(srcline->frontsector);
+		if (srcline->backsector)
+			P_UpdateMidtextureSlopesForSector(srcline->backsector);
 	}
 }
 
@@ -232,6 +237,12 @@ void T_DynamicSlopeVert (dynvertexplanethink_t* th)
 	}
 
 	ReconfigureViaVertexes(th->slope, th->vex[0], th->vex[1], th->vex[2]);
+
+	for (i = 0; i < 3; i++)
+	{
+		if (th->secs[i])
+			P_UpdateMidtextureSlopesForSector(th->secs[i]);
+	}
 }
 
 static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent)
@@ -758,6 +769,111 @@ pslope_t *P_MakeSlopeViaEquationConstants(const double a, const double b, const
 	return ret;
 }
 
+static pslope_t *P_GetReferenceSlopeForMidtexture(line_t *line)
+{
+	if (line->flags & ML_MIDPEG)
+	{
+		// Line has ML_MIDPEG, so use the floor slope
+		fixed_t frontheight = P_GetSectorFloorZAt(line->frontsector, line->v1->x, line->v1->y);
+		fixed_t backheight = P_GetSectorFloorZAt(line->backsector, line->v1->x, line->v1->y);
+
+		if (frontheight > backheight)
+		{
+			return line->frontsector->f_slope;
+		}
+		else
+		{
+			return line->backsector->f_slope;
+		}
+	}
+	else
+	{
+		// Line does not have ML_MIDPEG, so use the ceiling slope
+		fixed_t frontheight = P_GetSectorCeilingZAt(line->frontsector, line->v1->x, line->v1->y);
+		fixed_t backheight = P_GetSectorCeilingZAt(line->backsector, line->v1->x, line->v1->y);
+
+		if (frontheight < backheight)
+		{
+			return line->frontsector->c_slope;
+		}
+		else
+		{
+			return line->backsector->c_slope;
+		}
+	}
+
+	return NULL;
+}
+
+// Updates a slope for a solid midtexture based on the slope of the sector it's in.
+static void P_UpdateSolidMidtextureSlope(line_t *line, pslope_t *ref)
+{
+	pslope_t *slope = line->midtexslope;
+
+	if (ref == NULL)
+		return;
+
+	// Set origin
+	vector3_t origin;
+	origin.x = line->v1->x;
+	origin.y = line->v1->y;
+	origin.z = P_GetSlopeZAt(ref, origin.x, origin.y);
+	FV3_Copy(&slope->o, &origin);
+
+	// Get where the line ends
+	vector3_t point;
+	point.x = line->v2->x;
+	point.y = line->v2->y;
+	point.z = P_GetSlopeZAt(ref, point.x, point.y);
+
+	// Get length of the line
+	fixed_t extent = R_PointToDist2(0, 0, line->dx, line->dy);
+
+	// Precalculate variables
+	slope->zdelta = FixedDiv(origin.z - point.z, extent);
+	slope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
+	slope->xydirection = line->angle;
+
+	// Precalculate the direction
+	vector2_t dir;
+	dir.x = FixedMul(FINECOSINE(slope->zangle >> ANGLETOFINESHIFT), FINECOSINE((slope->xydirection+ANGLE_180) >> ANGLETOFINESHIFT));
+	dir.y = FixedMul(FINECOSINE(slope->zangle >> ANGLETOFINESHIFT), FINESINE((slope->xydirection+ANGLE_180) >> ANGLETOFINESHIFT));
+	FV2_Copy(&slope->d, &dir);
+
+	P_CalculateSlopeNormal(slope);
+
+	// Calling P_CalculateSlopeVectors is not necessary.
+	slope->moved = true;
+}
+
+// Goes through every line in the sector and updates the midtexture slope if it is present
+static void P_UpdateMidtextureSlopesForSector(sector_t *sector)
+{
+	for (size_t i = 0; i < sector->linecount; i++)
+	{
+		if (sector->lines[i]->midtexslope != NULL)
+			P_UpdateSolidMidtextureSlope(sector->lines[i], P_GetReferenceSlopeForMidtexture(sector->lines[i]));
+	}
+}
+
+// Creates a solid midtexture slope for the line if possible
+static void P_CreateSolidMidtextureSlope(line_t *line)
+{
+	if (line->backsector == NULL) // Ignore single-sided lines (of course)
+		return;
+
+	if ((line->flags & ML_MIDSOLID) == 0) // Ignore if the midtexture is not solid
+		return;
+
+	pslope_t *ref = P_GetReferenceSlopeForMidtexture(line);
+	if (ref)
+	{
+		line->midtexslope = Slope_Add(ref->flags & SL_NOPHYSICS);
+
+		P_UpdateSolidMidtextureSlope(line, ref);
+	}
+}
+
 /// Initializes and reads the slopes from the map data.
 void P_SpawnSlopes(const boolean fromsave) {
 	size_t i;
@@ -785,14 +901,21 @@ void P_SpawnSlopes(const boolean fromsave) {
 
 	/// Copies slopes from tagged sectors via line specials.
 	/// \note Doesn't actually copy, but instead they share the same pointers.
+	// Also, creates midtexture slopes.
 	for (i = 0; i < numlines; i++)
-		switch (lines[i].special)
+	{
+		line_t *line = &lines[i];
+
+		switch (line->special)
 		{
 			case 720:
-				P_CopySectorSlope(&lines[i]);
+				P_CopySectorSlope(line);
 			default:
 				break;
 		}
+
+		P_CreateSolidMidtextureSlope(line);
+	}
 }
 
 /// Initializes slopes.
@@ -810,10 +933,10 @@ void P_InitSlopes(void)
 // Returns the height of the sloped plane at (x, y) as a fixed_t
 fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y)
 {
-	fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) +
-	               FixedMul(y - slope->o.y, slope->d.y);
+	fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) / 2 +
+	               FixedMul(y - slope->o.y, slope->d.y) / 2;
 
-	return slope->o.z + FixedMul(dist, slope->zdelta);
+	return slope->o.z + FixedMul(dist, slope->zdelta) * 2;
 }
 
 // Like P_GetSlopeZAt but falls back to z if slope is NULL
diff --git a/src/p_spec.c b/src/p_spec.c
index 805817fb033c465b33059c24fbefb52432173444..78cf460632970ac108512f29f1fd2111aea5f462 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3684,7 +3684,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 
 		case 466: // Set level failure state
 			{
-				if (line->args[1])
+				if (line->args[0])
 				{
 					stagefailed = false;
 					CONS_Debug(DBG_GAMELOGIC, "Stage can be completed successfully!\n");
diff --git a/src/p_tick.c b/src/p_tick.c
index 6d7d4fd969fb70964e4e0cf6663d26bd6d81e8a7..56e0fd897bfbba718885a1104224d1554790f227 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -564,6 +564,12 @@ void P_DoTeamscrambling(void)
 		CV_SetValue(&cv_teamscramble, 0);
 }
 
+
+//
+// P_DoSpecialStageStuff()
+//
+// For old-style (non-NiGHTS) special stages
+//
 static inline void P_DoSpecialStageStuff(void)
 {
 	boolean stillalive = false;
@@ -601,7 +607,15 @@ static inline void P_DoSpecialStageStuff(void)
 				if (--players[i].nightstime > 6)
 				{
 					if (P_IsLocalPlayer(&players[i]) && oldnightstime > 10*TICRATE && players[i].nightstime <= 10*TICRATE)
-						S_ChangeMusicInternal("_drown", false);
+					{
+						if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
+						{
+							S_FadeMusic(0, 10*MUSICRATE);
+							S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
+						}
+						else
+							S_ChangeMusicInternal("_drown", false);
+					}
 					stillalive = true;
 				}
 				else if (!players[i].exiting)
diff --git a/src/p_user.c b/src/p_user.c
index b69db5da814d2476616647d4bd3c4c7657a05491..7ad5bccbb58db303a28c9b3fe438b7effdea3c90 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -776,7 +776,7 @@ static void P_DeNightserizePlayer(player_t *player)
 // NiGHTS Time!
 void P_NightserizePlayer(player_t *player, INT32 nighttime)
 {
-	UINT8 oldmare, oldmarelap, oldmarebonuslap;
+	UINT8 oldmare, oldmarelap, oldmarebonuslap, newmare;
 
 	// Bots can't be NiGHTSerized, silly!1 :P
 	if (player->bot)
@@ -797,6 +797,11 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		}
 	}
 
+	// Use mare-specific time limit if specified
+	newmare = P_FindLowestMare();
+	if (mapheaderinfo[gamemap-1]->nightstimer[newmare] > 0)
+		nighttime = mapheaderinfo[gamemap-1]->nightstimer[newmare];
+
 	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_SHIELDDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
 	player->homing = 0;
 	player->mo->fuse = 0;
@@ -867,7 +872,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 				continue;
 
 			players[i].texttimer = (3 * TICRATE) - 10;
-			players[i].textvar = 4; // Score and grades
+			players[i].textvar = NTV_BONUSTIMEEND; // Score and grades
 			players[i].lastmare = players[i].mare;
 			players[i].lastmarelap = players[i].marelap;
 			players[i].lastmarebonuslap = players[i].marebonuslap;
@@ -885,7 +890,8 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 			}
 
 			// Add score to leaderboards now
-			G_AddTempNightsRecords(player, players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1);
+			player->lastmaretime = leveltime - player->marebegunat;
+			G_AddTempNightsRecords(player, players[i].marescore, player->lastmaretime, players[i].mare + 1);
 
 			// transfer scores anyway
 			players[i].totalmarescore += players[i].marescore;
@@ -906,12 +912,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		player->lastmarelap = oldmarelap;
 		player->lastmarebonuslap = oldmarebonuslap;
 		player->texttimer = 4*TICRATE;
-		player->textvar = 4; // Score and grades
+		player->textvar = NTV_BONUSTIMEEND; // Score and grades
 		player->finishedspheres = (INT16)(player->spheres);
 		player->finishedrings = (INT16)(player->rings);
 
 		// Add score to temp leaderboards
-		G_AddTempNightsRecords(player, player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1));
+		player->lastmaretime = leveltime - player->marebegunat;
+		G_AddTempNightsRecords(player, player->marescore, player->lastmaretime, (UINT8)(oldmare + 1));
 
 		// Starting a new mare, transfer scores
 		player->totalmarescore += player->marescore;
@@ -924,7 +931,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 	}
 	else
 	{
-		player->textvar = 5; // Nothing, just tells it to go to the GET n RINGS/SPHERES text in a bit
+		player->textvar = NTV_NONE; // Nothing, just tells it to go to the GET n RINGS/SPHERES text in a bit
 		player->texttimer = 40;
 
 		// Don't show before title card
@@ -1082,6 +1089,13 @@ void P_ResetPlayer(player_t *player)
 		if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer))
 		{
 			player->mo->tracer->flags |= MF_PUSHABLE;
+
+			// goose the mom a little bit to trigger gravity to process for a tic
+			if (player->mo->tracer->eflags & MFE_VERTICALFLIP)
+				player->mo->tracer->momz -= 1;
+			else
+				player->mo->tracer->momz += 1;
+
 			P_SetTarget(&player->mo->tracer->tracer, NULL);
 		}
 		P_SetTarget(&player->mo->tracer, NULL);
@@ -1400,7 +1414,7 @@ void P_DoSuperDetransformation(player_t *player)
 	if (!G_CoopGametype())
 		player->powers[pw_flashing] = flashingtics-1;
 
-	if (player->mo->sprite2 & FF_SPR2SUPER)
+	if (player->mo->sprite2 & SPR2F_SUPER)
 		P_SetMobjState(player->mo, player->mo->state-states);
 
 	// Inform the netgame that the champion has fallen in the heat of battle.
@@ -2365,7 +2379,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 		if (dorollstuff)
 		{
 			if ((player->charability2 == CA2_SPINDASH) && !((player->pflags & (PF_SPINNING|PF_THOKKED)) == PF_THOKKED) && !(player->charability == CA_THOK && player->secondjump)
-			&& (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
+			&& (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) >= (5*player->mo->scale)))
 				player->pflags = (player->pflags|PF_SPINNING) & ~PF_THOKKED;
 			else if (!(player->pflags & PF_STARTDASH))
 				player->pflags &= ~PF_SPINNING;
@@ -4539,6 +4553,13 @@ void P_DoJump(player_t *player, boolean soundandstate, boolean allowflip)
 					player->mo->momz += player->mo->tracer->momz;
 				if (!P_IsObjectOnGround(player->mo->tracer))
 					P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true);
+
+				// goose the mom a little bit to trigger gravity to process for a tic
+				if (player->mo->tracer->eflags & MFE_VERTICALFLIP)
+					player->mo->tracer->momz -= 1;
+				else
+					player->mo->tracer->momz += 1;
+
 				player->mo->tracer->flags |= MF_PUSHABLE;
 				P_SetTarget(&player->mo->tracer->tracer, NULL);
 			}
@@ -4714,7 +4735,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 				 // Revving
 				else if ((cmd->buttons & BT_SPIN) && (player->pflags & PF_STARTDASH))
 				{
-					if (player->speed > 5*player->mo->scale)
+					if (player->speed >= 5*player->mo->scale)
 					{
 						player->pflags &= ~PF_STARTDASH;
 						P_SetMobjState(player->mo, S_PLAY_ROLL);
@@ -4754,9 +4775,8 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 					if (!player->spectator)
 						S_StartSound(player->mo, sfx_spin);
 				}
-				else
 				// Catapult the player from a spindash rev!
-				if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
+				else if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
 				{
 					player->pflags &= ~PF_STARTDASH;
 					if (player->powers[pw_carry] == CR_BRAKGOOP)
@@ -7005,7 +7025,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
 					{
 						players[i].bonustime = true;
 						players[i].texttimer = 4*TICRATE;
-						players[i].textvar = 1; // Time Bonus
+						players[i].textvar = NTV_BONUSTIMESTART; // Time Bonus
 						players[i].finishedtime = players[i].nightstime;
 						if (!G_IsSpecialStage(gamemap))
 							P_AddPlayerScore(&players[i], (players[i].finishedtime/TICRATE) * 100);
@@ -7089,12 +7109,12 @@ static void P_DoNiGHTSCapsule(player_t *player)
 			{
 				S_StartScreamSound(player->mo, sfx_lose);
 				player->texttimer = 4*TICRATE;
-				player->textvar = 3; // Get more rings!
+				player->textvar = NTV_GETMORESPHERES; // Get more spheres/chips!
 				player->capsule->reactiontime = 0;
 				player->capsule->extravalue1 = player->capsule->cvmem =\
 				 player->capsule->cusval = player->capsule->movecount =\
 				 player->capsule->lastlook = player->capsule->extravalue2 = -1;
-				P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked rings
+				P_RunNightsCapsuleTouchExecutors(player->mo, false, false); // run capsule exit executors, and we lacked spheres/chips
 			}
 		}
 	}
@@ -8759,7 +8779,7 @@ void P_MovePlayer(player_t *player)
 	if (!(player->mo->momz || player->mo->momx || player->mo->momy) && !(player->mo->eflags & MFE_GOOWATER)
 	&& player->panim == PA_IDLE && !(player->powers[pw_carry]))
 		P_DoTeeter(player);
-	
+
 	// Toss a flag
 	if (G_GametypeHasTeams() && (cmd->buttons & BT_TOSSFLAG) && !(player->powers[pw_super]) && !(player->tossdelay))
 	{
@@ -9801,9 +9821,10 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0,
 static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {25, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t multiplier_cons_t[] = {{0, "MIN"}, {3*FRACUNIT, "MAX"}, {0, NULL}};
+static CV_PossibleValue_t campos_cons_t[] = { {INT32_MIN, "MIN"}, {INT32_MAX, "MAX"}, {0, NULL} };
 
-consvar_t cv_cam_dist = CVAR_INIT ("cam_curdist", "160", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
-consvar_t cv_cam_height = CVAR_INIT ("cam_curheight", "25", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
+consvar_t cv_cam_dist = CVAR_INIT ("cam_curdist", "160", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
+consvar_t cv_cam_height = CVAR_INIT ("cam_curheight", "25", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
 consvar_t cv_cam_still = CVAR_INIT ("cam_still", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_cam_speed = CVAR_INIT ("cam_speed", "0.3", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
 consvar_t cv_cam_rotate = CVAR_INIT ("cam_rotate", "0", CV_CALL|CV_NOINIT|CV_ALLOWLUA, CV_CamRotate, CV_CamRotate_OnChange);
@@ -9811,8 +9832,8 @@ consvar_t cv_cam_rotspeed = CVAR_INIT ("cam_rotspeed", "10", CV_SAVE|CV_ALLOWLUA
 consvar_t cv_cam_turnmultiplier = CVAR_INIT ("cam_turnmultiplier", "0.75", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, multiplier_cons_t, NULL);
 consvar_t cv_cam_orbit = CVAR_INIT ("cam_orbit", "Off", CV_SAVE|CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_cam_adjust = CVAR_INIT ("cam_adjust", "On", CV_SAVE|CV_ALLOWLUA, CV_OnOff, NULL);
-consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
-consvar_t cv_cam2_height = CVAR_INIT ("cam2_curheight", "25", CV_FLOAT|CV_ALLOWLUA, NULL, NULL);
+consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
+consvar_t cv_cam2_height = CVAR_INIT ("cam2_curheight", "25", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
 consvar_t cv_cam2_still = CVAR_INIT ("cam2_still", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
 consvar_t cv_cam2_speed = CVAR_INIT ("cam2_speed", "0.3", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
 consvar_t cv_cam2_rotate = CVAR_INIT ("cam2_rotate", "0", CV_CALL|CV_NOINIT|CV_ALLOWLUA, CV_CamRotate, CV_CamRotate2_OnChange);
@@ -9824,23 +9845,23 @@ consvar_t cv_cam2_adjust = CVAR_INIT ("cam2_adjust", "On", CV_SAVE|CV_ALLOWLUA,
 // [standard vs simple][p1 or p2]
 consvar_t cv_cam_savedist[2][2] = {
 	{ // standard
-		CVAR_INIT ("cam_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 	},
 	{ // simple
-		CVAR_INIT ("cam_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 
 	}
 };
 consvar_t cv_cam_saveheight[2][2] = {
 	{ // standard
-		CVAR_INIT ("cam_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_height", "40", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 	},
 	{ // simple
-		CVAR_INIT ("cam_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCamDist),
-		CVAR_INIT ("cam2_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, NULL, CV_UpdateCam2Dist),
+		CVAR_INIT ("cam_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL|CV_ALLOWLUA, campos_cons_t, CV_UpdateCam2Dist),
 
 	}
 };
@@ -11417,10 +11438,10 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	}
 	else
 	{
-		if (tails->state != states+chosenstate)
+		if (tails->state != &states[chosenstate])
 		{
 			if (states[chosenstate].sprite == SPR_PLAY)
-				tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), (states[chosenstate].frame & FF_FRAMEMASK), player);
+				tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), P_GetStateSprite2(&states[chosenstate]), player);
 			P_SetMobjState(tails, chosenstate);
 		}
 	}
@@ -12121,6 +12142,10 @@ void P_PlayerThink(player_t *player)
 				case CR_DUSTDEVIL:
 					player->drawangle += ANG20;
 					break;
+				case CR_FAN:
+					if (player->pflags & PF_ANALOGMODE) // Don't impact drawangle in any special way when on a fan
+						player->drawangle = player->mo->angle;
+					break;
 				/* -- in case we wanted to have the camera freely movable during zoom tubes
 				case CR_ZOOMTUBE:*/
 				case CR_ROPEHANG:
@@ -12447,13 +12472,13 @@ void P_PlayerThink(player_t *player)
 	if (player->texttimer)
 	{
 		--player->texttimer;
-		if (!player->texttimer && !player->exiting && player->textvar >= 4)
+		if (!player->texttimer && !player->exiting && (player->textvar == NTV_NONE || player->textvar == NTV_BONUSTIMEEND))
 		{
 			player->texttimer = 4*TICRATE;
-			player->textvar = 2; // GET n RINGS!
+			player->textvar = NTV_GETSPHERES; // GET n SPHERES/CHIPS!
 
-			if (!P_MobjWasRemoved(player->capsule) && player->capsule->health != player->capsule->spawnpoint->angle)
-				player->textvar++; // GET n MORE RINGS!
+			if (!P_MobjWasRemoved(player->capsule) && player->capsule->health != player->capsule->spawnpoint->args[1])
+				player->textvar = NTV_GETMORESPHERES; // GET n MORE SPHERES/CHIPS!
 		}
 	}
 
diff --git a/src/r_defs.h b/src/r_defs.h
index 7e92c92492a88527f2bf5685bf93797c0081494c..7a6f518ee26ca96a4a4df62f30ec7dc741855bcd 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -405,6 +405,8 @@ typedef enum
 	SSF_ROPEHANG = 1<<18,
 	SSF_JUMPFLIP = 1<<19,
 	SSF_GRAVITYOVERRIDE = 1<<20, // combine with MSF_GRAVITYFLIP
+	SSF_NOPHYSICSFLOOR = 1<<21,
+	SSF_NOPHYSICSCEILING = 1<<22,
 } sectorspecialflags_t;
 
 typedef enum
@@ -610,6 +612,8 @@ typedef struct line_s
 	INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0
 
 	UINT32 secportal; // transferred sector portal
+
+	struct pslope_s *midtexslope;
 } line_t;
 
 typedef struct
@@ -974,6 +978,8 @@ typedef struct
 #endif
 } spriteframe_t;
 
+#define MAXFRAMENUM 256
+
 //
 // A sprite definition:  a number of animation frames.
 //
diff --git a/src/r_draw.c b/src/r_draw.c
index 86f7e488c8502516cc4f36bb04b7a516385fc5ed..feb4693bb4a9ab995a099b003caf6a40e8e610f5 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -74,7 +74,7 @@ UINT8 *dc_transmap; // one of the translucency tables
 UINT8 *dc_translation;
 
 struct r_lightlist_s *dc_lightlist = NULL;
-INT32 dc_numlights = 0, dc_maxlights, dc_texheight;
+INT32 dc_numlights = 0, dc_maxlights, dc_texheight, dc_postlength;
 
 // =========================================================================
 //                      SPAN DRAWING CODE STUFF
diff --git a/src/r_draw.h b/src/r_draw.h
index 1a828312a7a922353a3ff5b969908dc61dcf0ee6..77588d7dede09edf30463c1cd749b268724a6882 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -41,8 +41,7 @@ extern UINT8 *dc_translation;
 extern struct r_lightlist_s *dc_lightlist;
 extern INT32 dc_numlights, dc_maxlights;
 
-//Fix TUTIFRUTI
-extern INT32 dc_texheight;
+extern INT32 dc_texheight, dc_postlength;
 
 // -----------------------
 // SPAN DRAWING CODE STUFF
@@ -154,8 +153,10 @@ void R_VideoErase(size_t ofs, INT32 count);
 // -----------------
 
 void R_DrawColumn_8(void);
+void R_DrawColumnClamped_8(void);
 void R_DrawShadeColumn_8(void);
 void R_DrawTranslucentColumn_8(void);
+void R_DrawTranslucentColumnClamped_8(void);
 void R_DrawDropShadowColumn_8(void);
 void R_DrawTranslatedColumn_8(void);
 void R_DrawTranslatedTranslucentColumn_8(void);
diff --git a/src/r_draw8.c b/src/r_draw8.c
index 99fb71e289343034bc6327314da0e64b0d687dab..735127f88d12daafc0161ea080195ce66d4b3db1 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -100,6 +100,98 @@ void R_DrawColumn_8(void)
 	}
 }
 
+/**	\brief The R_DrawColumnClamped_8 function
+	Same as R_DrawColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions)
+*/
+void R_DrawColumnClamped_8(void)
+{
+	INT32 count;
+	UINT8 *dest;
+	fixed_t frac;
+	fixed_t fracstep;
+
+	count = dc_yh - dc_yl;
+
+	if (count < 0) // Zero length, column does not exceed a pixel.
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
+		return;
+#endif
+
+	// Framebuffer destination address.
+	dest = &topleft[dc_yl*vid.width + dc_x];
+
+	count++;
+
+	// Determine scaling, which is the only mapping to be done.
+	fracstep = dc_iscale;
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
+
+	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
+	// This is as fast as it gets.
+	{
+		const UINT8 *source = dc_source;
+		const lighttable_t *colormap = dc_colormap;
+		INT32 heightmask = dc_texheight-1;
+		INT32 idx;
+		if (dc_texheight & heightmask)   // not a power of 2 -- killough
+		{
+			heightmask++;
+			heightmask <<= FRACBITS;
+
+			if (frac < 0)
+				while ((frac += heightmask) <  0);
+			else
+				while (frac >= heightmask)
+					frac -= heightmask;
+
+			do
+			{
+				// Re-map color indices from wall texture column
+				//  using a lighting/special effects LUT.
+				// heightmask is the Tutti-Frutti fix
+				idx = frac>>FRACBITS;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+				dest += vid.width;
+
+				// Avoid overflow.
+				if (fracstep > 0x7FFFFFFF - frac)
+					frac += fracstep - heightmask;
+				else
+					frac += fracstep;
+
+				while (frac >= heightmask)
+					frac -= heightmask;
+			} while (--count);
+		}
+		else
+		{
+			while ((count -= 2) >= 0) // texture height is a power of 2
+			{
+				idx = (frac>>FRACBITS) & heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+				dest += vid.width;
+				frac += fracstep;
+				idx = (frac>>FRACBITS) & heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+				dest += vid.width;
+				frac += fracstep;
+			}
+			if (count & 1)
+			{
+				idx = (frac>>FRACBITS) & heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = colormap[source[idx]];
+			}
+		}
+	}
+}
+
 /**	\brief The R_DrawShadeColumn_8 function
 	Experiment to make software go faster. Taken from the Boom source
 */
@@ -212,6 +304,90 @@ void R_DrawTranslucentColumn_8(void)
 	}
 }
 
+/**	\brief The R_DrawTranslucentColumnClamped_8 function
+	Same as R_DrawTranslucentColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions)
+*/
+void R_DrawTranslucentColumnClamped_8(void)
+{
+	INT32 count;
+	UINT8 *dest;
+	fixed_t frac, fracstep;
+
+	count = dc_yh - dc_yl + 1;
+
+	if (count <= 0) // Zero length, column does not exceed a pixel.
+		return;
+
+#ifdef RANGECHECK
+	if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
+		I_Error("R_DrawTranslucentColumnClamped_8: %d to %d at %d", dc_yl, dc_yh, dc_x);
+#endif
+
+	dest = &topleft[dc_yl*vid.width + dc_x];
+
+	// Looks familiar.
+	fracstep = dc_iscale;
+	frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
+
+	// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
+	// This is as fast as it gets.
+	{
+		const UINT8 *source = dc_source;
+		const UINT8 *transmap = dc_transmap;
+		const lighttable_t *colormap = dc_colormap;
+		INT32 heightmask = dc_texheight - 1;
+		INT32 idx;
+		if (dc_texheight & heightmask)
+		{
+			heightmask++;
+			heightmask <<= FRACBITS;
+
+			if (frac < 0)
+				while ((frac += heightmask) < 0)
+					;
+			else
+				while (frac >= heightmask)
+					frac -= heightmask;
+
+			do
+			{
+				// Re-map color indices from wall texture column
+				// using a lighting/special effects LUT.
+				// heightmask is the Tutti-Frutti fix
+				idx = frac>>FRACBITS;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+				dest += vid.width;
+				if ((frac += fracstep) >= heightmask)
+					frac -= heightmask;
+			}
+			while (--count);
+		}
+		else
+		{
+			while ((count -= 2) >= 0) // texture height is a power of 2
+			{
+				idx = (frac>>FRACBITS)&heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+				dest += vid.width;
+				frac += fracstep;
+				idx = (frac>>FRACBITS)&heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+				dest += vid.width;
+				frac += fracstep;
+			}
+			if (count & 1)
+			{
+				idx = (frac>>FRACBITS)&heightmask;
+				if (idx >= 0 && idx < dc_postlength)
+					*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
+			}
+		}
+	}
+}
+
 // Hack: A cut-down copy of R_DrawTranslucentColumn_8 that does not read texture
 // data since something about calculating the texture reading address for drop shadows is broken.
 // dc_texturemid and dc_iscale get wrong values for drop shadows, however those are not strictly
diff --git a/src/r_main.c b/src/r_main.c
index 4624392944a931b4178f84038de2982f9ff371cb..067b8abdbcf20d9918d582285b6efbe9374f453d 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -390,22 +390,22 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
 	return R_PointToDist2(viewx, viewy, x, y);
 }
 
-line_t *R_GetFFloorLine(const seg_t *seg, const ffloor_t *pfloor)
+line_t *R_GetFFloorLine(const line_t *line, const ffloor_t *pfloor, const sector_t *sector)
 {
 	if (pfloor->master->flags & ML_TFERLINE)
 	{
-		size_t linenum = seg->linedef - pfloor->target->lines[0];
+		size_t linenum = min((size_t)(line - sector->lines[0]), pfloor->master->frontsector->linecount);
 		return pfloor->master->frontsector->lines[0] + linenum;
 	}
 	else
 		return pfloor->master;
 }
 
-side_t *R_GetFFloorSide(const seg_t *seg, const ffloor_t *pfloor)
+side_t *R_GetFFloorSide(const line_t *line, const ffloor_t *pfloor, const sector_t *sector)
 {
 	if (pfloor->master->flags & ML_TFERLINE)
 	{
-		line_t *newline = R_GetFFloorLine(seg, pfloor);
+		line_t *newline = R_GetFFloorLine(line, pfloor, sector);
 		return &sides[newline->sidenum[0]];
 	}
 	else
diff --git a/src/r_main.h b/src/r_main.h
index aedfeb6ad0f2ca2a0caaba771f38e44ad29e1142..64a69fffe64d0096241d2eca6c25b528069e8aaf 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -86,8 +86,8 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y);
 
 boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph);
 
-line_t *R_GetFFloorLine(const seg_t *seg, const ffloor_t *pfloor);
-side_t *R_GetFFloorSide(const seg_t *seg, const ffloor_t *pfloor);
+line_t *R_GetFFloorLine(const line_t *line, const ffloor_t *pfloor, const sector_t *sector);
+side_t *R_GetFFloorSide(const line_t *line, const ffloor_t *pfloor, const sector_t *sector);
 
 // Render stats
 
diff --git a/src/r_picformats.c b/src/r_picformats.c
index e4a59f2115d3833b3f5a76e38ff4a1cdd7d4ce30..d71657021b6e2cc91efe504b49286f459461095d 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -1570,7 +1570,7 @@ static void R_ParseSpriteInfo(boolean spr2)
 	spriteinfo_t *info;
 	char *sprinfoToken;
 	size_t sprinfoTokenLength;
-	char newSpriteName[5]; // no longer dynamically allocated
+	char newSpriteName[MAXSPRITENAME + 1]; // no longer dynamically allocated
 	spritenum_t sprnum = NUMSPRITES;
 	playersprite_t spr2num = NUMPLAYERSPRITES;
 	INT32 i;
@@ -1584,31 +1584,17 @@ static void R_ParseSpriteInfo(boolean spr2)
 		I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be");
 	}
 	sprinfoTokenLength = strlen(sprinfoToken);
-	if (sprinfoTokenLength != 4)
-	{
-		I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken);
-	}
-	else
-	{
-		memset(&newSpriteName, 0, 5);
-		M_Memcpy(newSpriteName, sprinfoToken, sprinfoTokenLength);
-		// ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer
-		strupr(newSpriteName); // Just do this now so we don't have to worry about it
-	}
+	if (sprinfoTokenLength > MAXSPRITENAME)
+		I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" is longer than %d characters", sprinfoToken, MAXSPRITENAME);
+	strcpy(newSpriteName, sprinfoToken);
+	strupr(newSpriteName); // Just do this now so we don't have to worry about it
 	Z_Free(sprinfoToken);
 
 	if (!spr2)
 	{
-		for (i = 0; i <= NUMSPRITES; i++)
-		{
-			if (i == NUMSPRITES)
-				I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
-			if (!memcmp(newSpriteName,sprnames[i],4))
-			{
-				sprnum = i;
-				break;
-			}
-		}
+		sprnum = R_GetSpriteNumByName(newSpriteName);
+		if (sprnum == NUMSPRITES)
+			I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
 	}
 	else
 	{
diff --git a/src/r_picformats.h b/src/r_picformats.h
index 3ee9805d867f30cf8eec923285b24d0172038f18..098f927a5619d74ca9813d37658d5bfb75bc8f04 100644
--- a/src/r_picformats.h
+++ b/src/r_picformats.h
@@ -100,7 +100,7 @@ typedef struct
 
 typedef struct
 {
-	spriteframepivot_t pivot[64];
+	spriteframepivot_t pivot[MAXFRAMENUM];
 	boolean available;
 } spriteinfo_t;
 
diff --git a/src/r_segs.c b/src/r_segs.c
index e07ced86a7c6002c7bd127c1e2867bdae5386419..75c95aa9345702b3dd989e57c3f2f20cc1499096 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -442,26 +442,75 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 }
 
 // Loop through R_DrawMaskedColumn calls
+static fixed_t repeatscroll = 0;
+
 static void R_DrawRepeatMaskedColumn(column_t *col, unsigned lengthcol)
 {
-	while (sprtopscreen < sprbotscreen) {
+	fixed_t topscreen = sprtopscreen;
+	fixed_t bottomscreen = sprbotscreen;
+
+	fixed_t texheight = dc_texheight*spryscale;
+
+	fixed_t scroll = -repeatscroll;
+	if (scroll < 0)
+	{
+		scroll = -FixedMul((abs(scroll) % (dc_texheight*FRACUNIT)), spryscale);
+		bottomscreen += texheight; // Draw an extra time
+	}
+	else if (scroll)
+	{
+		scroll = FixedMul(scroll % (dc_texheight*FRACUNIT), spryscale);
+		topscreen -= texheight; // Draw an extra time
+	}
+
+	while (topscreen < bottomscreen)
+	{
+		sprtopscreen = topscreen + scroll;
+
 		R_DrawMaskedColumn(col, lengthcol);
+
 		if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
-			sprtopscreen = INT32_MAX;
-		else
-			sprtopscreen += dc_texheight*spryscale;
+			break;
+
+		topscreen += texheight;
 	}
+
+	sprtopscreen = sprbotscreen;
 }
 
 static void R_DrawRepeatFlippedMaskedColumn(column_t *col, unsigned lengthcol)
 {
-	while (sprtopscreen < sprbotscreen) {
+	fixed_t topscreen = sprtopscreen;
+	fixed_t bottomscreen = sprbotscreen;
+
+	fixed_t texheight = dc_texheight*spryscale;
+
+	fixed_t scroll = -repeatscroll;
+	if (scroll < 0)
+	{
+		scroll = -FixedMul((abs(scroll) % (dc_texheight*FRACUNIT)), spryscale);
+		bottomscreen += texheight; // Draw an extra time
+	}
+	else if (scroll)
+	{
+		scroll = FixedMul(scroll % (dc_texheight*FRACUNIT), spryscale);
+		topscreen -= texheight; // Draw an extra time
+	}
+
+	while (topscreen < bottomscreen)
+	{
+		sprtopscreen = topscreen + scroll;
+		sprbotscreen = bottomscreen + scroll;
+
 		R_DrawFlippedMaskedColumn(col, lengthcol);
+
 		if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
-			sprtopscreen = INT32_MAX;
-		else
-			sprtopscreen += dc_texheight*spryscale;
+			break;
+
+		topscreen += texheight;
 	}
+
+	sprtopscreen = sprbotscreen;
 }
 
 // Returns true if a fake floor is translucent.
@@ -497,7 +546,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	sector_t        tempsec;
 	INT32             templight;
 	INT32             i, p;
-	fixed_t         offsetvalue;
 	lightlist_t     *light;
 	r_lightlist_t   *rlight;
 	INT32           range;
@@ -515,6 +563,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	fixed_t wall_scalex, wall_scaley;
 	UINT8 vertflip;
 	unsigned lengthcol;
+	boolean fog = false;
+	boolean fuzzy = false;
 
 	void (*colfunc_2s) (column_t *, unsigned);
 
@@ -526,13 +576,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	curline = ds->curline;
 	backsector = pfloor->target;
 	frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
-	sidedef = R_GetFFloorSide(curline, pfloor);
-
-	colfunc = colfuncs[BASEDRAWFUNC];
+	sidedef = R_GetFFloorSide(curline->linedef, pfloor, pfloor->target);
 
 	if (pfloor->master->flags & ML_TFERLINE)
 	{
-		line_t *newline = R_GetFFloorLine(curline, pfloor);
+		line_t *newline = R_GetFFloorLine(curline->linedef, pfloor, pfloor->target);
 		do_texture_skew = newline->flags & ML_SKEWTD;
 		dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
 	}
@@ -547,7 +595,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 	if (pfloor->fofflags & FOF_TRANSLUCENT)
 	{
-		boolean fuzzy = true;
+		fuzzy = true;
 
 		// Hacked up support for alpha value in software mode Tails 09-24-2002
 		// ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021
@@ -560,17 +608,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0)
 				fuzzy = false; // Opaque
 		}
-
-		if (fuzzy)
-			colfunc = colfuncs[COLDRAWFUNC_FUZZY];
 	}
 	else if (pfloor->fofflags & FOF_FOG)
+	{
 		colfunc = colfuncs[COLDRAWFUNC_FOG];
+		fog = true;
+	}
 
 	range = max(ds->x2-ds->x1, 1);
-	//SoM: Moved these up here so they are available for my lightlist calculations
-	rw_scalestep = ds->scalestep;
-	spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
 
 	dc_numlights = 0;
 	if (frontsector->numlights)
@@ -673,9 +718,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		// Get correct light level!
 		if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
 			lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
-		else if (pfloor->fofflags & FOF_FOG)
+		else if (fog)
 			lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
-		else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
+		else if (fuzzy)
 			lightnum = LIGHTLEVELS-1;
 		else
 			lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)
@@ -703,6 +748,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		vertflip = !vertflip;
 	}
 
+	//SoM: Moved these up here so they are available for my lightlist calculations
+	// Lactozilla: Moved them back down
+	// This uses floating point math now, because the fixed-point imprecisions
+	// become more severe the bigger the texture is scaled.
+	double dwall_scaley = FixedToDouble(wall_scaley);
+	double scalestep = FixedToDouble(ds->scalestep) / dwall_scaley;
+	double yscale = (FixedToDouble(ds->scale1) + (x1 - ds->x1)*scalestep) / dwall_scaley;
+
 	thicksidecol = ffloortexturecolumn;
 
 	wall_offsetx = ds->offsetx + sidedef->offsetx_mid;
@@ -734,7 +787,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	else
 		dc_texturemid = FixedMul(*pfloor->topheight - viewz, wall_scaley);
 
-	offsetvalue = sidedef->rowoffset + sidedef->offsety_mid;
+	repeatscroll = sidedef->rowoffset + sidedef->offsety_mid;
 
 	if (dont_peg_bottom)
 	{
@@ -744,7 +797,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			dc_texturemid = FixedMul(left_bottom, wall_scaley);
 		}
 		else
-			offsetvalue -= FixedMul(*pfloor->topheight - *pfloor->bottomheight, wall_scaley);
+			repeatscroll -= FixedMul(*pfloor->topheight - *pfloor->bottomheight, wall_scaley);
 	}
 
 	if (skewslope)
@@ -753,7 +806,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		ffloortextureslide = FixedMul(R_GetSlopeTextureSlide(skewslope, lineangle), wall_scaley);
 	}
 
-	dc_texturemid += offsetvalue;
+	dc_texturemid += repeatscroll;
 
 	// Texture must be cached
 	R_CheckTextureCache(texnum);
@@ -824,15 +877,41 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 						rlight->botheight += rlight->botheightstep;
 				}
 			}
-			spryscale += rw_scalestep;
+			yscale += scalestep;
 			continue;
 		}
 
-		dc_iscale = FixedMul(0xffffffffu / (unsigned)spryscale, wall_scaley);
-
 		// Get data for the column
 		col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS));
 
+		spryscale = DoubleToFixed(yscale);
+
+		// Eh. I tried fixing the scaling artifacts but it still wasn't perfect.
+		// So this checks if the column has gaps in it or not, and if it does, uses a version of the column drawers
+		// that prevents the artifacts from being visible.
+		// Note that if rendering fog then none of this matters because there's no texture mapping to be done
+		if (!fog)
+		{
+			dc_iscale = 0xffffffffu / (unsigned)spryscale;
+
+			// Column has a single post and it matches the texture height, use regular column drawers
+			if (col->num_posts == 1 && col->posts[0].topdelta == 0 && col->posts[0].length == (unsigned)dc_texheight)
+			{
+				if (fuzzy)
+					colfunc = colfuncs[COLDRAWFUNC_FUZZY];
+				else
+					colfunc = colfuncs[BASEDRAWFUNC];
+			}
+			else
+			{
+				// Otherwise use column drawers with extra checks
+				if (fuzzy)
+					colfunc = R_DrawTranslucentColumnClamped_8;
+				else
+					colfunc = R_DrawColumnClamped_8;
+			}
+		}
+
 		// SoM: New code does not rely on R_DrawColumnShadowed_8 which
 		// will (hopefully) put less strain on the stack.
 		if (dc_numlights)
@@ -947,7 +1026,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			if (windowtop < windowbottom)
 				colfunc_2s (col, lengthcol);
 
-			spryscale += rw_scalestep;
+			yscale += scalestep;
 			continue;
 		}
 
@@ -966,7 +1045,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 		// draw the texture
 		colfunc_2s (col, lengthcol);
-		spryscale += rw_scalestep;
+		yscale += scalestep;
 	}
 	colfunc = colfuncs[BASEDRAWFUNC];
 
diff --git a/src/r_skins.c b/src/r_skins.c
index 2029b4effb7184339f8ea2a906f28d0604447320..cd7d60b53e4c572630e26980309729a121d43cb7 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -35,30 +35,86 @@
 INT32 numskins = 0;
 skin_t **skins = NULL;
 
-//
-// P_GetSkinSprite2
-// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
-// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
-//
-
-UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
+// Gets the animation ID of a state
+UINT16 P_GetStateSprite2(state_t *state)
 {
-	UINT8 super = 0, i = 0;
+	if (state->sprite2)
+		return state->sprite2;
+	else
+	{
+		// Transform the state frame into an animation ID
+		UINT16 spr2 = state->frame & FF_FRAMEMASK;
 
-	if (!skin)
+		if (state->frame & SPR2F_SUPER)
+			spr2 |= SPR2F_SUPER;
+
+		return spr2;
+	}
+}
+
+// Gets the starting frame of an animation
+UINT16 P_GetSprite2StateFrame(state_t *state)
+{
+	if (state->sprite2)
+		return state->frame & FF_FRAMEMASK;
+	else
 		return 0;
+}
+
+// Checks if a state should use the "super" variant of the animation
+boolean P_IsStateSprite2Super(state_t *state)
+{
+	if (state->sprite2)
+	{
+		if (state->sprite2 & SPR2F_SUPER)
+			return true;
+	}
+	else if (state->frame & SPR2F_SUPER)
+		return true;
+
+	return false;
+}
+
+// Applies SPR2F_SUPER to an animation based on the actor's state
+UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj)
+{
+	if (mobj->player)
+	{
+		if (mobj->player->charflags & SF_NOSUPERSPRITES || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_NONIGHTSSUPER)))
+			spr2 &= ~SPR2F_SUPER;
+		else if (mobj->player->powers[pw_super] || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_SUPER)))
+			spr2 |= SPR2F_SUPER;
+	}
+
+	if (spr2 & SPR2F_SUPER)
+	{
+		if (mobj->eflags & MFE_FORCENOSUPER)
+			spr2 &= ~SPR2F_SUPER;
+	}
+	else if (mobj->eflags & MFE_FORCESUPER)
+		spr2 |= SPR2F_SUPER;
 
-	if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
+	return spr2;
+}
+
+// For non-super players, this tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
+// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
+UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player)
+{
+	UINT16 super = 0;
+	UINT8 i = 0;
+
+	if (!skin)
 		return 0;
 
-	while (!skin->sprites[spr2].numframes
+	while (!P_IsValidSprite2(skin, spr2)
 		&& spr2 != SPR2_STND
 		&& ++i < 32) // recursion limiter
 	{
-		if (spr2 & FF_SPR2SUPER)
+		if (spr2 & SPR2F_SUPER)
 		{
-			super = FF_SPR2SUPER;
-			spr2 &= ~FF_SPR2SUPER;
+			super = SPR2F_SUPER;
+			spr2 &= ~SPR2F_SUPER;
 			continue;
 		}
 
@@ -92,6 +148,51 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
 	return spr2;
 }
 
+// Gets the spritedef of a skin animation
+spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2)
+{
+	if (!skin)
+		return NULL;
+
+	boolean is_super = spr2 & SPR2F_SUPER;
+
+	spr2 &= SPR2F_MASK;
+
+	if (spr2 >= free_spr2)
+		return NULL;
+
+	if (is_super)
+		return &skin->super.sprites[spr2];
+	else
+		return &skin->sprites[spr2];
+}
+
+// Gets the spriteinfo of a skin animation
+spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2)
+{
+	if (!skin)
+		return NULL;
+
+	boolean is_super = spr2 & SPR2F_SUPER;
+
+	spr2 &= SPR2F_MASK;
+
+	if (spr2 >= free_spr2)
+		return NULL;
+
+	if (is_super)
+		return &skin->super.sprinfo[spr2];
+	else
+		return &skin->sprinfo[spr2];
+}
+
+// Checks if a skin animation is valid
+boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2)
+{
+	spritedef_t *sprdef = P_GetSkinSpritedef(skin, spr2);
+	return sprdef && sprdef->numframes;
+}
+
 static void Sk_SetDefaultValue(skin_t *skin)
 {
 	INT32 i;
@@ -500,10 +601,10 @@ static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
 	return INT16_MAX; // not found
 }
 
-static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT8 start_spr2)
+static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin, UINT16 start_spr2)
 {
 	UINT16 newlastlump;
-	UINT8 sprite2;
+	UINT16 sprite2;
 
 	*lump += 1; // start after S_SKIN
 	*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
@@ -523,7 +624,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
 		newlastlump++;
 		// load all sprite sets we are aware of... for super!
 		for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
-			R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump);
+			R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump, false);
 
 		newlastlump--;
 		*lastlump = newlastlump; // okay, make the normal sprite set loading end there
@@ -531,7 +632,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
 
 	// load all sprite sets we are aware of... for normal stuff.
 	for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
-		R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump);
+		R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump, false);
 
 	if (skin->sprites[0].numframes == 0)
 		CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]);
diff --git a/src/r_skins.h b/src/r_skins.h
index cc3b63cbed2c97de3fc312ad338d6f201edcd65b..1f2c57472d23ffd3026f0370e591dcd18ad77193 100644
--- a/src/r_skins.h
+++ b/src/r_skins.h
@@ -80,9 +80,14 @@ typedef struct
 	// specific sounds per skin
 	sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
 
+	spritedef_t sprites[NUMPLAYERSPRITES];
+	spriteinfo_t sprinfo[NUMPLAYERSPRITES];
+
 	// contains super versions too
-	spritedef_t sprites[NUMPLAYERSPRITES*2];
-	spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
+	struct {
+		spritedef_t sprites[NUMPLAYERSPRITES];
+		spriteinfo_t sprinfo[NUMPLAYERSPRITES];
+	} super;
 } skin_t;
 
 /// Externs
@@ -102,7 +107,14 @@ INT32 R_GetForcedSkin(INT32 playernum);
 void R_AddSkins(UINT16 wadnum, boolean mainfile);
 void R_PatchSkins(UINT16 wadnum, boolean mainfile);
 
-UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
+UINT16 P_GetStateSprite2(state_t *state);
+UINT16 P_GetSprite2StateFrame(state_t *state);
+UINT16 P_GetSkinSprite2(skin_t *skin, UINT16 spr2, player_t *player);
+UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj);
+spritedef_t *P_GetSkinSpritedef(skin_t *skin, UINT16 spr2);
+spriteinfo_t *P_GetSkinSpriteInfo(skin_t *skin, UINT16 spr2);
+boolean P_IsValidSprite2(skin_t *skin, UINT16 spr2);
+boolean P_IsStateSprite2Super(state_t *state);
 
 void R_RefreshSprite2(void);
 
diff --git a/src/r_textures.c b/src/r_textures.c
index 59cc114139c5abb24df0f47fa0dddd0e70ec8d72..5d3fe24db2c942647d514a92ad42a759d0b3c9f4 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -821,8 +821,8 @@ Rloadflats (INT32 i, INT32 w)
 			UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
 			if (Picture_PNGDimensions((UINT8 *)flatlump, &texw, &texh, NULL, NULL, lumplength))
 			{
-				width = (INT16)width;
-				height = (INT16)height;
+				width = (INT16)texw;
+				height = (INT16)texh;
 			}
 			else
 			{
@@ -1068,6 +1068,98 @@ void R_LoadTexturesPwad(UINT16 wadnum)
 	R_FinishLoadingTextures(newtextures);
 }
 
+static lumpnum_t W_GetTexPatchLumpNum(const char *name)
+{
+	// Flats as a texture patch crashes horribly, and flats
+	// can share the same name as textures.
+
+	// But even if they worked, we want to prioritize:
+	// Patches -> Textures -> anything else
+
+	enum
+	{
+		USE_PATCHES,
+		USE_TEXTURES,
+		USE__MAX,
+	};
+
+	lumpnum_t lump = LUMPERROR;
+	INT32 lump_type_it;
+	
+
+	for (lump_type_it = 0; lump_type_it < USE__MAX; lump_type_it++)
+	{
+		INT32 i;
+
+		for (i = numwadfiles - 1; i >= 0; i--) // Scan wad files backwards so patched lumps take precedent
+		{
+			lumpnum_t start = LUMPERROR;
+			lumpnum_t end = LUMPERROR;
+
+			switch (wadfiles[i]->type)
+			{
+				case RET_WAD:
+					if (lump_type_it == USE_PATCHES)
+					{
+						if ((start = W_CheckNumForMarkerStartPwad("P_START", (UINT16)i, 0)) == INT16_MAX)
+							continue;
+						else if ((end = W_CheckNumForNamePwad("P_END", (UINT16)i, start)) == INT16_MAX)
+							continue;
+					}
+					else if (lump_type_it == USE_TEXTURES)
+					{
+						if ((start = W_CheckNumForMarkerStartPwad("TX_START", (UINT16)i, 0)) == INT16_MAX)
+							continue;
+						else if ((end = W_CheckNumForNamePwad("TX_END", (UINT16)i, start)) == INT16_MAX)
+							continue;
+					}
+					break;
+				case RET_PK3:
+				case RET_FOLDER:
+					if (lump_type_it == USE_PATCHES)
+					{
+						if ((start = W_CheckNumForFolderStartPK3("Patches/", i, 0)) == INT16_MAX)
+							continue;
+						if ((end = W_CheckNumForFolderEndPK3("Patches/", i, start)) == INT16_MAX)
+							continue;
+					}
+					else if (lump_type_it == USE_TEXTURES)
+					{
+						if ((start = W_CheckNumForFolderStartPK3("Textures/", i, 0)) == INT16_MAX)
+							continue;
+						if ((end = W_CheckNumForFolderEndPK3("Textures/", i, start)) == INT16_MAX)
+							continue;
+					}
+					break;
+				default:
+					continue;
+			}
+
+			// Now find lump with specified name in that range.
+			lump = W_CheckNumForNamePwad(name, (UINT16)i, start);
+			if (lump < end)
+			{
+				lump += (i<<16); // found it, in our constraints
+				break;
+			}
+			lump = LUMPERROR;
+		}
+
+		if (lump != LUMPERROR)
+		{
+			break;
+		}
+	}
+
+	if (lump == LUMPERROR)
+	{
+		// Use whatever else you can find.
+		return W_GetNumForName(name);
+	}
+
+	return lump;
+}
+
 static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
 {
 	char *texturesToken;
@@ -1240,13 +1332,13 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
 	if (actuallyLoadPatch == true)
 	{
 		// Check lump exists
-		patchLumpNum = W_GetNumForName(patchName);
+		patchLumpNum = W_GetTexPatchLumpNum(patchName);
 		// If so, allocate memory for texpatch_t and fill 'er up
 		resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL);
 		resultPatch->originx = patchXPos;
 		resultPatch->originy = patchYPos;
-		resultPatch->lump = patchLumpNum & 65535;
-		resultPatch->wad = patchLumpNum>>16;
+		resultPatch->lump = LUMPNUM(patchLumpNum);
+		resultPatch->wad = WADFILENUM(patchLumpNum);
 		resultPatch->flip = flip;
 		resultPatch->alpha = alpha;
 		resultPatch->style = style;
diff --git a/src/r_things.c b/src/r_things.c
index 64226990961896ce934c5a9a42a1e8e8f967a497..fb9757a9ae077703433b2ad4bc8a3a1fc166d12b 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -77,7 +77,7 @@ spriteinfo_t spriteinfo[NUMSPRITES];
 spritedef_t *sprites;
 size_t numsprites;
 
-static spriteframe_t sprtemp[64];
+static spriteframe_t sprtemp[MAXFRAMENUM];
 static size_t maxframe;
 static const char *spritename;
 
@@ -116,6 +116,14 @@ static INT32 drawsegs_xrange_count = 0;
 //
 // ==========================================================================
 
+spritenum_t R_GetSpriteNumByName(const char *name)
+{
+	for (spritenum_t i = 0; i < NUMSPRITES; i++)
+		if (!strcmp(name, sprnames[i]))
+			return i;
+	return NUMSPRITES;
+}
+
 //
 //
 //
@@ -128,10 +136,14 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 {
 	char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
 
+	char framedescription[256];
+	if (cn != '\xFF')
+		sprintf(framedescription, "%s frame %d (%c)", spritename, frame, cn);
+	else
+		sprintf(framedescription, "%s frame %d", spritename, frame);
+
 	INT32 r;
-	lumpnum_t lumppat = wad;
-	lumppat <<= 16;
-	lumppat += lump;
+	lumpnum_t lumppat = (wad << 16) + lump;
 
 	if (maxframe ==(size_t)-1 || frame > maxframe)
 		maxframe = frame;
@@ -147,9 +159,9 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 	{
 		// the lump should be used for all rotations
 		if (sprtemp[frame].rotate == SRF_SINGLE)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple rot = 0 lump\n", framedescription);
 		else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message.
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has rotations and a rot = 0 lump\n", framedescription);
 
 		sprtemp[frame].rotate = SRF_SINGLE;
 		for (r = 0; r < 16; r++)
@@ -169,15 +181,15 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 		if (sprtemp[frame].rotate == SRF_NONE)
 			sprtemp[frame].rotate = SRF_SINGLE;
 		else if (sprtemp[frame].rotate == SRF_SINGLE)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has L/R rotations and a rot = 0 lump\n", framedescription);
 		else if (sprtemp[frame].rotate == SRF_3D)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8 rotations\n", framedescription);
 		else if (sprtemp[frame].rotate == SRF_3DGE)
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-G rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-G rotations\n", framedescription);
 		else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L))
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple L rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple L rotations\n", framedescription);
 		else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R))
-			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple R rotations\n", spritename, cn);
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple R rotations\n", framedescription);
 
 		sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
 		if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
@@ -204,9 +216,9 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 	if (sprtemp[frame].rotate == SRF_NONE)
 		sprtemp[frame].rotate = SRF_SINGLE;
 	else if (sprtemp[frame].rotate == SRF_SINGLE)
-		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8/G rotations and a rot = 0 lump\n", spritename, cn);
+		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has 1-8/G rotations and a rot = 0 lump\n", framedescription);
 	else if (sprtemp[frame].rotate & SRF_2D)
-		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8/G rotations\n", spritename, cn);
+		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8/G rotations\n", framedescription);
 
 	// make 0 based
 	rotation--;
@@ -226,7 +238,12 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 	}
 
 	if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
-		CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, cr);
+	{
+		if (cn != '\xFF')
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c (%c%c) has two lumps mapped to it\n", spritename, frame, cr, cn, cr);
+		else
+			CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c has two lumps mapped to it\n", spritename, frame, cr);
+	}
 
 	// lumppat & lumpid are the same for original Doom, but different
 	// when using sprites in pwad : the lumppat points the new graphics
@@ -238,24 +255,201 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 		sprtemp[frame].flip &= ~(1<<rotation);
 }
 
+static boolean GetFramesAndRotationsFromShortLumpName(
+	const char *name,
+	INT32 *ret_frame,
+	UINT8 *ret_rotation,
+	INT32 *ret_frame2,
+	UINT8 *ret_rotation2
+)
+{
+	size_t namelen = strlen(name);
+
+	if (namelen != 6 && namelen != 8)
+		return false;
+
+	*ret_frame = R_Char2Frame(name[4]);
+	*ret_rotation = R_Char2Rotation(name[5]);
+	if (*ret_frame >= 64 || *ret_rotation == 255)
+		return false;
+
+	if (namelen == 8)
+	{
+		*ret_frame2 = R_Char2Frame(name[6]);
+		*ret_rotation2 = R_Char2Rotation(name[7]);
+		if (*ret_frame2 >= 64 || *ret_rotation2 == 255)
+			return false;
+	}
+	else
+	{
+		*ret_frame2 = -1;
+		*ret_rotation2 = 255;
+	}
+
+	return true;
+}
+
+static boolean GetSingleFrameAndRotation(
+	const char *name,
+	size_t len,
+	INT32 *ret_frame,
+	UINT8 *ret_rotation
+)
+{
+	const char *underscore = strchr(name, '_');
+
+	// Found but past the part of the name we are parsing
+	if ((size_t)(underscore - name) >= len)
+		underscore = NULL;
+
+	size_t framelen = underscore ? (size_t)(underscore - name) : len;
+	if (framelen < 1 || framelen > 4)
+		return false;
+
+	char framepart[4 + 1]; // Max 9999
+	strlcpy(framepart, name, framelen + 1);
+
+	for (size_t i = 0; i < framelen; i++)
+		if (!isdigit(framepart[i]))
+			return false;
+
+	*ret_frame = atoi(framepart);
+	*ret_rotation = underscore ? R_Char2Rotation(*(underscore + 1)) : 0;
+	if (*ret_frame >= MAXFRAMENUM || *ret_rotation == 255)
+		return false;
+
+	return true;
+}
+
+static boolean GetFramesAndRotationsFromLongLumpName(
+	const char *name,
+	INT32 *ret_frame,
+	UINT8 *ret_rotation,
+	INT32 *ret_frame2,
+	UINT8 *ret_rotation2
+)
+{
+	const char *plus = strchr(name, '+');
+
+	if (plus)
+	{
+		size_t len1 = plus - name;
+
+		if (!GetSingleFrameAndRotation(name, len1, ret_frame, ret_rotation))
+			return false;
+		if (!GetSingleFrameAndRotation(plus + 1, strlen(name) - len1 - 1, ret_frame2, ret_rotation2))
+			return false;
+	}
+	else
+	{
+		if (!GetSingleFrameAndRotation(name, strlen(name), ret_frame, ret_rotation))
+			return false;
+
+		*ret_frame2 = -1;
+		*ret_rotation2 = 255;
+	}
+
+	return true;
+}
+
+static UINT8 GetOppositeRotation(UINT8 rotation, UINT8 flags)
+{
+	if (flags & ~SRF_3DMASK)
+		I_Error("GetOppositeRotation: rotation type not supported");
+
+	UINT8 numrotations = (flags == SRF_3D) ? 8 : 16;
+	return (rotation == 1) ? 1 : numrotations + 2 - rotation;
+}
+
+static void MirrorMissingRotations(void)
+{
+	for (UINT32 framenum = 0; framenum < maxframe; framenum++)
+	{
+		spriteframe_t *frame = &sprtemp[framenum];
+
+		if (frame->rotate == SRF_NONE || !(frame->rotate & SRF_3DMASK))
+			continue;
+
+		UINT8 numrotations = frame->rotate == SRF_3D ? 8 : 16;
+
+		for (UINT8 rotation = 1; rotation <= numrotations; rotation++)
+		{
+			if (frame->lumppat[rotation - 1] != LUMPERROR)
+				continue;
+
+			UINT8 baserotation = GetOppositeRotation(rotation, frame->rotate);
+			UINT32 lumpnum = frame->lumppat[baserotation - 1];
+			R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), frame->lumpid[baserotation], framenum, rotation, 1);
+		}
+	}
+}
+
+// Some checks to help development
+static void CheckFrame(const char *sprname)
+{
+	for (UINT32 frame = 0; frame < maxframe; frame++)
+	{
+		spriteframe_t *spriteframe = &sprtemp[frame];
+
+		char framedescription[256];
+		if (frame < 64)
+			sprintf(framedescription, "%s frame %d (%c)", sprname, frame, R_Frame2Char(frame));
+		else
+			sprintf(framedescription, "%s frame %d", sprname, frame);
+
+		switch (spriteframe->rotate)
+		{
+		case SRF_NONE:
+			// no rotations were found for that frame at all
+			I_Error("R_AddSingleSpriteDef: No patches found for %s", framedescription);
+			break;
+
+		case SRF_SINGLE:
+			// only the first rotation is needed
+			break;
+
+		case SRF_2D: // both Left and Right rotations
+			// we test to see whether the left and right slots are present
+			if ((spriteframe->lumppat[2] == LUMPERROR) || (spriteframe->lumppat[6] == LUMPERROR))
+				I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (L-R mode)",
+				framedescription);
+			break;
+
+		default:
+			{
+				// must have all 8/16 frames
+				UINT8 rotation = ((spriteframe->rotate & SRF_3DGE) ? 16 : 8);
+				while (rotation--)
+				{
+					// we test the patch lump, or the id lump whatever
+					// if it was not loaded the two are LUMPERROR
+					if (spriteframe->lumppat[rotation] == LUMPERROR)
+						I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (1-%c mode)",
+								framedescription, ((spriteframe->rotate & SRF_3DGE) ? 'G' : '8'));
+				}
+			}
+			break;
+		}
+	}
+}
+
 // Install a single sprite, given its identifying name (4 chars)
 //
 // (originally part of R_AddSpriteDefs)
 //
-// Pass: name of sprite : 4 chars
+// Pass: name of sprite
 //       spritedef_t
 //       wadnum         : wad number, indexes wadfiles[], where patches
 //                        for frames are found
 //       startlump      : first lump to search for sprite frames
 //       endlump        : AFTER the last lump to search
+//       longname       : whether to use long sprite names or 4-char names
 //
 // Returns true if the sprite was succesfully added
 //
-boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump)
+boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname)
 {
 	UINT16 l;
-	UINT8 frame;
-	UINT8 rotation;
 	lumpinfo_t *lumpinfo;
 	UINT16 numadded = 0;
 
@@ -282,15 +476,23 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 
 	for (l = startlump; l < endlump; l++)
 	{
-		if (memcmp(lumpinfo[l].name,sprname,4)==0)
+		if (longname && W_IsLumpFolder(wadnum, l))
+			I_Error("R_AddSingleSpriteDef: all frame lumps for a sprite should be contained inside a single folder\n");
+
+		// For long sprites, the startlump-endlump range only includes
+		// relevant lumps, so no check needed in that case
+		if (longname || (strlen(sprname) == 4 && !memcmp(lumpinfo[l].name, sprname, 4)))
 		{
 			INT16 width, height;
 			INT16 topoffset, leftoffset;
+			INT32 frame, frame2;
+			UINT8 rotation, rotation2;
 
-			frame = R_Char2Frame(lumpinfo[l].name[4]);
-			rotation = R_Char2Rotation(lumpinfo[l].name[5]);
+			boolean good = longname ?
+				GetFramesAndRotationsFromLongLumpName(lumpinfo[l].longname, &frame, &rotation, &frame2, &rotation2) :
+				GetFramesAndRotationsFromShortLumpName(lumpinfo[l].name, &frame, &rotation, &frame2, &rotation2);
 
-			if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
+			if (!good) // Give an actual NAME error -_-...
 			{
 				CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
 				continue;
@@ -322,19 +524,8 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 			//----------------------------------------------------
 
 			R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0);
-
-			if (lumpinfo[l].name[6])
-			{
-				frame = R_Char2Frame(lumpinfo[l].name[6]);
-				rotation = R_Char2Rotation(lumpinfo[l].name[7]);
-
-				if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
-				{
-					CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
-					continue;
-				}
-				R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
-			}
+			if (frame2 != -1)
+				R_InstallSpriteLump(wadnum, l, numspritelumps, frame2, rotation2, 1);
 
 			if (++numspritelumps >= max_spritelumps)
 			{
@@ -374,41 +565,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 
 	maxframe++;
 
-	//
-	//  some checks to help development
-	//
-	for (frame = 0; frame < maxframe; frame++)
-	{
-		switch (sprtemp[frame].rotate)
-		{
-			case SRF_NONE:
-			// no rotations were found for that frame at all
-			I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
-			break;
-
-			case SRF_SINGLE:
-			// only the first rotation is needed
-			break;
+	if (longname)
+		MirrorMissingRotations();
 
-			case SRF_2D: // both Left and Right rotations
-			// we test to see whether the left and right slots are present
-			if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
-				I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (L-R mode)",
-				sprname, R_Frame2Char(frame));
-			break;
-
-			default:
-			// must have all 8/16 frames
-				rotation = ((sprtemp[frame].rotate & SRF_3DGE) ? 16 : 8);
-				while (rotation--)
-				// we test the patch lump, or the id lump whatever
-				// if it was not loaded the two are LUMPERROR
-				if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
-					I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (1-%c mode)",
-					        sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
-			break;
-		}
-	}
+	CheckFrame(sprname);
 
 	// allocate space for the frames present and copy sprtemp to it
 	if (spritedef->numframes &&             // has been allocated
@@ -429,14 +589,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 	return true;
 }
 
-//
-// Search for sprites replacements in a wad whose names are in namelist
-//
-void R_AddSpriteDefs(UINT16 wadnum)
+static void AddShortSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
 {
-	size_t i, addsprites = 0;
+	size_t i;
 	UINT16 start, end;
-	char wadname[MAX_WADPATH];
 
 	// Find the sprites section in this resource file.
 	switch (wadfiles[wadnum]->type)
@@ -474,27 +630,90 @@ void R_AddSpriteDefs(UINT16 wadnum)
 		return;
 	}
 
-
 	//
 	// scan through lumps, for each sprite, find all the sprite frames
 	//
 	for (i = 0; i < numsprites; i++)
 	{
-		if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4])
-			continue;
-
-		if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
+		if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end, false))
 		{
 			// if a new sprite was added (not just replaced)
-			addsprites++;
+			(*ptr_spritesadded)++;
 #ifndef ZDEBUG
 			CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum);
 #endif
 		}
 	}
 
-	nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
-	CONS_Printf(M_GetText("%s added %d frames in %s sprites\n"), wadname, end-start, sizeu1(addsprites));
+	*ptr_framesadded += end - start;
+}
+
+static void AddLongSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
+{
+	if (!W_FileHasFolders(wadfiles[wadnum]))
+		return;
+
+	UINT16 start = W_CheckNumForFolderStartPK3("LongSprites/", wadnum, 0);
+	UINT16 end = W_CheckNumForFolderEndPK3("LongSprites/", wadnum, start);
+
+	if (start == INT16_MAX || end == INT16_MAX || start >= end)
+		return;
+
+	size_t lumpnum = start;
+
+	while (lumpnum < end)
+	{
+		if (W_IsLumpFolder(wadnum, lumpnum))
+		{
+			lumpnum++;
+			continue;
+		}
+
+		UINT16 folderstart, folderend;
+		char *folderpath = W_GetLumpFolderPathPK3(wadnum, lumpnum);
+		folderstart = lumpnum;
+		folderend = W_CheckNumForFolderEndPK3(folderpath, wadnum, lumpnum);
+		Z_Free(folderpath);
+
+		spritenum_t sprnum;
+		char *sprname = W_GetLumpFolderNamePK3(wadnum, lumpnum);
+		strupr(sprname);
+		sprnum = R_GetSpriteNumByName(sprname);
+
+		if (sprnum != NUMSPRITES && R_AddSingleSpriteDef(sprname, &sprites[sprnum], wadnum, folderstart, folderend, true))
+		{
+			// A new sprite was added (not just replaced)
+			(*ptr_spritesadded)++;
+#ifndef ZDEBUG
+			CONS_Debug(DBG_SETUP, "long sprite %s set in pwad %d\n", sprname, wadnum);
+#endif
+		}
+
+		Z_Free(sprname);
+
+		lumpnum = folderend;
+	}
+
+	*ptr_framesadded += end - start;
+}
+
+//
+// Search for sprites replacements in a wad whose names are in namelist
+//
+void R_AddSpriteDefs(UINT16 wadnum)
+{
+	char wadname[MAX_WADPATH];
+	size_t spritesadded = 0;
+	size_t framesadded = 0;
+
+	AddShortSpriteDefs(wadnum, &spritesadded, &framesadded);
+	AddLongSpriteDefs(wadnum, &spritesadded, &framesadded);
+
+	if (spritesadded || framesadded)
+	{
+		nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
+		CONS_Printf(M_GetText("%s added %s frames in %s sprites\n"), wadname, sizeu1(framesadded), sizeu2(spritesadded));
+	}
 }
 
 //
@@ -620,8 +839,10 @@ void R_DrawMaskedColumn(column_t *column, unsigned lengthcol)
 	{
 		post_t *post = &column->posts[i];
 
+		dc_postlength = post->length;
+
 		INT32 topscreen = sprtopscreen + spryscale*post->topdelta;
-		INT32 bottomscreen = topscreen + spryscale*post->length;
+		INT32 bottomscreen = topscreen + spryscale*dc_postlength;
 
 		dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
 		dc_yh = (bottomscreen-1)>>FRACBITS;
@@ -690,10 +911,12 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol)
 		if (!post->length)
 			continue;
 
-		topdelta = lengthcol-post->length-post->topdelta;
+		dc_postlength = post->length;
+
+		topdelta = lengthcol-dc_postlength-post->topdelta;
 		topscreen = sprtopscreen + spryscale*topdelta;
-		bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*post->length
-		                                      : sprbotscreen + spryscale*post->length;
+		bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*dc_postlength
+		                                      : sprbotscreen + spryscale*dc_postlength;
 
 		dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
 		dc_yh = (bottomscreen-1)>>FRACBITS;
@@ -1579,20 +1802,22 @@ static void R_ProjectSprite(mobj_t *thing)
 	// decide which patch to use for sprite relative to player
 #ifdef RANGECHECK
 	if ((size_t)(thing->sprite) >= numsprites)
-		I_Error("R_ProjectSprite: invalid sprite number %d ", thing->sprite);
+		I_Error("R_ProjectSprite: invalid sprite number %d", thing->sprite);
 #endif
 
-	frame = thing->frame&FF_FRAMEMASK;
+	frame = thing->frame & FF_FRAMEMASK;
 
 	//Fab : 02-08-98: 'skin' override spritedef currently used for skin
 	if (thing->skin && thing->sprite == SPR_PLAY)
 	{
-		sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
+		sprdef = P_GetSkinSpritedef(thing->skin, thing->sprite2);
 #ifdef ROTSPRITE
-		sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
+		sprinfo = P_GetSkinSpriteInfo(thing->skin, thing->sprite2);
 #endif
-		if (frame >= sprdef->numframes) {
-			CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(frame));
+
+		if (frame >= sprdef->numframes)
+		{
+			CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[SPR2_%s] %sframe %s\n"), ((skin_t *)thing->skin)->name, spr2names[thing->sprite2 & SPR2F_MASK], (thing->sprite2 & SPR2F_SUPER) ? "super ": "", sizeu5(frame));
 			thing->sprite = states[S_UNKNOWN].sprite;
 			thing->frame = states[S_UNKNOWN].frame;
 			sprdef = &sprites[thing->sprite];
diff --git a/src/r_things.h b/src/r_things.h
index f68d75a837ef698bcb98fc4e6dc568f97bf8881a..3daf55c4235bc753aeb5f1c897856e6d9303338c 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -27,7 +27,9 @@
 
 #define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
 
-boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump);
+spritenum_t R_GetSpriteNumByName(const char *name);
+
+boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname);
 
 //faB: find sprites in wadfile, replace existing, add new ones
 //     (only sprites from namelist are added or replaced)
diff --git a/src/s_sound.c b/src/s_sound.c
index aa049899ff602cf6a1f7af4c287d8f3673bf5597..32353a59c2d590dd8ea1f74b47399de0886684d0 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -2256,9 +2256,9 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
 		return;
 
 	strncpy(newmusic, mmusic, sizeof(newmusic)-1);
+	newmusic[6] = 0;
 	if (LUA_HookMusicChange(music_name, &hook_param))
 		return;
-	newmusic[6] = 0;
 
 	// No Music (empty string)
 	if (newmusic[0] == 0)
@@ -2494,11 +2494,11 @@ static void Command_Tunes_f(void)
 		track = (UINT16)atoi(COM_Argv(2))-1;
 
 	strncpy(mapmusname, tunearg, 7);
+	mapmusname[6] = 0;
 
 	if (argc > 4)
 		position = (UINT32)atoi(COM_Argv(4));
 
-	mapmusname[6] = 0;
 	mapmusflags = (track & MUSIC_TRACKMASK);
 	mapmusposition = position;
 
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index 5aca04d120c39287eec5c2097aa6375e52eb27fb..ee48fa2b154568889c50d4e0a6c8d97c5c2a7bf0 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -1,7 +1,6 @@
 # Declare SDL2 interface sources
 
 target_sources(SRB2SDL2 PRIVATE
-	mixer_sound.c
 	ogl_sdl.c
 	i_threads.c
 	i_net.c
@@ -13,6 +12,161 @@ target_sources(SRB2SDL2 PRIVATE
 	hwsym_sdl.c
 )
 
+# Compatibility flag with later versions of GCC
+# We should really fix our code to not need this
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+endif()
+
+# Yes we know we use insecure CRT functions...
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+    target_compile_definitions(SRB2SDL2 PRIVATE -D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# Compiler warnings configuration
+target_compile_options(SRB2SDL2 PRIVATE
+    # Using generator expressions to handle per-language compile options
+
+    # C, GNU
+    # This is a direct translation from versions.mk
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>:
+        -Wall
+        -Wno-trigraphs
+        -W # Was controlled by RELAXWARNINGS
+        -pedantic
+        -Wpedantic
+        -Wfloat-equal
+        -Wundef
+        -Wpointer-arith
+        -Wbad-function-cast
+        -Wcast-qual
+        -Wcast-align # Was controlled by NOCASTALIGNWARN
+        -Wwrite-strings
+        -Wsign-compare
+        -Wmissing-prototypes
+        -Wmissing-declarations
+        -Wmissing-noreturn
+        -Winline
+        -Wformat-y2k
+        -Wformat-security
+
+        $<$<VERSION_LESS:$<C_COMPILER_VERSION>,2.9.5>:
+            -Wno-div-by-zero
+            -Wendif-labels
+            -Wdisabled-optimization
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.0.0>:
+            -Wold-style-definition
+            -Wmissing-field-initializers
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.1.0>:
+            -Wshadow
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.3.0>:
+            -funit-at-a-time
+            -Wlogical-op
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.5.0>:
+            -Wlogical-op
+            -Wno-error=array-bounds
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,4.6.0>:
+            -Wno-suggest-attribute=noreturn
+            -Wno-error=suggest-attribute=noreturn
+            -Werror=vla
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,5.4.0>:
+            -Wno-logical-op
+            -Wno-error=logical-op
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,6.1.0>:
+            -Wno-tautological-compare
+            -Wno-error=tautological-compare
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,7.1.0>:
+            -Wno-error=format-overflow=2
+            -Wimplicit-fallthrough=4
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,8.1.0>:
+            -Wno-error=format-overflow
+            -Wno-error=stringop-truncation
+            -Wno-error=stringop-overflow
+            -Wno-format-overflow
+            -Wno-stringop-truncation
+            -Wno-stringop-overflow
+            -Wno-error=multistatement-macros
+        >
+
+        $<$<VERSION_GREATER_EQUAL:$<C_COMPILER_VERSION>,9.1.0>:
+            -Wno-error=address-of-packed-member
+        >
+    >
+
+    # C, Clang and Apple Clang
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
+        -Wall
+        -Wno-absolute-value
+        -Wno-trigraphs
+        -Wno-error=non-literal-null-conversion
+        -Wno-error=constant-conversion
+        -Wno-unused-but-set-variable
+        -Wno-error=unused-but-set-variable
+        -Wno-shorten-64-to-32
+    >
+
+    # C, MSVC
+    $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:MSVC>>:
+        # All warnings at and before Visual Studio 2019 RTM
+        # https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-by-compiler-version?view=msvc-170
+        /Wv:19.20.27004.0
+    >
+
+    # C++, GNU, Clang and Apple Clang
+    $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<C_COMPILER_ID:GNU>,$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
+        -Wall
+        -Wno-unused-function
+        -Wno-unused-but-set-variable
+        -Wno-unused-private-field
+    >
+
+    # C++, MSVC
+    $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<C_COMPILER_ID:MSVC>>:
+        /Wv:19.20.27004.0
+    >
+
+    # GNU
+    $<$<C_COMPILER_ID:GNU>:
+        -fmax-errors=5
+    >
+)
+if(SRB2_CONFIG_ERRORMODE)
+    target_compile_options(SRB2SDL2 PRIVATE
+        $<$<OR:$<C_COMPILER_ID:GNU>,$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>:
+            -Werror
+        >
+
+        $<$<C_COMPILER_ID:MSVC>:
+            /WX
+        >
+    )
+endif()
+
+# Link warnings configuration
+target_link_options(SRB2SDL2 PRIVATE
+    $<$<C_COMPILER_ID:GNU>:
+        # -Wl,--as-needed   - Was controlled by NOLDWARNING
+    >
+)
+
 if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
 	target_sources(SRB2SDL2 PRIVATE
 		../win32/win_dbg.c
@@ -62,12 +216,6 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
 	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2main)
 endif()
 
-if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}")
-	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2-static SDL2_mixer::SDL2_mixer-static)
-else()
-	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2 SDL2_mixer::SDL2_mixer)
-endif()
-
 if("${CMAKE_SYSTEM_NAME}" MATCHES Linux)
 	target_link_libraries(SRB2SDL2 PRIVATE m rt)
 endif()
@@ -81,8 +229,84 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES Windows)
 	)
 endif()
 
-target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+find_package(SDL2 CONFIG REQUIRED)
+find_package(SDL2 REQUIRED)
+if(TARGET SDL2main)
+	target_link_libraries(SRB2SDL2 PRIVATE SDL2main)
+endif()
 target_compile_definitions(SRB2SDL2 PRIVATE -DDIRECTFULLSCREEN -DHAVE_SDL)
+target_include_directories(SRB2SDL2 PRIVATE ${SDL2_INCLUDE_DIR})
+
+find_package(SDL2_mixer_ext CONFIG QUIET)
+find_package(SDL2_mixer_ext QUIET)
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static OR TARGET SDL2_mixer_ext OR TARGET SDL2_mixer_ext_Static)
+	if(NOT TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static AND TARGET SDL2_mixer_ext_Static)
+	add_library(SDL2_mixer_ext::SDL2_mixer_ext_Static ALIAS SDL2_mixer_ext_Static)
+	endif()
+	if(NOT TARGET SDL2_mixer_ext::SDL2_mixer_ext AND TARGET SDL2_mixer_ext)
+	add_library(SDL2_mixer_ext::SDL2_mixer_ext ALIAS SDL2_mixer_ext)
+	endif()
+	if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+		if(TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+			target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer_ext::SDL2_mixer_ext_Static)
+		else()
+			target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer_ext::SDL2_mixer_ext)
+		endif()
+	target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DHAVE_MIXERX -DSOUND=SOUND_MIXER)
+	endif()
+endif()
+
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+	message(STATUS "SDL2_mixer_ext found, skipping SDL2_mixer")
+else()
+	message(STATUS "SDL2_mixer_ext not found, going to try SDL2_mixer")
+	find_package(SDL2_mixer CONFIG QUIET)
+	find_package(SDL2_mixer QUIET)
+	if(TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static OR TARGET SDL2_mixer OR TARGET SDL2_mixer_Static)
+		if(NOT TARGET SDL2_mixer::SDL2_mixer-static AND TARGET SDL2_mixer_Static)
+		add_library(SDL2_mixer::SDL2_mixer-static ALIAS SDL2_mixer_Static)
+		endif()
+		if(NOT TARGET SDL2_mixer::SDL2_mixer AND TARGET SDL2_mixer)
+		add_library(SDL2_mixer::SDL2_mixer ALIAS SDL2_mixer)
+		endif()
+		if(TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static)
+			if(TARGET SDL2_mixer::SDL2_mixer-static)
+				target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer::SDL2_mixer-static)
+			else()
+				target_link_libraries(SRB2SDL2 PRIVATE SDL2_mixer::SDL2_mixer)
+			endif()
+		target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+		endif()
+	endif()
+endif()
+
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static OR TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static)
+	target_sources(SRB2SDL2 PRIVATE mixer_sound.c)
+	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2)
+else()
+	target_sources(SRB2SDL2 PRIVATE sdl_sound.c)
+	target_link_libraries(SRB2SDL2 PRIVATE SDL2::SDL2)
+endif()
+
+if(TARGET SDL2::SDL2)
+	message(STATUS "SDL2 Found")
+else()
+	message(STATUS "no SDL2 Found")
+endif()
+
+if(TARGET SDL2::SDL2main)
+	message(STATUS "SDL2main Found")
+else()
+	message(STATUS "No SDL2main Found")
+endif()
+
+if(TARGET SDL2_mixer_ext::SDL2_mixer_ext OR TARGET SDL2_mixer_ext::SDL2_mixer_ext_Static)
+	message(STATUS "SDL2_mixer_ext Found")
+elseif(TARGET SDL2_mixer::SDL2_mixer OR TARGET SDL2_mixer::SDL2_mixer-static)
+	message(STATUS "SDL2_mixer found")
+else()
+	message(STATUS "no SDL2_mixer_ext or SDL2_mixer Found")
+endif()
 
 #### Installation ####
 if("${CMAKE_SYSTEM_NAME}" MATCHES Darwin)
diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c
index f5fe9fb041b9f02057955afe072815e709b19dc3..b2177e563120fc76cf726353e5cad841e45b1762 100644
--- a/src/sdl/i_main.c
+++ b/src/sdl/i_main.c
@@ -186,6 +186,9 @@ int main(int argc, char **argv)
 #endif
 #endif
 
+	// disable text input right off the bat, since we don't need it at the start.
+	I_SetTextInputMode(false);
+
 #ifdef LOGMESSAGES
 	if (!M_CheckParm("-nolog"))
 		InitLogging();
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 9f0fa0250a664dfe020d649ac65ccb347a63a3c8..8bae550b0b12c1cc40fa166d6dc9963946a4c11d 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -271,75 +271,86 @@ SDL_bool framebuffer = SDL_FALSE;
 UINT8 keyboard_started = false;
 
 #ifdef UNIXBACKTRACE
-#define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string)
-#define CRASHLOG_WRITE(string) if (fd != -1) junk = write(fd, string, strlen(string))
-#define CRASHLOG_STDERR_WRITE(string) \
-	if (fd != -1)\
-		junk = write(fd, string, strlen(string));\
-	I_OutputMsg("%s", string)
+
+static void bt_write_file(int fd, const char *string) {
+	ssize_t written = 0;
+	ssize_t sourcelen = strlen(string);
+
+	while (fd != -1 && (written != -1 && errno != EINTR) && written < sourcelen)
+		written = write(fd, string, sourcelen);
+}
+
+static void bt_write_stderr(const char *string) {
+	bt_write_file(STDERR_FILENO, string);
+}
+
+static void bt_write_all(int fd, const char *string) {
+	bt_write_file(fd, string);
+	bt_write_file(STDERR_FILENO, string);
+}
 
 static void write_backtrace(INT32 signal)
 {
 	int fd = -1;
-#ifndef NOEXECINFO
-	size_t size;
-#endif
 	time_t rawtime;
 	struct tm timeinfo;
-	ssize_t junk;
 
 	enum { BT_SIZE = 1024, STR_SIZE = 32 };
 #ifndef NOEXECINFO
-	void *array[BT_SIZE];
+	void *funcptrs[BT_SIZE];
+	size_t bt_size;
 #endif
 	char timestr[STR_SIZE];
 
-	const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n";
-	const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr.
+	const char *filename = va("%s" PATHSEP "%s", srb2home, "crash-log.txt");
 
-	fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
+	fd = open(filename, O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
 
-	if (fd == -1)
-		I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n");
+	if (fd == -1) // File handle error
+		bt_write_stderr("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n");
 
 	// Get the current time as a string.
 	time(&rawtime);
 	localtime_r(&rawtime, &timeinfo);
 	strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo);
 
-	CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator
+	bt_write_file(fd, "------------------------\n"); // Nice looking seperator
 
-	CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs.
-	CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message
-	STDERR_WRITE(error2); // Tell the user where the crash log is.
+	bt_write_all(fd, "\n"); // Newline to look nice for both outputs.
+	bt_write_all(fd, "An error occurred within SRB2! Send this stack trace to someone who can help!\n");
+
+	if (fd != -1) // If the crash log exists,
+		bt_write_stderr("(Or find crash-log.txt in your SRB2 directory.)\n"); // tell the user where the crash log is.
 
 	// Tell the log when we crashed.
-	CRASHLOG_WRITE("Time of crash: ");
-	CRASHLOG_WRITE(timestr);
-	CRASHLOG_WRITE("\n");
+	bt_write_file(fd, "Time of crash: ");
+	bt_write_file(fd, timestr);
+	bt_write_file(fd, "\n");
 
 	// Give the crash log the cause and a nice 'Backtrace:' thing
 	// The signal is given to the user when the parent process sees we crashed.
-	CRASHLOG_WRITE("Cause: ");
-	CRASHLOG_WRITE(strsignal(signal));
-	CRASHLOG_WRITE("\n"); // Newline for the signal name
+	bt_write_file(fd, "Cause: ");
+	bt_write_file(fd, strsignal(signal));
+	bt_write_file(fd, "\n"); // Newline for the signal name
 
-#ifndef NOEXECINFO
-	CRASHLOG_STDERR_WRITE("\nBacktrace:\n");
+#ifdef NOEXECINFO
+	bt_write_all(fd, "\nNo Backtrace support\n");
+#else
+	bt_write_all(fd, "\nBacktrace:\n");
 
 	// Flood the output and log with the backtrace
-	size = backtrace(array, BT_SIZE);
-	backtrace_symbols_fd(array, size, fd);
-	backtrace_symbols_fd(array, size, STDERR_FILENO);
+	bt_size = backtrace(funcptrs, BT_SIZE);
+	backtrace_symbols_fd(funcptrs, bt_size, fd);
+	backtrace_symbols_fd(funcptrs, bt_size, STDERR_FILENO);
 #endif
 
-	CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :)
-	(void)junk;
-	close(fd);
+	bt_write_file(fd, "\n"); // Write another newline to the log so it looks nice :)
+	if (fd != -1) {
+		fsync(fd); // reaaaaally make sure we got that data written.
+		close(fd);
+	}
 }
-#undef STDERR_WRITE
-#undef CRASHLOG_WRITE
-#undef CRASHLOG_STDERR_WRITE
+
 #endif // UNIXBACKTRACE
 
 static void I_ReportSignal(int num, int coredumped)
@@ -2305,7 +2316,7 @@ void I_SleepDuration(precise_t duration)
 	int status;
 	do status = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts);
 	while (status == EINTR);
-#else
+#elif defined (MIN_SLEEP_DURATION_MS)
 	UINT64 precision = I_GetPrecisePrecision();
 	INT32 sleepvalue = cv_sleep.value;
 	UINT64 delaygranularity;
@@ -3275,4 +3286,18 @@ const char *I_GetSysName(void)
 	return SDL_GetPlatform();
 }
 
+
+void I_SetTextInputMode(boolean active)
+{
+	if (active)
+		SDL_StartTextInput();
+	else
+		SDL_StopTextInput();
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return SDL_IsTextInputActive();
+}
+
 #endif
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 76fe172fce0e27f46ceb491be5a43f1b3e72f770..249be61f69dd054824e6a21b755130226ccb4957 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -382,6 +382,8 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
 
 static boolean ShouldIgnoreMouse(void)
 {
+	if (cv_alwaysgrabmouse.value)
+		return false;
 	if (menuactive)
 		return !M_MouseNeeded();
 	if (paused || con_destlines || chat_on)
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 083bb52243be4e69bfaa1faffc51d96cec1d620a..e088a448c129ed6e2392e8bcadf3cb62e9932525 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -371,9 +371,11 @@ void ST_LoadFaceGraphics(INT32 skinnum)
 		spritedef_t *sprdef = &skins[skinnum]->sprites[SPR2_XTRA];
 		spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC];
 		faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
-		if (skins[skinnum]->sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes > XTRA_LIFEPIC)
+
+		spritedef_t *super_sprdef = P_GetSkinSpritedef(skins[skinnum], SPR2_XTRA|SPR2F_SUPER);
+		if (super_sprdef->numframes > XTRA_LIFEPIC)
 		{
-			sprdef = &skins[skinnum]->sprites[SPR2_XTRA|FF_SPR2SUPER];
+			sprdef = super_sprdef;
 			sprframe = &sprdef->spriteframes[0];
 			superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX);
 		}
@@ -507,7 +509,7 @@ static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fix
 static void ST_drawDebugInfo(void)
 {
 	INT32 height = 0, h = 8, w = 18, lowh;
-	void (*textfunc)(INT32, INT32, INT32, const char *);
+	fixed_t textscale = FRACUNIT/2;
 
 	if (!(stplyr->mo && cv_debug))
 		return;
@@ -516,12 +518,12 @@ static void ST_drawDebugInfo(void)
 
 	if ((moviemode == MM_GIF && cv_gif_downscale.value) || vid.dup == 1)
 	{
-		textfunc = V_DrawRightAlignedString;
+		textscale = FRACUNIT;
 		lowh = ((vid.height/vid.dup) - 16);
 	}
 	else
 	{
-		textfunc = V_DrawRightAlignedSmallString;
+		textscale = FRACUNIT/2;
 		h /= 2;
 		w /= 2;
 		lowh = 0;
@@ -532,10 +534,10 @@ static void ST_drawDebugInfo(void)
 								V_DrawRightAlignedThinString(320,  8+lowh, VFLAGS|V_REDMAP, "SOME INFO NOT VISIBLE");\
 								return;\
 							}\
-							textfunc(320, height, VFLAGS, str);\
+							V_DrawAlignedFontString(320, height, VFLAGS, textscale, textscale, str, hu_font, alignright);\
 							height += h;
 
-#define V_DrawDebugFlag(f, str) textfunc(width, height, VFLAGS|f, str);\
+#define V_DrawDebugFlag(f, str) V_DrawAlignedFontString(width, height, VFLAGS|f, textscale, textscale, str, hu_font, alignright);\
 								width -= w
 
 	if (cv_debug & DBG_MEMORY)
@@ -1267,19 +1269,19 @@ tic_t lt_exitticker = 0, lt_endtime = 0;
 //
 static void ST_cacheLevelTitle(void)
 {
-#define SETPATCH(default, warning, custom, idx) \
+#define SETPATCH(def, warning, custom, idx) \
 { \
 	lumpnum_t patlumpnum = LUMPERROR; \
 	if (mapheaderinfo[gamemap-1]->custom[0] != '\0') \
 	{ \
-		patlumpnum = W_CheckNumForName(mapheaderinfo[gamemap-1]->custom); \
+		patlumpnum = W_CheckNumForPatchName(mapheaderinfo[gamemap-1]->custom); \
 		if (patlumpnum != LUMPERROR) \
 			lt_patches[idx] = (patch_t *)W_CachePatchNum(patlumpnum, PU_HUDGFX); \
 	} \
 	if (patlumpnum == LUMPERROR) \
 	{ \
 		if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) \
-			lt_patches[idx] = (patch_t *)W_CachePatchName(default, PU_HUDGFX); \
+			lt_patches[idx] = (patch_t *)W_CachePatchName(def, PU_HUDGFX); \
 		else \
 			lt_patches[idx] = (patch_t *)W_CachePatchName(warning, PU_HUDGFX); \
 	} \
@@ -1551,13 +1553,16 @@ static void ST_drawPowerupHUD(void)
 	{
 		shieldoffs[q] = ICONSEP;
 
-		if ((stplyr->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE)
+		if ((stplyr->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE
+		&& (stplyr->powers[pw_shield] & SH_FORCEHP) > 0) // Special handling for >1HP Force Shields
 		{
-			UINT8 i, max = (stplyr->powers[pw_shield] & SH_FORCEHP);
-			for (i = 0; i <= max; i++)
-			{
-				V_DrawSmallScaledPatch(offs-(i<<1), hudinfo[HUD_POWERUPS].y-(i<<1), (V_PERPLAYER|hudinfo[HUD_POWERUPS].f)|((i == max) ? V_HUDTRANS : V_HUDTRANSHALF), forceshield);
-			}
+			UINT8 max = (stplyr->powers[pw_shield] & SH_FORCEHP);
+
+			V_DrawSmallScaledPatch(offs,   hudinfo[HUD_POWERUPS].y,   V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANSHALF, forceshield);
+			V_DrawSmallScaledPatch(offs-2, hudinfo[HUD_POWERUPS].y-2, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS,     forceshield);
+
+			if (max > 1) // if the shield has more than 2 hits, show the extra n hits as "+n"
+				V_DrawRightAlignedThinString(offs+16, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, va("+%d", max - 1));
 		}
 		else
 		{
@@ -1567,6 +1572,7 @@ static void ST_drawPowerupHUD(void)
 				case SH_ELEMENTAL:   p = watershield;   break;
 				case SH_ARMAGEDDON:  p = bombshield;    break;
 				case SH_ATTRACT:     p = ringshield;    break;
+				case SH_FORCE:       p = forceshield;   break;
 				case SH_PITY:        p = pityshield;    break;
 				case SH_PINK:        p = pinkshield;    break;
 				case SH_FLAMEAURA:   p = flameshield;   break;
@@ -1749,22 +1755,23 @@ static void ST_drawNightsRecords(void)
 
 	switch (stplyr->textvar)
 	{
-		case 1: // A "Bonus Time Start" by any other name...
+		case NTV_BONUSTIMESTART: // A "Bonus Time Start" by any other name...
 		{
 			V_DrawCenteredString(BASEVIDWIDTH/2, 52, V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!"));
 			V_DrawCenteredString(BASEVIDWIDTH/2, 60,            aflag, M_GetText("SCORE MULTIPLIER START!"));
 
 			if (stplyr->finishedtime)
 			{
-				V_DrawString(BASEVIDWIDTH/2 - 48, 140, aflag, "TIME:");
-				V_DrawString(BASEVIDWIDTH/2 - 48, 148, aflag, "BONUS:");
-				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE));
-				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
+				tic_t maretime = stplyr->startedtime - stplyr->finishedtime;
+				V_DrawString(BASEVIDWIDTH/2 - 48, 140, V_YELLOWMAP|aflag, "TIME:");
+				V_DrawString(BASEVIDWIDTH/2 - 48, 148, V_YELLOWMAP|aflag, "BONUS:");
+				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, aflag, va("%i:%02i.%02i", G_TicsToMinutes(maretime,true), G_TicsToSeconds(maretime), G_TicsToCentiseconds(maretime)));
+				V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100));
 			}
 			break;
 		}
-		case 2: // Get n Spheres
-		case 3: // Get n more Spheres
+		case NTV_GETSPHERES: // Get n Spheres
+		case NTV_GETMORESPHERES: // Get n more Spheres
 		{
 			if (!stplyr->capsule)
 				return;
@@ -1772,31 +1779,37 @@ static void ST_drawNightsRecords(void)
 			// Yes, this string is an abomination.
 			V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag,
 								 va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health,
-									(stplyr->textvar == 3) ? M_GetText("MORE ") : "",
+									(stplyr->textvar == NTV_GETMORESPHERES) ? M_GetText("MORE ") : "",
 									(G_IsSpecialStage(gamemap)) ? "SPHERE" : "CHIP",
 									(stplyr->capsule->health > 1) ? "S" : ""));
 			break;
 		}
-		case 4: // End Bonus
+		case NTV_BONUSTIMEEND: // End Bonus
 		{
-			V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
-			V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:");
-			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres));
-			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 148, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres * 50));
-			ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
+			V_DrawString(BASEVIDWIDTH/2 - 48, 132, V_YELLOWMAP|aflag, "TIME:");
+			V_DrawString(BASEVIDWIDTH/2 - 48, 140, V_YELLOWMAP|aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
+			V_DrawString(BASEVIDWIDTH/2 - 48, 148, V_YELLOWMAP|aflag, "BONUS:");
+			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 132, aflag, va("%i:%02i.%02i", G_TicsToMinutes(stplyr->lastmaretime,true), G_TicsToSeconds(stplyr->lastmaretime), G_TicsToCentiseconds(stplyr->lastmaretime)));
+			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, aflag, va("%d", stplyr->finishedspheres));
+			V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, aflag, va("%d", stplyr->finishedspheres * 50));
+			ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 48)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
+
+			// If this is a multi-mare map, display the mare number.
+			if (stplyr->lastmare || P_FindLowestMare() < UINT8_MAX)
+				V_DrawLevelActNum(BASEVIDWIDTH/2 - 80, 128 + 3, aflag, stplyr->lastmare + 1);
 
 			// If new record, say so!
 			if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1, clientGamedata) <= stplyr->lastmarescore)
 			{
 				if (stplyr->texttimer & 16)
-					V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *");
+					V_DrawCenteredString(BASEVIDWIDTH/2, 184, aflag, "\x85* \x82NEW RECORD \x85*\x80");
 			}
 
 			if (P_HasGrades(gamemap, stplyr->lastmare + 1))
 			{
 				UINT8 grade = P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare);
-				if (modeattacking || grade >= GRADE_A)
-					V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag, ngradeletters[grade]);
+				if (modeattacking || !G_IsSpecialStage(gamemap) || grade >= GRADE_A)
+					V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 128, aflag, ngradeletters[grade]);
 			}
 			break;
 		}
@@ -1906,7 +1919,7 @@ static void ST_drawNiGHTSHUD(void)
 	// Link drawing
 	if (!oldspecialstage
 	// Don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
-	&& !(stplyr->texttimer && stplyr->textvar == 4)
+	&& !(stplyr->texttimer && stplyr->textvar == NTV_BONUSTIMEEND)
 	&& LUA_HudEnabled(hud_nightslink)
 	&& ((cv_debug & DBG_NIGHTSBASIC) || stplyr->linkcount > 1)) // When debugging, show "0 Link".
 	{
@@ -1953,7 +1966,7 @@ static void ST_drawNiGHTSHUD(void)
 		INT32 amount;
 		const INT32 length = 88;
 
-		origamount = stplyr->capsule->spawnpoint->angle;
+		origamount = stplyr->capsule->spawnpoint->args[1];
 		I_Assert(origamount > 0); // should not happen now
 
 		ST_DrawTopLeftOverlayPatch(72, 8, nbracket);
diff --git a/src/string.c b/src/string.c
index 2f16fa4c68a35fa287156f546fc2973e9d4ad426..b24e12e6e36fec3078aaae76bee7a765f9c30c8f 100644
--- a/src/string.c
+++ b/src/string.c
@@ -68,3 +68,27 @@ int endswith(const char *base, const char *tag)
 
 	return !memcmp(&base[base_length - tag_length], tag, tag_length);
 }
+
+// strtok version that only skips over one delimiter at a time
+char *xstrtok(char *line, const char *delims)
+{
+	static char *saveline = NULL;
+	char *p;
+
+	if(line != NULL)
+		saveline = line;
+
+	// see if we have reached the end of the line
+	if(saveline == NULL || *saveline == '\0')
+		return NULL;
+
+	p = saveline; // save start of this token
+	
+	saveline += strcspn(saveline, delims); // get the number of non-delims characters, go past delimiter
+
+	if(*saveline != '\0') // trash the delim if necessary
+		*saveline++ = '\0';
+
+	return p;
+}
+
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
deleted file mode 100644
index 28c4ce492f2d8b4e7590e3ac10f9ce6a95d98a0f..0000000000000000000000000000000000000000
--- a/src/tests/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-target_sources(srb2tests PRIVATE
-	boolcompat.cpp
-)
diff --git a/src/tests/boolcompat.cpp b/src/tests/boolcompat.cpp
deleted file mode 100644
index fee40cd36f2bce34217a875024d6b41fe71adbd1..0000000000000000000000000000000000000000
--- a/src/tests/boolcompat.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <catch2/catch_test_macros.hpp>
-
-#include "../doomtype.h"
-
-TEST_CASE("C++ bool is convertible to doomtype.h boolean") {
-	REQUIRE(static_cast<boolean>(true) == 1);
-	REQUIRE(static_cast<boolean>(false) == 0);
-}
diff --git a/src/v_video.c b/src/v_video.c
index 355bdf860160dced8d8baad8679ba86c68ed4582..3beb435b58428491e5b62f3ce48ec35535c25f60 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1923,70 +1923,37 @@ UINT8 *V_GetStringColormap(INT32 colorflags)
 	}
 }
 
-// Writes a single character (draw WHITE if bit 7 set)
+// Generalized character drawing function, combining console & chat functionality with a specified font.
 //
-void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed)
+void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fixed_t scale, UINT8 *colormap, fontdef_t font)
 {
 	INT32 w, flags;
-	const UINT8 *colormap = V_GetStringColormap(c);
+	const UINT8 *color = colormap ? colormap : V_GetStringColormap(c);
 
 	flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
 	c &= 0x7f;
-	if (lowercaseallowed)
-		c -= HU_FONTSTART;
-	else
-		c = toupper(c) - HU_FONTSTART;
-	if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
+	c = (lowercaseallowed ? c : toupper(c)) - FONTSTART;
+	if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		return;
 
-	w = hu_font[c]->width;
+	w = FixedMul(font.chars[c]->width / 2, scale);	// use normal sized characters if we're using a terribly low resolution.
 	if (x + w > vid.width)
 		return;
 
-	if (colormap != NULL)
-		V_DrawMappedPatch(x, y, flags, hu_font[c], colormap);
-	else
-		V_DrawScaledPatch(x, y, flags, hu_font[c]);
+	V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, scale, flags, font.chars[c], color);
 }
 
-// Writes a single character for the chat. (draw WHITE if bit 7 set)
-// Essentially the same as the above but it's small or big depending on what resolution you've chosen to huge..
+// Precompile a wordwrapped string to any given width, using a specified font.
 //
-void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap)
-{
-	INT32 w, flags;
-	//const UINT8 *colormap = V_GetStringColormap(c);
-
-	flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
-	c &= 0x7f;
-	if (lowercaseallowed)
-		c -= HU_FONTSTART;
-	else
-		c = toupper(c) - HU_FONTSTART;
-	if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		return;
-
-	w = (vid.width < 640 ) ? ((hu_font[c]->width / 2)) : (hu_font[c]->width);	// use normal sized characters if we're using a terribly low resolution.
-	if (x + w > vid.width)
-		return;
-
-	V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, (vid.width < 640) ? (FRACUNIT) : (FRACUNIT/2), flags, hu_font[c], colormap);
-
-
-}
-
-// Precompile a wordwrapped string to any given width.
-// This is a muuuch better method than V_WORDWRAP.
-char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
+char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font)
 {
 	int c;
-	size_t chw, i, lastusablespace = 0;
-	size_t slen;
+	size_t slen, chw, i, lastusablespace = 0;
 	char *newstring = Z_StrDup(string);
-	INT32 spacewidth = 4, charwidth = 0;
+	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	slen = strlen(string);
-
+	
 	if (w == 0)
 		w = BASEVIDWIDTH;
 	w -= x;
@@ -1995,814 +1962,104 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
 	switch (option & V_SPACINGMASK)
 	{
 		case V_MONOSPACE:
-			spacewidth = 8;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 8;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (i = 0; i < slen; ++i)
-	{
-		c = newstring[i];
-		if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
-			continue;
-
-		if (c == '\n')
-		{
-			x = 0;
-			lastusablespace = 0;
-			continue;
-		}
-
-		if (!(option & V_ALLOWLOWERCASE))
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			chw = spacewidth;
-			lastusablespace = i;
-		}
-		else
-			chw = (charwidth ? charwidth : hu_font[c]->width);
-
-		x += chw;
-
-		if (lastusablespace != 0 && x > w)
-		{
-			newstring[lastusablespace] = '\n';
-			i = lastusablespace;
-			lastusablespace = 0;
-			x = 0;
-		}
-	}
-	return newstring;
-}
-
-//
-// Write a string using the hu_font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = (option & V_CHARCOLORMASK);
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 4, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 8;
+			spacewidth = font.charwidth;
 			/* FALLTHRU */
 		case V_OLDSPACING:
-			charwidth = 8;
+			charwidth = font.charwidth;
 			break;
 		case V_6WIDTHSPACE:
 			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 8*dup;
-			else
-				cy += 12*dup;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += spacewidth * dup;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*dup/2;
-		}
-		else
-			w = hu_font[c]->width * dup;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, hu_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_StringWidth(string, option)/2;
-	V_DrawString(x, y, option, string);
-}
-
-void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_StringWidth(string, option);
-	V_DrawString(x, y, option, string);
-}
-
-//
-// Write a string using the hu_font, 0.5x scale
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 4;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 4;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 4*dup;
-			else
-				cy += 6*dup;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += spacewidth * dup;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*dup/4;
-		}
-		else
-			w = hu_font[c]->width * dup / 2;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT/2, option, hu_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_SmallStringWidth(string, option)/2;
-	V_DrawSmallString(x, y, option, string);
-}
-
-
-void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_SmallStringWidth(string, option);
-	V_DrawSmallString(x, y, option, string);
-}
-
-//
-// Write a string using the tny_font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 5;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 5;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 8*dup;
-			else
-				cy += 12*dup;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase || !tny_font[c-HU_FONTSTART])
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
-		{
-			cx += spacewidth * dup;
-			continue;
-		}
-
-		if (charwidth)
-			w = charwidth * dup;
-		else
-			w = tny_font[c]->width * dup;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, tny_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_ThinStringWidth(string, option)/2;
-	V_DrawThinString(x, y, option, string);
-}
-
-void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x -= V_ThinStringWidth(string, option);
-	V_DrawThinString(x, y, option, string);
-}
-
-//
-// Write a string using the tny_font, 0.5x scale
-// NOTE: the text is centered for screens larger than the base width
-//
-// Literally a wrapper. ~Golden
-void V_DrawSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x <<= FRACBITS;
-	y <<= FRACBITS;
-	V_DrawSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
-}
-
-void V_DrawCenteredSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x <<= FRACBITS;
-	y <<= FRACBITS;
-	V_DrawCenteredSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
-}
-
-void V_DrawRightAlignedSmallThinString(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	x <<= FRACBITS;
-	y <<= FRACBITS;
-	V_DrawRightAlignedSmallThinStringAtFixed((fixed_t)x, (fixed_t)y, option, string);
-}
-
-// Draws a string at a fixed_t location.
-void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 4, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 8;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 8;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color ignoring
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += (8*dup)<<FRACBITS;
-			else
-				cy += (12*dup)<<FRACBITS;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += (spacewidth * dup)<<FRACBITS;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*(dup/2);
-		}
-		else
-			w = hu_font[c]->width * dup;
-
-		if ((cx>>FRACBITS) > scrwidth)
-			continue;
-		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
-		{
-			cx += w<<FRACBITS;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT, option, hu_font[c], colormap);
-
-		cx += w<<FRACBITS;
-	}
-}
-
-void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= (V_StringWidth(string, option) / 2)<<FRACBITS;
-	V_DrawStringAtFixed(x, y, option, string);
-}
-
-void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= V_StringWidth(string, option)<<FRACBITS;
-	V_DrawStringAtFixed(x, y, option, string);
-}
-
-// Draws a small string at a fixed_t location.
-void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 4;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 4;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += (4*dup)<<FRACBITS;
-			else
-				cy += (6*dup)<<FRACBITS;
-
-			continue;
-		}
-
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-		{
-			cx += (spacewidth * dup)<<FRACBITS;
-			continue;
-		}
-
-		if (charwidth)
-		{
-			w = charwidth * dup;
-			center = w/2 - hu_font[c]->width*(dup/4);
-		}
-		else
-			w = hu_font[c]->width * dup / 2;
-
-		if ((cx>>FRACBITS) > scrwidth)
-			break;
-		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
-		{
-			cx += w<<FRACBITS;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-
-		V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT/2, option, hu_font[c], colormap);
-
-		cx += w<<FRACBITS;
-	}
-}
-
-void V_DrawCenteredSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= (V_SmallStringWidth(string, option) / 2)<<FRACBITS;
-	V_DrawSmallStringAtFixed(x, y, option, string);
-}
-
-void V_DrawRightAlignedSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= V_SmallStringWidth(string, option)<<FRACBITS;
-	V_DrawSmallStringAtFixed(x, y, option, string);
-}
-
-// Draws a thin string at a fixed_t location.
-void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
-	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2, charwidth = 0;
-
-	INT32 lowercase = (option & V_ALLOWLOWERCASE);
-	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 8;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 8;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 6;
-		default:
-			break;
-	}
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-
-			if (option & V_RETURN8)
-				cy += (8*dup)<<FRACBITS;
-			else
-				cy += (12*dup)<<FRACBITS;
+		default:
+			break;
+	}
 
+	for (i = 0; i < slen; ++i)
+	{
+		c = newstring[i];
+		if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
 			continue;
-		}
 
-		c = *ch;
-		if (!lowercase || !tny_font[c-HU_FONTSTART])
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
+		if (c == '\n')
 		{
-			cx += (spacewidth * dup)<<FRACBITS;
+			x = 0;
+			lastusablespace = 0;
 			continue;
 		}
 
-		if (charwidth)
+		c = (option & V_ALLOWLOWERCASE ? c : toupper(c)) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		{
-			w = charwidth * dup;
-			center = w/2 - tny_font[c]->width*(dup/2);
+			chw = spacewidth;
+			lastusablespace = i;
 		}
 		else
-			w = tny_font[c]->width * dup;
+			chw = (charwidth ? charwidth : font.chars[c]->width);
 
-		if ((cx>>FRACBITS) > scrwidth)
-			break;
-		if ((cx>>FRACBITS)+left + w < 0) //left boundary check
+		x +=  FixedMul(chw, scale);
+
+		if (lastusablespace != 0 && x > w)
 		{
-			cx += w<<FRACBITS;
-			continue;
+			newstring[lastusablespace] = '\n';
+			i = lastusablespace;
+			lastusablespace = x = 0;
 		}
-
-		colormap = V_GetStringColormap(charflags);
-
-		V_DrawFixedPatch(cx + (center<<FRACBITS), cy, FRACUNIT, option, tny_font[c], colormap);
-
-		cx += w<<FRACBITS;
 	}
+	return newstring;
 }
 
-void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+// Draw a string, using a supplied font and scale.
+// NOTE: The text is centered for screens larger than the base width.
+void V_DrawFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
 {
-	x -= (V_ThinStringWidth(string, option) / 2)<<FRACBITS;
-	V_DrawThinStringAtFixed(x, y, option, string);
+	V_DrawFontStringAtFixed((fixed_t)x<<FRACBITS, (fixed_t)y<<FRACBITS, option, pscale, vscale, string, font);
 }
 
-void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+void V_DrawAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align)
 {
-	x -= V_ThinStringWidth(string, option)<<FRACBITS;
-	V_DrawThinStringAtFixed(x, y, option, string);
+	V_DrawAlignedFontStringAtFixed((fixed_t)x<<FRACBITS, (fixed_t)y<<FRACBITS, option, pscale, vscale, string, font, align);
 }
 
-// Draws a small string at a fixed_t location.
-void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+// Write a string, using a supplied font and scale, at fixed_t coordinates.
+// NOTE: The text is centered for screens larger than the base width.
+void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
 {
 	fixed_t cx = x, cy = y;
-	INT32 w, c, dup, scrwidth, center = 0, left = 0;
+	INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0;
 	const char *ch = string;
-	INT32 charflags = 0;
-	const UINT8 *colormap = NULL;
-	INT32 spacewidth = 2<<FRACBITS, charwidth = 0;
+	INT32 charflags = (option & V_CHARCOLORMASK);
+	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	INT32 lowercase = (option & V_ALLOWLOWERCASE);
 	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
 
 	if (option & V_NOSCALESTART)
 	{
-		dup = vid.dup<<FRACBITS;
+		dupx = vid.dup<<FRACBITS;
+		dupy = vid.dup<<FRACBITS;
 		scrwidth = vid.width;
 	}
 	else
 	{
-		dup = FRACUNIT;
+		dupx = pscale;
+		dupy = vscale;
 		scrwidth = FixedDiv(vid.width<<FRACBITS, vid.dup);
-		left = ((scrwidth - (BASEVIDWIDTH<<FRACBITS))/2);
+		left = (scrwidth - (BASEVIDWIDTH << FRACBITS))/2;
 		scrwidth -= left;
 	}
 
 	if (option & V_NOSCALEPATCH)
 		scrwidth *= vid.dup;
 
-	charflags = (option & V_CHARCOLORMASK);
-
-	switch (option & V_SPACINGMASK)
+	switch (option & V_SPACINGMASK) // TODO: 2.3: drop support for these crusty flags
 	{
 		case V_MONOSPACE:
-			spacewidth = 4<<FRACBITS;
+			spacewidth = font.charwidth;
 			/* FALLTHRU */
 		case V_OLDSPACING:
-			charwidth = 4<<FRACBITS;
+			charwidth = font.charwidth;
 			break;
 		case V_6WIDTHSPACE:
-			spacewidth = 3<<FRACBITS;
+			spacewidth = 6;
 		default:
 			break;
 	}
@@ -2821,61 +2078,66 @@ void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char
 		if (*ch == '\n')
 		{
 			cx = x;
-
-			if (option & V_RETURN8)
-				cy += 4*dup;
-			else
-				cy += 6*dup;
-
+			cy += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, dupy);
 			continue;
 		}
 
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= HU_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
+		c = (lowercase ? *ch : toupper(*ch)) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		{
-			cx += FixedMul(spacewidth, dup);
+			cx += FixedMul((spacewidth<<FRACBITS), dupx);
 			continue;
 		}
 
 		if (charwidth)
 		{
-			w = FixedMul(charwidth, dup);
-			center = w/2 - tny_font[c]->width*(dup/4);
+			w = FixedMul((charwidth<<FRACBITS), dupx);
+			center = w/2 - FixedMul(font.chars[c]->width<<FRACBITS, (dupx/2));
 		}
 		else
-			w = tny_font[c]->width * dup / 2;
+			w = FixedMul(font.chars[c]->width<<FRACBITS, dupx);
 
-		if (cx > scrwidth)
-			break;
+		if ((cx>>FRACBITS) > scrwidth)
+			continue;
 		if (cx+left + w < 0) //left boundary check
 		{
 			cx += w;
 			continue;
 		}
 
-		colormap = V_GetStringColormap(charflags);
-
-		V_DrawFixedPatch(cx + center, cy, FRACUNIT/2, option, tny_font[c], colormap);
+		V_DrawStretchyFixedPatch(cx + center, cy, pscale, vscale, option, font.chars[c], V_GetStringColormap(charflags));
 
-		cx += w;
+		cx += w + (font.kerning<<FRACBITS);
 	}
 }
 
-void V_DrawCenteredSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
+void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align)
 {
-	x -= V_SmallThinStringWidth(string, option)/4;
-	V_DrawSmallThinStringAtFixed(x, y, option, string);
-}
+	char *text = strdup(string);
+	char* line = xstrtok(text, "\n");
+	fixed_t lx = x, ly = y;
 
-void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
-{
-	x -= V_SmallThinStringWidth(string, option)/2;
-	V_DrawSmallThinStringAtFixed(x, y, option, string);
+	while (line)
+	{
+		switch(align)
+		{
+			case alignleft:
+				lx = x;
+				break;
+			case aligncenter:
+				lx = x - (V_FontStringWidth(line, option, font)*pscale) / 2;
+				break;
+			case alignright:
+				lx = x - (V_FontStringWidth(line, option, font)*pscale);
+				break;
+		}
+		
+		V_DrawFontStringAtFixed(lx, ly, option, pscale, vscale, line, font);
+
+		ly += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, vscale);
+
+		line = xstrtok(NULL, "\n");
+	}
 }
 
 // Draws a tallnum.  Replaces two functions in y_inter and st_stuff
@@ -2940,56 +2202,21 @@ void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num)
 	}
 }
 
-// Write a string using the credit font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string)
+// Returns the width of the act num patch(es)
+INT16 V_LevelActNumWidth(UINT8 num)
 {
-	INT32 w, c, dup, scrwidth = BASEVIDWIDTH;
-	fixed_t cx = x, cy = y;
-	const char *ch = string;
+	INT16 result = 0;
 
-	// It's possible for string to be a null pointer
-	if (!string)
-		return;
+	if (num == 0)
+		result = ttlnum[num]->width;
 
-	if (option & V_NOSCALESTART)
+	while (num > 0 && num <= 99)
 	{
-		dup = vid.dup;
-		scrwidth = vid.width;
+		result = result + ttlnum[num%10]->width;
+		num = num/10;
 	}
-	else
-		dup = 1;
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	for (;;)
-	{
-		c = *ch++;
-		if (!c)
-			break;
-		if (c == '\n')
-		{
-			cx = x;
-			cy += (12*dup)<<FRACBITS;
-			continue;
-		}
-
-		c = toupper(c) - CRED_FONTSTART;
-		if (c < 0 || c >= CRED_FONTSIZE)
-		{
-			cx += (16*dup)<<FRACBITS;
-			continue;
-		}
-
-		w = cred_font[c]->width * dup;
-		if ((cx>>FRACBITS) > scrwidth)
-			continue;
 
-		V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT);
-		cx += w<<FRACBITS;
-	}
+	return result;
 }
 
 // Draw a string using the nt_font
@@ -3030,21 +2257,18 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
 		if (*ch == '\n')
 		{
 			cx = x<<FRACBITS;
-			cy += FixedMul((21*dup)*FRACUNIT, scale);
+			cy += FixedMul((ntb_font.linespacing * dup)*FRACUNIT, scale);
 			continue;
 		}
 
-		c = toupper(*ch);
-		c -= NT_FONTSTART;
-
-		// character does not exist or is a space
-		if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c])
+		c = toupper(*ch) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !ntb_font.chars[c] || !nto_font.chars[c])
 		{
-			cx += FixedMul((4 * dup)*FRACUNIT, scale);
+			cx += FixedMul((ntb_font.spacewidth * dup)*FRACUNIT, scale);
 			continue;
 		}
 
-		w = FixedMul(((ntb_font[c]->width)+2 * dup) * FRACUNIT, scale);
+		w = FixedMul(((ntb_font.chars[c]->width)+ntb_font.kerning * dup) * FRACUNIT, scale);
 
 		if (FixedInt(cx) > scrwidth)
 			continue;
@@ -3054,8 +2278,8 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
 			continue;
 		}
 
-		V_DrawFixedPatch(cx, cy, scale, option, nto_font[c], outlinecolormap);
-		V_DrawFixedPatch(cx, cy, scale, option, ntb_font[c], basecolormap);
+		V_DrawFixedPatch(cx, cy, scale, option, nto_font.chars[c], outlinecolormap);
+		V_DrawFixedPatch(cx, cy, scale, option, ntb_font.chars[c], basecolormap);
 
 		cx += w;
 	}
@@ -3170,193 +2394,20 @@ INT32 V_CountNameTagLines(const char *string)
 	return ntlines;
 }
 
-INT32 V_NameTagWidth(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	// It's possible for string to be a null pointer
-	if (!string)
-		return 0;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		c = toupper(string[i]) - NT_FONTSTART;
-		if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c])
-			w += 4;
-		else
-			w += (ntb_font[c]->width)+2;
-	}
-
-	return w;
-}
-
-// Find string width from cred_font chars
-//
-INT32 V_CreditStringWidth(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	// It's possible for string to be a null pointer
-	if (!string)
-		return 0;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		c = toupper(string[i]) - CRED_FONTSTART;
-		if (c < 0 || c >= CRED_FONTSIZE)
-			w += 16;
-		else
-			w += cred_font[c]->width;
-	}
-
-	return w;
-}
-
-// Write a string using the level title font
-// NOTE: the text is centered for screens larger than the base width
-//
-void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
-{
-	INT32 w, c, cx = x, cy = y, dup, scrwidth, left = 0;
-	const char *ch = string;
-	INT32 charflags = (option & V_CHARCOLORMASK);
-	const UINT8 *colormap = NULL;
-
-	if (option & V_NOSCALESTART)
-	{
-		dup = vid.dup;
-		scrwidth = vid.width;
-	}
-	else
-	{
-		dup = 1;
-		scrwidth = vid.width/vid.dup;
-		left = (scrwidth - BASEVIDWIDTH)/2;
-		scrwidth -= left;
-	}
-
-	if (option & V_NOSCALEPATCH)
-		scrwidth *= vid.dup;
-
-	for (;;ch++)
-	{
-		if (!*ch)
-			break;
-		if (*ch & 0x80) //color parsing -x 2.16.09
-		{
-			// manually set flags override color codes
-			if (!(option & V_CHARCOLORMASK))
-				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
-			continue;
-		}
-		if (*ch == '\n')
-		{
-			cx = x;
-			cy += 12*dup;
-			continue;
-		}
-
-		c = *ch - LT_FONTSTART;
-		if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
-		{
-			cx += 16*dup;
-			continue;
-		}
-
-		w = lt_font[c]->width * dup;
-
-		if (cx > scrwidth)
-			continue;
-		if (cx+left + w < 0) //left boundary check
-		{
-			cx += w;
-			continue;
-		}
-
-		colormap = V_GetStringColormap(charflags);
-		V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, lt_font[c], colormap);
-
-		cx += w;
-	}
-}
-
-// Find string width from lt_font chars
-//
-INT32 V_LevelNameWidth(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		if (string[i] & 0x80)
-			continue;
-		c = string[i] - LT_FONTSTART;
-		if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
-			w += 16;
-		else
-			w += lt_font[c]->width;
-	}
-
-	return w;
-}
-
-// Find max height of the string
-//
-INT32 V_LevelNameHeight(const char *string)
-{
-	INT32 c, w = 0;
-	size_t i;
-
-	for (i = 0; i < strlen(string); i++)
-	{
-		c = string[i] - LT_FONTSTART;
-		if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
-			continue;
-
-		if (lt_font[c]->height > w)
-			w = lt_font[c]->height;
-	}
-
-	return w;
-}
-
-// For ST_drawTitleCard
-// Returns the width of the act num patch(es)
-INT16 V_LevelActNumWidth(UINT8 num)
-{
-	INT16 result = 0;
-
-	if (num == 0)
-		result = ttlnum[num]->width;
-
-	while (num > 0 && num <= 99)
-	{
-		result = result + ttlnum[num%10]->width;
-		num = num/10;
-	}
-
-	return result;
-}
-
+// Find string width from supplied font characters & character width.
 //
-// Find string width from hu_font chars
-//
-INT32 V_StringWidth(const char *string, INT32 option)
+INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 {
-	INT32 c, w = 0;
-	INT32 spacewidth = 4, charwidth = 0;
-	size_t i;
+	INT32 c, w = 0, wline = 0;
+	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	switch (option & V_SPACINGMASK)
 	{
 		case V_MONOSPACE:
-			spacewidth = 8;
+			spacewidth = font.charwidth;
 			/* FALLTHRU */
 		case V_OLDSPACING:
-			charwidth = 8;
+			charwidth = font.charwidth;
 			break;
 		case V_6WIDTHSPACE:
 			spacewidth = 6;
@@ -3364,16 +2415,24 @@ INT32 V_StringWidth(const char *string, INT32 option)
 			break;
 	}
 
-	for (i = 0; i < strlen(string); i++)
+	for (size_t i = 0; i < strlen(string); i++)
 	{
+		if (string[i] == '\n')
+		{
+			if (wline < w) wline = w;
+			w = 0;
+			continue;
+		}	
 		if (string[i] & 0x80)
 			continue;
-		c = toupper(string[i]) - HU_FONTSTART;
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
+
+		c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 			w += spacewidth;
 		else
-			w += (charwidth ? charwidth : hu_font[c]->width);
+			w += (charwidth ? charwidth : (font.chars[c]->width)) + font.kerning;
 	}
+	w = max(wline, w);
 
 	if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
 		w *= vid.dup;
@@ -3381,87 +2440,30 @@ INT32 V_StringWidth(const char *string, INT32 option)
 	return w;
 }
 
+// Find max string height from supplied font characters
 //
-// Find string width from hu_font chars, 0.5x scale
-//
-INT32 V_SmallStringWidth(const char *string, INT32 option)
+INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font)
 {
-	INT32 c, w = 0;
-	INT32 spacewidth = 2, charwidth = 0;
-	size_t i;
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 4;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 4;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
+	INT32 c, h = 0, result = 0;
 
-	for (i = 0; i < strlen(string); i++)
+	for (size_t i = 0; i < strlen(string); i++)
 	{
-		if (string[i] & 0x80)
+		c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
+		if (c < 0 || c >= FONTSIZE || !font.chars[c])
+		{
+			if (string[i] == '\n')
+			{
+				result += (option & V_RETURN8) ? 8 : font.linespacing;
+				h = 0;
+			}	
 			continue;
-		c = toupper(string[i]) - HU_FONTSTART;
-		if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
-			w += spacewidth;
-		else
-			w += (charwidth ? charwidth : (hu_font[c]->width / 2));
-	}
-
-	return w;
-}
-
-//
-// Find string width from tny_font chars
-//
-INT32 V_ThinStringWidth(const char *string, INT32 option)
-{
-	INT32 c, w = 0;
-	INT32 spacewidth = 2, charwidth = 0;
-	size_t i;
-
-	switch (option & V_SPACINGMASK)
-	{
-		case V_MONOSPACE:
-			spacewidth = 5;
-			/* FALLTHRU */
-		case V_OLDSPACING:
-			charwidth = 5;
-			break;
-		case V_6WIDTHSPACE:
-			spacewidth = 3;
-		default:
-			break;
-	}
+		}
 
-	for (i = 0; i < strlen(string); i++)
-	{
-		if (string[i] & 0x80)
-			continue;
-		c = toupper(string[i]) - HU_FONTSTART;
-		if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
-			w += spacewidth;
-		else
-			w += (charwidth ? charwidth : tny_font[c]->width);
+		if (font.chars[c]->height > h)
+			h = font.chars[c]->height;
 	}
 
-	return w;
-}
-
-//
-// Find string width from tny_font chars, 0.5x scale
-//
-INT32 V_SmallThinStringWidth(const char *string, INT32 option)
-{
-	INT32 w = V_ThinStringWidth(string, option)<<FRACBITS;
-	return w/2 + FRACUNIT; // +FRACUNIT because otherwise it's offset wrong.
+	return result + h;
 }
 
 boolean *heatshifter = NULL;
diff --git a/src/v_video.h b/src/v_video.h
index 5a3df5a4499588df56e4a6d152f1445f82a60926..d37762466147ae843c8f0fba5218f4e8af3f6462 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -17,6 +17,7 @@
 #include "doomdef.h"
 #include "doomtype.h"
 #include "r_defs.h"
+#include "hu_stuff.h" //font arrays
 
 //
 // VIDEO
@@ -191,86 +192,93 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U
 
 void V_DrawFadeConsBack(INT32 plines);
 void V_DrawPromptBack(INT32 boxheight, INT32 color);
-
-// draw a single character
-void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
-// draw a single character, but for the chat
-void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap);
-
-UINT8 *V_GetStringColormap(INT32 colorflags);
-
-void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string);
-
-// wordwrap a string using the hu_font
-char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string);
 UINT8 *V_GetStringColormap(INT32 colorflags);
 
+// Generalized character drawing function, combining console & chat functionality with a specified font.
+void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fixed_t scale, UINT8 *colormap, fontdef_t font);
+#define V_DrawCharacter(x,y,c,l) V_DrawFontCharacter(x,y,c,l,FRACUNIT,NULL,hu_font)
+#define V_DrawChatCharacter(x,y,c,l,cm) V_DrawFontCharacter(x,y,c,l,FRACUNIT/2,cm,hu_font)
+
+// Precompile a wordwrapped string to any given width, using a specified font.
+char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font);
+#define V_WordWrap(x,w,o,str) V_FontWordWrap(x, w, o, FRACUNIT, str, hu_font)
+#define V_ChatWordWrap(x,w,o,str) V_FontWordWrap(x, w, o, FRACUNIT/2, str, hu_font)
+
+enum string_align {
+	alignleft = 0,
+	aligncenter,
+	alignright
+};
+
+// Draw a string, using a supplied font and scale.
+void V_DrawFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
+void V_DrawAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align);
+// Draw a string, using a supplied font and scale, at fixed_t coordinates.
+void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
+void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, enum string_align align);
+
+// Defines for old string drawers.
 // draw a string using the hu_font
-void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string);
-
+#define V_DrawString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT,FRACUNIT,str,hu_font)
+#define V_DrawCenteredString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,aligncenter)
+#define V_DrawRightAlignedString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,alignright)
 // draw a string using the hu_font, 0.5x scale
-void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string);
-
-// draw a string using the tny_font
-void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string);
-
+#define V_DrawSmallString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font)
+#define V_DrawCenteredSmallString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,aligncenter)
+#define V_DrawRightAlignedSmallString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,alignright)
+// Write a string using the tny_font
+#define V_DrawThinString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT,FRACUNIT,str,tny_font)
+#define V_DrawCenteredThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,aligncenter)
+#define V_DrawRightAlignedThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,alignright)
 // draw a string using the tny_font, 0.5x scale
-void V_DrawSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawCenteredSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
-
+#define V_DrawSmallThinString(x,y,o,str) V_DrawFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font)
+#define V_DrawCenteredSmallThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,aligncenter)
+#define V_DrawRightAlignedSmallThinString(x,y,o,str) V_DrawAlignedFontString(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,alignright)
 // draw a string using the hu_font at fixed_t coordinates
-void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-
+#define V_DrawStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,hu_font)
+#define V_DrawCenteredStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,aligncenter)
+#define V_DrawRightAlignedStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,hu_font,alignright)
 // draw a string using the hu_font at fixed_t coordinates, 0.5x scale
-void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-
+#define V_DrawSmallStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font)
+#define V_DrawCenteredSmallStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,aligncenter)
+#define V_DrawRightAlignedSmallStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,hu_font,alignright)
 // draw a string using the tny_font at fixed_t coordinates
-void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-
+#define V_DrawThinStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,tny_font)
+#define V_DrawCenteredThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,aligncenter)
+#define V_DrawRightAlignedThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,tny_font,alignright)
 // draw a string using the tny_font at fixed_t coordinates, 0.5x scale
-void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawCenteredSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
-void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
+#define V_DrawSmallThinStringAtFixed(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font)
+#define V_DrawCenteredSmallThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,aligncenter)
+#define V_DrawRightAlignedSmallThinStringAtFixed(x,y,o,str) V_DrawAlignedFontStringAtFixed(x,y,o,FRACUNIT/2,FRACUNIT/2,str,tny_font,alignright)
+// draw a string using the credit font
+#define V_DrawCreditString(x,y,o,str) V_DrawFontStringAtFixed(x,y,o,FRACUNIT,FRACUNIT,str,cred_font)
+// draw a string using the level title font
+#define V_DrawLevelTitle(x,y,o,str) V_DrawFontString(x,y,o|V_ALLOWLOWERCASE,FRACUNIT,FRACUNIT,str,lt_font)
 
 // Draw tall nums, used for menu, HUD, intermission
 void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num);
 void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits);
 void V_DrawLevelActNum(INT32 x, INT32 y, INT32 flags, UINT8 num);
-
-// Find string width from lt_font chars
-INT32 V_LevelNameWidth(const char *string);
-INT32 V_LevelNameHeight(const char *string);
 INT16 V_LevelActNumWidth(UINT8 num); // act number width
 
-void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string);
-INT32 V_CreditStringWidth(const char *string);
-
 // Draw a string using the nt_font
 void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string);
 INT32 V_CountNameTagLines(const char *string);
-INT32 V_NameTagWidth(const char *string);
-
-// Find string width from hu_font chars
-INT32 V_StringWidth(const char *string, INT32 option);
-// Find string width from hu_font chars, 0.5x scale
-INT32 V_SmallStringWidth(const char *string, INT32 option);
-// Find string width from tny_font chars
-INT32 V_ThinStringWidth(const char *string, INT32 option);
-// Find string width from tny_font chars, 0.5x scale
-INT32 V_SmallThinStringWidth(const char *string, INT32 option);
+
+// Find string width or height from supplied font chars
+INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font);
+INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font);
+
+// Defines for old string width functions.
+#define V_StringWidth(str,o) V_FontStringWidth(str,o,hu_font)
+#define V_SmallStringWidth(str,o) V_FontStringWidth(str,o,hu_font)/2
+#define V_ThinStringWidth(str,o) V_FontStringWidth(str,o,tny_font)
+#define V_SmallThinStringWidth(str,o) V_FontStringWidth(str,o,tny_font)/2
+#define V_CreditStringWidth(str) V_FontStringWidth(str,0,cred_font)
+#define V_NameTagWidth(str) V_FontStringWidth(str,0,ntb_font)
+#define V_LevelNameWidth(str) V_FontStringWidth(str,V_ALLOWLOWERCASE,lt_font)
+#define V_LevelNameHeight(str) V_FontStringHeight(str,0,lt_font)
+#define V_StringHeight(str,o) V_FontStringHeight(str,o,hu_font)
 
 void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param);
 
diff --git a/src/w_wad.c b/src/w_wad.c
index 0666c4a600bcf20678f88539fb4055a0d5466992..cc7cdc20167d616083d86db652b05aa8eb182e5e 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -98,6 +98,7 @@ typedef struct lumpnum_cache_s
 {
 	char lumpname[32];
 	lumpnum_t lumpnum;
+	UINT32 hash;
 } lumpnum_cache_t;
 
 static lumpnum_cache_t lumpnumcache[LUMPNUMCACHESIZE];
@@ -1349,6 +1350,47 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
 	return i;
 }
 
+char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump)
+{
+	const char *fullname = wadfiles[wad]->lumpinfo[lump].fullname;
+
+	const char *slash = strrchr(fullname, '/');
+	INT32 pathlen = slash ? slash - fullname : 0;
+
+	char *path = Z_Calloc(pathlen + 1, PU_STATIC, NULL);
+	strncpy(path, fullname, pathlen);
+
+	return path;
+}
+
+char *W_GetLumpFolderNamePK3(UINT16 wad, UINT16 lump)
+{
+	const char *fullname = wadfiles[wad]->lumpinfo[lump].fullname;
+	size_t start, end;
+
+	INT32 i = strlen(fullname);
+
+	i--;
+	while (i >= 0 && fullname[i] != '/')
+		i--;
+	if (i < 0)
+		return NULL;
+	end = i;
+
+	i--;
+	while (i >= 0 && fullname[i] != '/')
+		i--;
+	if (i < 0)
+		return NULL;
+	start = i + 1;
+
+	size_t namelen = end - start;
+	char *foldername = Z_Calloc(namelen + 1, PU_STATIC, NULL);
+	strncpy(foldername, fullname + start, namelen);
+
+	return foldername;
+}
+
 void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps)
 {
 	size_t name_length = strlen(name);
@@ -1434,6 +1476,63 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
 	return INT16_MAX;
 }
 
+static lumpnum_t CheckLumpInCache(const char *name, boolean longname)
+{
+	if (longname)
+	{
+		UINT32 hash = quickncasehash(name, 32);
+
+		// Loop backwards so that we check most recent entries first
+		for (INT32 i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
+		{
+			if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].hash == hash
+				&& stricmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
+			{
+				lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
+				return lumpnumcache[lumpnumcacheindex].lumpnum;
+			}
+		}
+	}
+	else
+	{
+		UINT32 hash = quickncasehash(name, 8);
+
+		// Loop backwards so that we check most recent entries first
+		for (INT32 i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
+		{
+			if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].hash == hash
+				&& lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8] == '\0'
+				&& strnicmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0)
+			{
+				lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
+				return lumpnumcache[lumpnumcacheindex].lumpnum;
+			}
+		}
+	}
+
+	return LUMPERROR;
+}
+
+static void AddLumpToCache(lumpnum_t lumpnum, const char *name, boolean longname)
+{
+	if (longname && strlen(name) >= 32)
+		return;
+
+	lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
+	memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
+	if (longname)
+	{
+		strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32);
+		lumpnumcache[lumpnumcacheindex].hash = quickncasehash(name, 32);
+	}
+	else
+	{
+		strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8);
+		lumpnumcache[lumpnumcacheindex].hash = quickncasehash(name, 8);
+	}
+	lumpnumcache[lumpnumcacheindex].lumpnum = lumpnum;
+}
+
 //
 // W_CheckNumForName
 // Returns LUMPERROR if name not found.
@@ -1446,17 +1545,10 @@ lumpnum_t W_CheckNumForName(const char *name)
 	if (!*name) // some doofus gave us an empty string?
 		return LUMPERROR;
 
-	// Check the lumpnumcache first. Loop backwards so that we check
-	// most recent entries first
-	for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
-	{
-		if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8]
-			&& strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0)
-		{
-			lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
-			return lumpnumcache[lumpnumcacheindex].lumpnum;
-		}
-	}
+	// Check the lumpnumcache first.
+	lumpnum_t cachenum = CheckLumpInCache(name, false);
+	if (cachenum != LUMPERROR)
+		return cachenum;
 
 	// scan wad files backwards so patch lump files take precedence
 	for (i = numwadfiles - 1; i >= 0; i--)
@@ -1470,12 +1562,11 @@ lumpnum_t W_CheckNumForName(const char *name)
 	else
 	{
 		// Update the cache.
-		lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
-		memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
-		strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8);
-		lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check;
+		lumpnum_t lumpnum = (i << 16) + check;
+
+		AddLumpToCache(lumpnum, name, false);
 
-		return lumpnumcache[lumpnumcacheindex].lumpnum;
+		return lumpnum;
 	}
 }
 
@@ -1493,16 +1584,10 @@ lumpnum_t W_CheckNumForLongName(const char *name)
 	if (!*name) // some doofus gave us an empty string?
 		return LUMPERROR;
 
-	// Check the lumpnumcache first. Loop backwards so that we check
-	// most recent entries first
-	for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
-	{
-		if (strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
-		{
-			lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
-			return lumpnumcache[lumpnumcacheindex].lumpnum;
-		}
-	}
+	// Check the lumpnumcache first.
+	lumpnum_t cachenum = CheckLumpInCache(name, true);
+	if (cachenum != LUMPERROR)
+		return cachenum;
 
 	// scan wad files backwards so patch lump files take precedence
 	for (i = numwadfiles - 1; i >= 0; i--)
@@ -1515,16 +1600,12 @@ lumpnum_t W_CheckNumForLongName(const char *name)
 	if (check == INT16_MAX) return LUMPERROR;
 	else
 	{
-		if (strlen(name) < 32)
-		{
-			// Update the cache.
-			lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
-			memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
-			strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32);
-			lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
-		}
+		// Update the cache.
+		lumpnum_t lumpnum = (i << 16) + check;
+
+		AddLumpToCache(lumpnum, name, true);
 
-		return (i << 16) + check;
+		return lumpnum;
 	}
 }
 
@@ -1606,6 +1687,159 @@ lumpnum_t W_GetNumForLongName(const char *name)
 	return i;
 }
 
+//
+// Same as W_CheckNumForNamePwad, but handles namespaces.
+//
+static UINT16 W_CheckNumForPatchNamePwad(const char *name, UINT16 wad, boolean longname)
+{
+	UINT16 i, start, end;
+	static char uname[8 + 1] = { 0 };
+	UINT32 hash = 0;
+	lumpinfo_t *lump_p;
+
+	if (!TestValidLump(wad,0))
+		return INT16_MAX;
+
+	if (!longname)
+	{
+		strlcpy(uname, name, sizeof uname);
+		strupr(uname);
+		hash = quickncasehash(uname, 8);
+	}
+
+	// SRB2 doesn't have a specific namespace for graphics, which means someone can do weird things
+	// like placing graphics inside a namespace it doesn't make sense for them to be in, like Sounds/ or SOC/
+	// So for now, this checks for lumps OUTSIDE of the flats namespace.
+	// When this situation changes, change the loops below to check for lumps INSIDE the namespaces to look in.
+	// TODO: cache namespace lump IDs
+	if (W_FileHasFolders(wadfiles[wad]))
+	{
+		start = W_CheckNumForFolderStartPK3("Flats/", wad, 0);
+		end = W_CheckNumForFolderEndPK3("Flats/", wad, start);
+	}
+	else
+	{
+		start = W_CheckNumForMarkerStartPwad("F_START", wad, 0);
+		end = W_CheckNumForNamePwad("F_END", wad, start);
+		if (end != INT16_MAX)
+			end++;
+	}
+
+	lump_p = wadfiles[wad]->lumpinfo;
+
+	if (start == INT16_MAX)
+		start = wadfiles[wad]->numlumps;
+
+	for (i = 0; i < start; i++, lump_p++)
+	{
+		if ((!longname && lump_p->hash == hash && !strncmp(lump_p->name, uname, sizeof(uname) - 1))
+		|| (longname && stricmp(lump_p->longname, name) == 0))
+			return i;
+	}
+
+	if (end != INT16_MAX && start < end)
+	{
+		lump_p = wadfiles[wad]->lumpinfo + end;
+
+		for (i = end; i < wadfiles[wad]->numlumps; i++, lump_p++)
+		{
+			if ((!longname && lump_p->hash == hash && !strncmp(lump_p->name, uname, sizeof(uname) - 1))
+			|| (longname && stricmp(lump_p->longname, name) == 0))
+				return i;
+		}
+	}
+
+	// not found.
+	return INT16_MAX;
+}
+
+//
+// W_CheckNumForPatchNameInternal
+// Gets a lump number out of a patch name. Returns LUMPERROR if name not found.
+//
+static lumpnum_t W_CheckNumForPatchNameInternal(const char *name, boolean longname)
+{
+	INT32 i;
+	lumpnum_t check = INT16_MAX;
+
+	if (!*name) // some doofus gave us an empty string?
+		return LUMPERROR;
+
+	// Check the lumpnumcache first.
+	lumpnum_t cachenum = CheckLumpInCache(name, longname);
+	if (cachenum != LUMPERROR)
+		return cachenum;
+
+	// scan wad files backwards so patch lump files take precedence
+	for (i = numwadfiles - 1; i >= 0; i--)
+	{
+		check = W_CheckNumForPatchNamePwad(name,(UINT16)i,longname);
+		if (check != INT16_MAX)
+			break; //found it
+	}
+
+	if (check == INT16_MAX) return LUMPERROR;
+	else
+	{
+		// Update the cache.
+		lumpnum_t lumpnum = (i << 16) + check;
+
+		AddLumpToCache(lumpnum, name, longname);
+
+		return lumpnum;
+	}
+}
+
+//
+// W_CheckNumForPatchName
+// Wrapper for W_CheckNumForPatchNameInternal(name, false). Returns LUMPERROR if name not found.
+//
+lumpnum_t W_CheckNumForPatchName(const char *name)
+{
+	return W_CheckNumForPatchNameInternal(name, false);
+}
+
+//
+// Like W_CheckNumForPatchName, but can find entries with long names.
+// Wrapper for W_CheckNumForPatchNameInternal(name, true). Returns LUMPERROR if name not found.
+//
+lumpnum_t W_CheckNumForLongPatchName(const char *name)
+{
+	return W_CheckNumForPatchNameInternal(name, true);
+}
+
+//
+// W_GetNumForPatchName
+//
+// Calls W_CheckNumForPatchName, but bombs out if not found.
+//
+lumpnum_t W_GetNumForPatchName(const char *name)
+{
+	lumpnum_t i;
+
+	i = W_CheckNumForPatchName(name);
+
+	if (i == LUMPERROR)
+		I_Error("W_CheckNumForPatchName: %s not found!\n", name);
+
+	return i;
+}
+
+//
+// Like W_GetNumForPatchName, but can find entries with long names
+//
+lumpnum_t W_GetNumForLongPatchName(const char *name)
+{
+	lumpnum_t i;
+
+	i = W_CheckNumForLongPatchName(name);
+
+	if (i == LUMPERROR)
+		I_Error("W_GetNumForLongPatchName: %s not found!\n", name);
+
+	return i;
+}
+
 //
 // W_CheckNumForNameInBlock
 // Checks only in blocks from blockstart lump to blockend lump
@@ -2250,10 +2484,10 @@ void *W_CachePatchName(const char *name, INT32 tag)
 {
 	lumpnum_t num;
 
-	num = W_CheckNumForName(name);
+	num = W_CheckNumForPatchName(name);
 
 	if (num == LUMPERROR)
-		return W_CachePatchNum(W_GetNumForName("MISSING"), tag);
+		return W_CachePatchNum(W_GetNumForPatchName("MISSING"), tag);
 	return W_CachePatchNum(num, tag);
 }
 
@@ -2261,10 +2495,10 @@ void *W_CachePatchLongName(const char *name, INT32 tag)
 {
 	lumpnum_t num;
 
-	num = W_CheckNumForLongName(name);
+	num = W_CheckNumForLongPatchName(name);
 
 	if (num == LUMPERROR)
-		return W_CachePatchNum(W_GetNumForLongName("MISSING"), tag);
+		return W_CachePatchNum(W_GetNumForLongPatchName("MISSING"), tag);
 	return W_CachePatchNum(num, tag);
 }
 #ifndef NOMD5
diff --git a/src/w_wad.h b/src/w_wad.h
index e043e4d62c82f061ce505c4ce6b6a2298d48a4ec..3dcb9b6e8bbc6ee11669f473e9395a0006f84db0 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -180,6 +180,8 @@ UINT16 W_CheckNumForMarkerStartPwad(const char *name, UINT16 wad, UINT16 startlu
 UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
 UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
 UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump);
+char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump);
+char *W_GetLumpFolderNamePK3(UINT16 wad, UINT16 lump);
 
 void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps);
 void W_GetFolderLumps(const char *name, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps);
@@ -191,6 +193,12 @@ lumpnum_t W_CheckNumForName(const char *name);
 lumpnum_t W_CheckNumForLongName(const char *name);
 lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR
 lumpnum_t W_GetNumForLongName(const char *name);
+
+lumpnum_t W_CheckNumForPatchName(const char *name);
+lumpnum_t W_CheckNumForLongPatchName(const char *name);
+lumpnum_t W_GetNumForPatchName(const char *name); // like W_CheckNumForPatchName but I_Error on LUMPERROR
+lumpnum_t W_GetNumForLongPatchName(const char *name);
+
 lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend);
 UINT8 W_LumpExists(const char *name); // Lua uses this.
 
diff --git a/thirdparty/00-SDL-Mixer-X-2.6.0-DISABLE_INSTALL.patch b/thirdparty/00-SDL-Mixer-X-2.6.0-DISABLE_INSTALL.patch
new file mode 100644
index 0000000000000000000000000000000000000000..0e7f55f1b282300bbdb6d21a8abd67373fd45828
--- /dev/null
+++ b/thirdparty/00-SDL-Mixer-X-2.6.0-DISABLE_INSTALL.patch
@@ -0,0 +1,26 @@
+--- a/CMakeLists.txt	2023-11-22 22:42:53.000000000 -0500
++++ b/CMakeLists.txt	2024-02-15 18:46:57.852076200 -0500
+@@ -45,6 +45,7 @@
+ 
+     option(SDL_MIXER_X_STATIC   "Build static library of SDL Mixer X" ${SDL_MIXER_X_STATIC_ENABLED_BY_DEFAULT})
+     option(SDL_MIXER_X_SHARED   "Build shared library of SDL Mixer X" ${SDL_MIXER_X_SHARED_ENABLED_BY_DEFAULT})
++     option(SDL_MIXER_X_DISABLE_INSTALL   "Disable install of SDL Mixer X" OFF)
+ else()
+     set(SDL_MIXER_X_STATIC ON)
+     set(SDL_MIXER_X_SHARED OFF)
+@@ -475,6 +476,7 @@
+     add_subdirectory(examples)
+ endif()
+ 
++if(NOT SDL_MIXER_X_DISABLE_INSTALL)
+ if(SDL_MIXER_X_STATIC AND NOT BUILD_AS_VB6_BINDING)
+     install(TARGETS SDL2_mixer_ext_Static
+             EXPORT SDL2MixerExtStaticTargets
+@@ -500,6 +502,7 @@
+             NAMESPACE SDL2_mixer_ext::
+             DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/SDL2_mixer_ext")
+ endif()
++endif()
+ 
+ 
+ if(BUILD_AS_VB6_BINDING)
diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt
index 19aa22c9b7a17613910dbdc9f28717e16e604986..5114cbe2c81432173409cce5a113ea9305b5b23b 100644
--- a/thirdparty/CMakeLists.txt
+++ b/thirdparty/CMakeLists.txt
@@ -1,23 +1,2 @@
-macro(export)
-endmacro()
 
-if(SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
-	set(SRB2_INTERNAL_LIBRARY_TYPE SHARED)
-	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES OFF)
-else()
-	set(SRB2_INTERNAL_LIBRARY_TYPE STATIC)
-	set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES ON)
-endif()
-
-if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
-	include("cpm-sdl2.cmake")
-	include("cpm-sdl2-mixer.cmake")
-	include("cpm-zlib.cmake")
-	include("cpm-png.cmake")
-	include("cpm-curl.cmake")
-	include("cpm-openmpt.cmake")
-endif()
-
-if("${SRB2_CONFIG_USE_GME}")
-	include("cpm-libgme.cmake")
-endif()
+include("Ccache.cmake")
diff --git a/thirdparty/Ccache.cmake b/thirdparty/Ccache.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6ca0d9fa0615d8cf091992ed84bec7b4fef09144
--- /dev/null
+++ b/thirdparty/Ccache.cmake
@@ -0,0 +1,15 @@
+# Enable CCache
+# (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options)
+if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows)
+	option(USE_CCACHE "Enable ccache support" OFF)
+
+	if(USE_CCACHE)
+		find_program(CCACHE_TOOL_PATH ccache)
+		if(CCACHE_TOOL_PATH)
+			set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
+			set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
+		else()
+			message(WARNING "USE_CCACHE was set but ccache is not found (set CCACHE_TOOL_PATH)")
+		endif()
+	endif()
+endif()
\ No newline at end of file
diff --git a/thirdparty/cpm-libgme.cmake b/thirdparty/cpm-libgme.cmake
deleted file mode 100644
index f15bc3b31cb23ed7663ed950c14c1d6a0dc36567..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-libgme.cmake
+++ /dev/null
@@ -1,16 +0,0 @@
-CPMAddPackage(
-	NAME libgme
-	VERSION 0.6.3
-	URL "https://bitbucket.org/mpyne/game-music-emu/get/e76bdc0cb916e79aa540290e6edd0c445879d3ba.zip"
-	EXCLUDE_FROM_ALL ON
-	OPTIONS
-		"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"ENABLE_UBSAN OFF"
-		"GME_YM2612_EMU MAME"
-)
-
-if(libgme_ADDED)
-	target_compile_features(gme PRIVATE cxx_std_11)
-	# libgme's CMakeLists.txt already links this
-	#target_link_libraries(gme PRIVATE ZLIB::ZLIB)
-endif()
diff --git a/thirdparty/cpm-png.cmake b/thirdparty/cpm-png.cmake
deleted file mode 100644
index f16ac037b0cc9c077f3ef315b67b430e68cf9b40..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-png.cmake
+++ /dev/null
@@ -1,69 +0,0 @@
-CPMAddPackage(
-	NAME png
-	VERSION 1.6.38
-	URL "https://github.com/glennrp/libpng/archive/refs/tags/v1.6.38.zip"
-	# png cmake build is broken on msys/mingw32
-	DOWNLOAD_ONLY YES
-)
-
-if(png_ADDED)
-	# Since png's cmake build is broken, we're going to create a target manually
-	set(
-		PNG_SOURCES
-		png.h
-		pngconf.h
-		pngpriv.h
-		pngdebug.h
-		pnginfo.h
-		pngstruct.h
-		png.c
-		pngerror.c
-		pngget.c
-		pngmem.c
-		pngpread.c
-		pngread.c
-		pngrio.c
-		pngrtran.c
-		pngrutil.c
-		pngset.c
-		pngtrans.c
-		pngwio.c
-		pngwrite.c
-		pngwtran.c
-		pngwutil.c
-	)
-	list(TRANSFORM PNG_SOURCES PREPEND "${png_SOURCE_DIR}/")
-
-	add_custom_command(
-		OUTPUT "${png_BINARY_DIR}/include/png.h" "${png_BINARY_DIR}/include/pngconf.h"
-		COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h" "${png_BINARY_DIR}/include"
-		DEPENDS "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h"
-		VERBATIM
-	)
-	add_custom_command(
-		OUTPUT "${png_BINARY_DIR}/include/pnglibconf.h"
-		COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt" "${png_BINARY_DIR}/include/pnglibconf.h"
-		DEPENDS "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt"
-		VERBATIM
-	)
-	list(
-		APPEND PNG_SOURCES
-		"${png_BINARY_DIR}/include/png.h"
-		"${png_BINARY_DIR}/include/pngconf.h"
-		"${png_BINARY_DIR}/include/pnglibconf.h"
-	)
-	add_library(png "${SRB2_INTERNAL_LIBRARY_TYPE}" ${PNG_SOURCES})
-
-	# Disable ARM NEON since having it automatic breaks libpng external build on clang for some reason
-	target_compile_definitions(png PRIVATE -DPNG_ARM_NEON_OPT=0)
-
-	# The png includes need to be available to consumers
-	target_include_directories(png PUBLIC "${png_BINARY_DIR}/include")
-
-	# ... and these also need to be present only for png build
-	target_include_directories(png PRIVATE "${ZLIB_SOURCE_DIR}")
-	target_include_directories(png PRIVATE "${ZLIB_BINARY_DIR}")
-	target_include_directories(png PRIVATE "${png_BINARY_DIR}")
-	target_link_libraries(png PRIVATE ZLIB::ZLIB)
-	add_library(PNG::PNG ALIAS png)
-endif()
diff --git a/thirdparty/cpm-sdl2-mixer.cmake b/thirdparty/cpm-sdl2-mixer.cmake
deleted file mode 100644
index b7dfeae0d3eab254651f0c5e6e69e7af0626012e..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-sdl2-mixer.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-CPMAddPackage(
-	NAME SDL2_mixer
-	VERSION 2.6.2
-	URL "https://github.com/libsdl-org/SDL_mixer/archive/refs/tags/release-2.6.2.zip"
-	EXCLUDE_FROM_ALL ON
-	OPTIONS
-		"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL2MIXER_INSTALL OFF"
-		"SDL2MIXER_DEPS_SHARED OFF"
-		"SDL2MIXER_SAMPLES OFF"
-		"SDL2MIXER_VENDORED ON"
-		"SDL2MIXER_FLAC ON"
-		"SDL2MIXER_FLAC_LIBFLAC OFF"
-		"SDL2MIXER_FLAC_DRFLAC ON"
-		"SDL2MIXER_MOD OFF"
-		"SDL2MIXER_MP3 ON"
-		"SDL2MIXER_MP3_DRMP3 ON"
-		"SDL2MIXER_MIDI ON"
-		"SDL2MIXER_OPUS OFF"
-		"SDL2MIXER_VORBIS STB"
-		"SDL2MIXER_WAVE ON"
-)
diff --git a/thirdparty/cpm-sdl2.cmake b/thirdparty/cpm-sdl2.cmake
deleted file mode 100644
index 0bb404e4c90fc6e9e5ff79314f0703a1aa4ae9a6..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-sdl2.cmake
+++ /dev/null
@@ -1,28 +0,0 @@
-set(
-	internal_sdl2_options
-
-		"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
-		"SDL_TEST OFF"
-		"SDL2_DISABLE_INSTALL ON"
-)
-
-if(${CMAKE_SYSTEM} MATCHES Windows)
-	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
-endif()
-if(${CMAKE_SYSTEM} MATCHES Darwin)
-	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
-endif()
-if(${CMAKE_SYSTEM} MATCHES Linux)
-	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN ON")
-endif()
-
-CPMAddPackage(
-	NAME SDL2
-	VERSION 2.28.5
-	GITHUB_REPOSITORY "libsdl-org/SDL"
-	GIT_TAG release-2.28.5
-	EXCLUDE_FROM_ALL ON
-	OPTIONS ${internal_sdl2_options}
-)
diff --git a/thirdparty/cpm-zlib.cmake b/thirdparty/cpm-zlib.cmake
deleted file mode 100644
index f0a2c33aee8c483d82b4ab26e1d0be2143fd9e16..0000000000000000000000000000000000000000
--- a/thirdparty/cpm-zlib.cmake
+++ /dev/null
@@ -1,18 +0,0 @@
-CPMAddPackage(
-	NAME zlib
-	VERSION 1.3.1
-	GITHUB_REPOSITORY "madler/zlib"
-	GIT_TAG v1.3.1
-	EXCLUDE_FROM_ALL
-	OPTIONS
-		"ZLIB_BUILD_EXAMPLES OFF"
-)
-
-if(zlib_ADDED)
-	if(SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
-		add_library(ZLIB::ZLIB ALIAS zlib)
-	endif()
-	if(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES)
-		add_library(ZLIB::ZLIB ALIAS zlibstatic)
-	endif()
-endif()
diff --git a/thirdparty/cpm-curl.cmake b/thirdparty/curl.cmake
similarity index 55%
rename from thirdparty/cpm-curl.cmake
rename to thirdparty/curl.cmake
index 3d8c6e61d46dee6f06f4e6d69beb09d1605f6584..5c3aa26e35882d64ca8a6cf99517d28e9fc56dcc 100644
--- a/thirdparty/cpm-curl.cmake
+++ b/thirdparty/curl.cmake
@@ -1,8 +1,16 @@
+if(TARGET CURL::libcurl)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'CURL::libcurl'")
+
+set(CURL_ENABLE_EXPORT_TARGET OFF CACHE BOOL "" FORCE)
+
 set(
 	internal_curl_options
 
 	"BUILD_CURL_EXE OFF"
-	"BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
+	"BUILD_SHARED_LIBS OFF"
 	"CURL_DISABLE_TESTS ON"
 	"HTTP_ONLY ON"
 	"CURL_DISABLE_CRYPTO_AUTH ON"
@@ -26,10 +34,25 @@ if(${CMAKE_SYSTEM} MATCHES Linux)
 	list(APPEND internal_curl_options "CURL_USE_OPENSSL ON")
 endif()
 
-CPMAddPackage(
-	NAME curl
-	VERSION 7.86.0
-	URL "https://github.com/curl/curl/archive/refs/tags/curl-7_86_0.zip"
-	EXCLUDE_FROM_ALL ON
-	OPTIONS ${internal_curl_options}
-)
+include(FetchContent)
+
+if (CURL_USE_THIRDPARTY)
+	FetchContent_Declare(
+		curl
+		VERSION 7.88.1
+		GITHUB_REPOSITORY "curl/curl"
+		GIT_TAG curl-7_88_1
+		EXCLUDE_FROM_ALL ON
+		OPTIONS ${internal_curl_options}
+	)
+else()
+	FetchContent_Declare(
+		curl
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/curl/"
+		EXCLUDE_FROM_ALL ON
+		OPTIONS ${internal_curl_options}
+	)
+endif()
+
+FetchContent_MakeAvailable(curl)
+
diff --git a/thirdparty/libapng.cmake b/thirdparty/libapng.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f4bc50ff1d301b58bf91c44bfe40986c5c987654
--- /dev/null
+++ b/thirdparty/libapng.cmake
@@ -0,0 +1,38 @@
+if(TARGET libapng_static)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'libapng_static'")
+
+set(PNG_SHARED OFF CACHE BOOL "" FORCE)
+set(PNG_BUILD_ZLIB ON CACHE BOOL "" FORCE)
+
+include(FetchContent)
+
+	FetchContent_Declare(
+		libapng-local
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/libapng/"
+		EXCLUDE_FROM_ALL ON
+		DOWNLOAD_ONLY YES
+		OPTION
+			"PNG_SHARED OFF"
+			"PNG_EXECUTABLES OFF"
+			"PNG_TESTS OFF"
+			"PNG_BUILD_ZLIB ON"
+	)
+
+FetchContent_MakeAvailable(libapng-local)
+
+#add_custom_command(
+#OUTPUT ${libapng-local_BINARY_DIR}/CMakeLists.txt
+#COMMAND ${CMAKE_COMMAND}
+#  -Din_file:FILEPATH=${libapng-locall_SOURCE_DIR}/CMakeLists.txt
+#  -Dpatch_file:FILEPATH=${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/00-libapng-ZLIB.patch
+#  -Dout_file:FILEPATH=${libapng-local_BINARY_DIR}/CMakeLists.txt
+#  -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/PatchFile.cmake
+#DEPENDS ${libapng-local_SOURCE_DIR}/CMakeLists.txt
+#)
+
+set(libapng_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/libapng" "${libapng_BINARY_DIR}" CACHE PATH "" FORCE)
+
+set(libapng_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/libapng/png.h" "${CMAKE_CURRENT_SOURCE_DIR}/libapng/pngconf.h" CACHE PATH "" FORCE)
diff --git a/thirdparty/cpm-openmpt.cmake b/thirdparty/libopenmpt.cmake
similarity index 82%
rename from thirdparty/cpm-openmpt.cmake
rename to thirdparty/libopenmpt.cmake
index 01f7ff75f64d915799e432f2923a2c7e8c344466..256b4c406b99b73bf96e9488316b1093515f65c9 100644
--- a/thirdparty/cpm-openmpt.cmake
+++ b/thirdparty/libopenmpt.cmake
@@ -1,13 +1,33 @@
-CPMAddPackage(
-	NAME openmpt
-	VERSION 0.4.30
-	URL "https://github.com/OpenMPT/openmpt/archive/refs/tags/libopenmpt-0.4.30.zip"
-	DOWNLOAD_ONLY ON
-)
+if(TARGET libopenmpt)
+    #return()
+endif()
+
+message(STATUS "Third-party: creating target 'libopenmpt'")
+
+
+include(FetchContent)
+
+if (libopenmpt_USE_THIRDPARTY)
+	FetchContent_Declare(
+		libopenmpt-local
+		GITHUB_REPOSITORY openmpt
+		GIT_TAG libopenmpt-0.4.38
+		version 0.4.38
+		EXCLUDE_FROM_ALL ON
+	)
+else()
+	FetchContent_Declare(
+		libopenmpt-local
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/libopenmpt/"
+		EXCLUDE_FROM_ALL ON
+	)
+endif()
+
+FetchContent_MakeAvailable(libopenmpt)
 
-if(openmpt_ADDED)
+if(aaaa-libopenmpt-local_ADDED)
 	set(
-		openmpt_SOURCES
+		libopenmpt-local_SOURCES
 
 		# minimp3
 		# -DMPT_WITH_MINIMP3
@@ -264,26 +284,26 @@ if(openmpt_ADDED)
 		libopenmpt/libopenmpt_impl.cpp
 		libopenmpt/libopenmpt_ext_impl.cpp
 	)
-	list(TRANSFORM openmpt_SOURCES PREPEND "${openmpt_SOURCE_DIR}/")
+	list(TRANSFORM libopenmpt-local_SOURCES PREPEND "${libopenmpt-local_SOURCE_DIR}/")
 
 	# -DLIBOPENMPT_BUILD
 	configure_file("openmpt_svn_version.h" "svn_version.h")
-	add_library(openmpt "${SRB2_INTERNAL_LIBRARY_TYPE}" ${openmpt_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/svn_version.h)
+	add_library(libopenmpt STATIC ${libopenmpt-local_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/svn_version.h)
 	if("${CMAKE_C_COMPILER_ID}" STREQUAL GNU OR "${CMAKE_C_COMPILER_ID}" STREQUAL Clang OR "${CMAKE_C_COMPILER_ID}" STREQUAL AppleClang)
-		target_compile_options(openmpt PRIVATE "-g0")
+		target_compile_options(libopenmpt PRIVATE "-g0")
 	endif()
 	if("${CMAKE_SYSTEM_NAME}" STREQUAL Windows AND "${CMAKE_C_COMPILER_ID}" STREQUAL MSVC)
-		target_link_libraries(openmpt PRIVATE Rpcrt4)
+		target_link_libraries(libopenmpt PRIVATE Rpcrt4)
 	endif()
-	target_compile_features(openmpt PRIVATE cxx_std_11)
-	target_compile_definitions(openmpt PRIVATE -DLIBOPENMPT_BUILD)
+	target_compile_features(libopenmpt PRIVATE cxx_std_11)
+	target_compile_definitions(libopenmpt PRIVATE -DLIBOPENMPT_BUILD)
 
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/common")
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/src")
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/include")
-	target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}")
-	target_include_directories(openmpt PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}/common")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}/src")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}/include")
+	target_include_directories(libopenmpt PRIVATE "${libopenmpt-local_SOURCE_DIR}")
+	target_include_directories(libopenmpt PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
 
 	# I wish this wasn't necessary, but it is
-	target_include_directories(openmpt PUBLIC "${openmpt_SOURCE_DIR}")
+	target_include_directories(libopenmpt PUBLIC "${libopenmpt-local_SOURCE_DIR}")
 endif()
diff --git a/thirdparty/libpng-1.6.40-apng.patch b/thirdparty/libpng-1.6.40-apng.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c5b870004ad2f7a82df6bbbc061c24cc8f5a5393
--- /dev/null
+++ b/thirdparty/libpng-1.6.40-apng.patch
@@ -0,0 +1,1728 @@
+diff -Naru libpng-1.6.40.org/png.h libpng-1.6.40/png.h
+--- libpng-1.6.40.org/png.h	2023-09-10 11:12:23.044481879 +0900
++++ libpng-1.6.40/png.h	2023-09-10 11:08:58.964075833 +0900
+@@ -330,6 +330,10 @@
+ #   include "pnglibconf.h"
+ #endif
+ 
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ #  include "pngconf.h"
+@@ -425,6 +429,17 @@
+  * See pngconf.h for base types that vary by machine/system
+  */
+ 
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE        0x00U
++#define PNG_DISPOSE_OP_BACKGROUND  0x01U
++#define PNG_DISPOSE_OP_PREVIOUS    0x02U
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE        0x00U
++#define PNG_BLEND_OP_OVER          0x01U
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+  * do not agree upon the version number.
+  */
+@@ -746,6 +761,10 @@
+ #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
+ #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
+ #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x20000U
++#define PNG_INFO_fcTL 0x40000U
++#endif
+ 
+ /* This is used for the transformation routines, as some of them
+  * change these values for the row.  It also should enable using
+@@ -783,6 +802,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++    png_uint_32));
++#endif
+ 
+ /* The following callback receives png_uint_32 row_number, int pass for the
+  * png_bytep data of the row.  When transforming an interlaced image the
+@@ -3226,6 +3249,74 @@
+ /*******************************************************************************
+  *  END OF HARDWARE AND SOFTWARE OPTIONS
+  ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
++   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
++   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++   png_infop info_ptr));
++
++PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++   png_infop info_ptr));
++
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
++   png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
++   png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
++   png_byte *blend_op));
++
++PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
++   png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++   png_byte blend_op));
++
++PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
++   (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
++   (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
++   png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++   png_progressive_frame_ptr frame_info_fn,
++   png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
++   png_infop info_ptr, png_bytepp row_pointers,
++   png_uint_32 width, png_uint_32 height,
++   png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++   png_byte blend_op));
++
++PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
++   png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+ 
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+  * defs, and in scripts/symbols.def.
+@@ -3235,7 +3326,11 @@
+  * one to use is one more than this.)
+  */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++  PNG_EXPORT_LAST_ORDINAL(269);
++#else
+   PNG_EXPORT_LAST_ORDINAL(249);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+ 
+ #ifdef __cplusplus
+diff -Naru libpng-1.6.40.org/pngget.c libpng-1.6.40/pngget.c
+--- libpng-1.6.40.org/pngget.c	2023-09-10 11:09:32.954139030 +0900
++++ libpng-1.6.40/pngget.c	2023-09-10 11:08:58.922075757 +0900
+@@ -1257,4 +1257,166 @@
+ #  endif
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++             png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++    png_debug1(1, "in %s retrieval function", "acTL");
++
++    if (png_ptr != NULL && info_ptr != NULL &&
++        (info_ptr->valid & PNG_INFO_acTL) &&
++        num_frames != NULL && num_plays != NULL)
++    {
++        *num_frames = info_ptr->num_frames;
++        *num_plays = info_ptr->num_plays;
++        return (1);
++    }
++
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_num_frames()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->num_frames);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_num_plays()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->num_plays);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++             png_uint_32 *width, png_uint_32 *height,
++             png_uint_32 *x_offset, png_uint_32 *y_offset,
++             png_uint_16 *delay_num, png_uint_16 *delay_den,
++             png_byte *dispose_op, png_byte *blend_op)
++{
++    png_debug1(1, "in %s retrieval function", "fcTL");
++
++    if (png_ptr != NULL && info_ptr != NULL &&
++        (info_ptr->valid & PNG_INFO_fcTL) &&
++        width != NULL && height != NULL &&
++        x_offset != NULL && y_offset != NULL &&
++        delay_num != NULL && delay_den != NULL &&
++        dispose_op != NULL && blend_op != NULL)
++    {
++        *width = info_ptr->next_frame_width;
++        *height = info_ptr->next_frame_height;
++        *x_offset = info_ptr->next_frame_x_offset;
++        *y_offset = info_ptr->next_frame_y_offset;
++        *delay_num = info_ptr->next_frame_delay_num;
++        *delay_den = info_ptr->next_frame_delay_den;
++        *dispose_op = info_ptr->next_frame_dispose_op;
++        *blend_op = info_ptr->next_frame_blend_op;
++        return (1);
++    }
++
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_width()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_width);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_height()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_height);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_x_offset()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_x_offset);
++    return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_y_offset()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_y_offset);
++    return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_delay_num()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_delay_num);
++    return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_delay_den()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_delay_den);
++    return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_dispose_op()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_dispose_op);
++    return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_get_next_frame_blend_op()");
++
++    if (png_ptr != NULL && info_ptr != NULL)
++        return (info_ptr->next_frame_blend_op);
++    return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_first_frame_is_hidden()");
++
++    if (png_ptr != NULL)
++       return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++    PNG_UNUSED(info_ptr)
++
++    return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* READ || WRITE */
+diff -Naru libpng-1.6.40.org/pnginfo.h libpng-1.6.40/pnginfo.h
+--- libpng-1.6.40.org/pnginfo.h	2022-11-24 08:37:51.507052183 +0900
++++ libpng-1.6.40/pnginfo.h	2023-09-10 11:08:58.922075757 +0900
+@@ -263,5 +263,18 @@
+    png_bytepp row_pointers;        /* the image bits */
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++   png_uint_32 num_frames; /* including default image */
++   png_uint_32 num_plays;
++   png_uint_32 next_frame_width;
++   png_uint_32 next_frame_height;
++   png_uint_32 next_frame_x_offset;
++   png_uint_32 next_frame_y_offset;
++   png_uint_16 next_frame_delay_num;
++   png_uint_16 next_frame_delay_den;
++   png_byte next_frame_dispose_op;
++   png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Naru libpng-1.6.40.org/pngpread.c libpng-1.6.40/pngpread.c
+--- libpng-1.6.40.org/pngpread.c	2022-11-24 08:37:51.507052183 +0900
++++ libpng-1.6.40/pngpread.c	2023-09-10 11:08:58.922075757 +0900
+@@ -195,6 +195,106 @@
+ 
+    chunk_name = png_ptr->chunk_name;
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++   if (png_ptr->num_frames_read > 0 &&
++       png_ptr->num_frames_read < info_ptr->num_frames)
++   {
++      if (chunk_name == png_IDAT)
++      {
++         /* Discard trailing IDATs for the first frame */
++         if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++            png_error(png_ptr, "out of place IDAT");
++
++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++
++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++         return;
++      }
++      else if (chunk_name == png_fdAT)
++      {
++         if (png_ptr->buffer_size < 4)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++
++         png_ensure_sequence_number(png_ptr, 4);
++
++         if (!(png_ptr->mode & PNG_HAVE_fcTL))
++         {
++            /* Discard trailing fdATs for frames other than the first */
++            if (png_ptr->num_frames_read < 2)
++               png_error(png_ptr, "out of place fdAT");
++
++            if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++            {
++               png_push_save_buffer(png_ptr);
++               return;
++            }
++
++            png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++            return;
++         }
++
++         else
++         {
++            /* frame data follows */
++            png_ptr->idat_size = png_ptr->push_length - 4;
++            png_ptr->mode |= PNG_HAVE_IDAT;
++            png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++            return;
++         }
++      }
++
++      else if (chunk_name == png_fcTL)
++      {
++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++
++         png_read_reset(png_ptr);
++         png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++         png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++         if (!(png_ptr->mode & PNG_HAVE_fcTL))
++            png_error(png_ptr, "missing required fcTL chunk");
++
++         png_read_reinit(png_ptr, info_ptr);
++         png_progressive_read_reset(png_ptr);
++
++         if (png_ptr->frame_info_fn != NULL)
++            (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++         return;
++      }
++
++      else
++      {
++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++         {
++            png_push_save_buffer(png_ptr);
++            return;
++         }
++         png_warning(png_ptr, "Skipped (ignored) a chunk "
++                              "between APNG chunks");
++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++         return;
++      }
++
++      return;
++   }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+    if (chunk_name == png_IDAT)
+    {
+       if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+@@ -261,6 +361,9 @@
+ 
+    else if (chunk_name == png_IDAT)
+    {
++#ifdef PNG_READ_APNG_SUPPORTED
++      png_have_info(png_ptr, info_ptr);
++#endif
+       png_ptr->idat_size = png_ptr->push_length;
+       png_ptr->process_mode = PNG_READ_IDAT_MODE;
+       png_push_have_info(png_ptr, info_ptr);
+@@ -406,6 +509,30 @@
+       png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+    }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++   else if (chunk_name == png_acTL)
++   {
++      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++      {
++         png_push_save_buffer(png_ptr);
++         return;
++      }
++
++      png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++   }
++
++   else if (chunk_name == png_fcTL)
++   {
++      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++      {
++         png_push_save_buffer(png_ptr);
++         return;
++      }
++
++      png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++   }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+ 
+    else
+    {
+@@ -539,7 +666,11 @@
+       png_byte chunk_tag[4];
+ 
+       /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++      PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+       PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+       png_push_fill_buffer(png_ptr, chunk_length, 4);
+       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+       png_reset_crc(png_ptr);
+@@ -547,17 +678,64 @@
+       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++      if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++      {
++          if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++          {
++              png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++              if (png_ptr->frame_end_fn != NULL)
++                 (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++              png_ptr->num_frames_read++;
++              return;
++          }
++          else
++          {
++              if (png_ptr->chunk_name == png_IEND)
++                  png_error(png_ptr, "Not enough image data");
++              if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++              {
++                 png_push_save_buffer(png_ptr);
++                 return;
++              }
++              png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++                                   "APNG chunks");
++              png_crc_finish(png_ptr, png_ptr->push_length);
++              png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++              return;
++          }
++      }
++      else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++      if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+       if (png_ptr->chunk_name != png_IDAT)
++#endif
+       {
+          png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ 
+          if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+             png_error(png_ptr, "Not enough compressed data");
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++         if (png_ptr->frame_end_fn != NULL)
++            (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++         png_ptr->num_frames_read++;
++#endif
++
+          return;
+       }
+ 
+       png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++      if (png_ptr->num_frames_read > 0)
++      {
++         png_ensure_sequence_number(png_ptr, 4);
++         png_ptr->idat_size -= 4;
++      }
++#endif
+    }
+ 
+    if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
+@@ -631,6 +809,15 @@
+    if (!(buffer_length > 0) || buffer == NULL)
+       png_error(png_ptr, "No IDAT data (internal error)");
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++   /* If the app is not APNG-aware, decode only the first frame */
++   if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++   {
++     png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++     return;
++   }
++#endif
++
+    /* This routine must process all the data it has been given
+     * before returning, calling the row callback as required to
+     * handle the uncompressed results.
+@@ -1085,6 +1272,18 @@
+    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++   png_progressive_frame_ptr frame_info_fn,
++   png_progressive_frame_ptr frame_end_fn)
++{
++   png_ptr->frame_info_fn = frame_info_fn;
++   png_ptr->frame_end_fn = frame_end_fn;
++   png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Naru libpng-1.6.40.org/pngpriv.h libpng-1.6.40/pngpriv.h
+--- libpng-1.6.40.org/pngpriv.h	2023-09-10 11:09:32.954139030 +0900
++++ libpng-1.6.40/pngpriv.h	2023-09-10 11:08:58.923075759 +0900
+@@ -628,6 +628,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
+ #define PNG_WROTE_eXIf            0x4000U
+ #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL            0x10000U
++#define PNG_HAVE_fcTL            0x20000U
++#endif
+ 
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR                 0x0001U
+@@ -864,6 +868,16 @@
+ #define png_tRNS PNG_U32(116,  82,  78,  83)
+ #define png_zTXt PNG_U32(122,  84,  88, 116)
+ 
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97,  99,  84,  76)
++#define png_fcTL PNG_U32(102,  99,  84,  76)
++#define png_fdAT PNG_U32(102, 100,  65,  84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN       0x0001U
++#define PNG_APNG_APP                 0x0002U
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+  * macro will fail on top-bit-set values because of the sign extension.
+  */
+@@ -1635,6 +1649,47 @@
+     */
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
++   png_uint_32 width, png_uint_32 height,
++   png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den,
++   png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
++   png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
++   png_infop info_ptr),PNG_EMPTY);
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
++   png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
++   png_uint_32 width, png_uint_32 height,
++   png_uint_32 x_offset, png_uint_32 y_offset,
++   png_uint_16 delay_num, png_uint_16 delay_den,
++   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
++   png_const_bytep data, png_size_t length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
++   png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Naru libpng-1.6.40.org/pngread.c libpng-1.6.40/pngread.c
+--- libpng-1.6.40.org/pngread.c	2022-11-24 08:37:51.508052181 +0900
++++ libpng-1.6.40/pngread.c	2023-09-10 11:08:58.923075759 +0900
+@@ -161,6 +161,9 @@
+ 
+       else if (chunk_name == png_IDAT)
+       {
++#ifdef PNG_READ_APNG_SUPPORTED
++         png_have_info(png_ptr, info_ptr);
++#endif
+          png_ptr->idat_size = length;
+          break;
+       }
+@@ -255,6 +258,17 @@
+          png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++      else if (chunk_name == png_acTL)
++         png_handle_acTL(png_ptr, info_ptr, length);
++
++      else if (chunk_name == png_fcTL)
++         png_handle_fcTL(png_ptr, info_ptr, length);
++
++      else if (chunk_name == png_fdAT)
++         png_handle_fdAT(png_ptr, info_ptr, length);
++#endif
++
+       else
+          png_handle_unknown(png_ptr, info_ptr, length,
+              PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -262,6 +276,72 @@
+ }
+ #endif /* SEQUENTIAL_READ */
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++    png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++    png_debug(0, "Reading frame head");
++
++    if (!(png_ptr->mode & PNG_HAVE_acTL))
++        png_error(png_ptr, "attempt to png_read_frame_head() but "
++                           "no acTL present");
++
++    /* do nothing for the main IDAT */
++    if (png_ptr->num_frames_read == 0)
++        return;
++
++    png_read_reset(png_ptr);
++    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++    png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++    have_chunk_after_DAT = 0;
++    for (;;)
++    {
++        png_uint_32 length = png_read_chunk_header(png_ptr);
++
++        if (png_ptr->chunk_name == png_IDAT)
++        {
++            /* discard trailing IDATs for the first frame */
++            if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++                png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++            png_crc_finish(png_ptr, length);
++        }
++
++        else if (png_ptr->chunk_name == png_fcTL)
++        {
++            png_handle_fcTL(png_ptr, info_ptr, length);
++            have_chunk_after_DAT = 1;
++        }
++
++        else if (png_ptr->chunk_name == png_fdAT)
++        {
++            png_ensure_sequence_number(png_ptr, length);
++
++            /* discard trailing fdATs for frames other than the first */
++            if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++                png_crc_finish(png_ptr, length - 4);
++            else if(png_ptr->mode & PNG_HAVE_fcTL)
++            {
++                png_ptr->idat_size = length - 4;
++                png_ptr->mode |= PNG_HAVE_IDAT;
++
++                break;
++            }
++            else
++                png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++        }
++        else
++        {
++            png_warning(png_ptr, "Skipped (ignored) a chunk "
++                                 "between APNG chunks");
++            png_crc_finish(png_ptr, length);
++        }
++    }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Naru libpng-1.6.40.org/pngrutil.c libpng-1.6.40/pngrutil.c
+--- libpng-1.6.40.org/pngrutil.c	2022-11-24 08:37:51.510052177 +0900
++++ libpng-1.6.40/pngrutil.c	2023-09-10 11:08:58.923075759 +0900
+@@ -864,6 +864,11 @@
+    filter_type = buf[11];
+    interlace_type = buf[12];
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++   png_ptr->first_frame_width = width;
++   png_ptr->first_frame_height = height;
++#endif
++
+    /* Set internal variables */
+    png_ptr->width = width;
+    png_ptr->height = height;
+@@ -2858,6 +2863,179 @@
+ }
+ #endif
+ 
++#ifdef PNG_READ_APNG_SUPPORTED
++void /* PRIVATE */
++png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++    png_byte data[8];
++    png_uint_32 num_frames;
++    png_uint_32 num_plays;
++    png_uint_32 didSet;
++
++    png_debug(1, "in png_handle_acTL");
++
++    if (!(png_ptr->mode & PNG_HAVE_IHDR))
++    {
++        png_error(png_ptr, "Missing IHDR before acTL");
++    }
++    else if (png_ptr->mode & PNG_HAVE_IDAT)
++    {
++        png_warning(png_ptr, "Invalid acTL after IDAT skipped");
++        png_crc_finish(png_ptr, length);
++        return;
++    }
++    else if (png_ptr->mode & PNG_HAVE_acTL)
++    {
++        png_warning(png_ptr, "Duplicate acTL skipped");
++        png_crc_finish(png_ptr, length);
++        return;
++    }
++    else if (length != 8)
++    {
++        png_warning(png_ptr, "acTL with invalid length skipped");
++        png_crc_finish(png_ptr, length);
++        return;
++    }
++
++    png_crc_read(png_ptr, data, 8);
++    png_crc_finish(png_ptr, 0);
++
++    num_frames = png_get_uint_31(png_ptr, data);
++    num_plays = png_get_uint_31(png_ptr, data + 4);
++
++    /* the set function will do error checking on num_frames */
++    didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
++    if(didSet)
++        png_ptr->mode |= PNG_HAVE_acTL;
++}
++
++void /* PRIVATE */
++png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++    png_byte data[22];
++    png_uint_32 width;
++    png_uint_32 height;
++    png_uint_32 x_offset;
++    png_uint_32 y_offset;
++    png_uint_16 delay_num;
++    png_uint_16 delay_den;
++    png_byte dispose_op;
++    png_byte blend_op;
++
++    png_debug(1, "in png_handle_fcTL");
++
++    png_ensure_sequence_number(png_ptr, length);
++
++    if (!(png_ptr->mode & PNG_HAVE_IHDR))
++    {
++        png_error(png_ptr, "Missing IHDR before fcTL");
++    }
++    else if (png_ptr->mode & PNG_HAVE_IDAT)
++    {
++        /* for any frames other then the first this message may be misleading,
++        * but correct. PNG_HAVE_IDAT is unset before the frame head is read
++        * i can't think of a better message */
++        png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
++        png_crc_finish(png_ptr, length-4);
++        return;
++    }
++    else if (png_ptr->mode & PNG_HAVE_fcTL)
++    {
++        png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
++        png_crc_finish(png_ptr, length-4);
++        return;
++    }
++    else if (length != 26)
++    {
++        png_warning(png_ptr, "fcTL with invalid length skipped");
++        png_crc_finish(png_ptr, length-4);
++        return;
++    }
++
++    png_crc_read(png_ptr, data, 22);
++    png_crc_finish(png_ptr, 0);
++
++    width = png_get_uint_31(png_ptr, data);
++    height = png_get_uint_31(png_ptr, data + 4);
++    x_offset = png_get_uint_31(png_ptr, data + 8);
++    y_offset = png_get_uint_31(png_ptr, data + 12);
++    delay_num = png_get_uint_16(data + 16);
++    delay_den = png_get_uint_16(data + 18);
++    dispose_op = data[20];
++    blend_op = data[21];
++
++    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
++    {
++        png_warning(png_ptr, "fcTL for the first frame must have zero offset");
++        return;
++    }
++
++    if (info_ptr != NULL)
++    {
++        if (png_ptr->num_frames_read == 0 &&
++            (width != info_ptr->width || height != info_ptr->height))
++        {
++            png_warning(png_ptr, "size in first frame's fcTL must match "
++                               "the size in IHDR");
++            return;
++        }
++
++        /* The set function will do more error checking */
++        png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
++                                x_offset, y_offset, delay_num, delay_den,
++                                dispose_op, blend_op);
++
++        png_read_reinit(png_ptr, info_ptr);
++
++        png_ptr->mode |= PNG_HAVE_fcTL;
++    }
++}
++
++void /* PRIVATE */
++png_have_info(png_structp png_ptr, png_infop info_ptr)
++{
++    if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
++    {
++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++        info_ptr->num_frames++;
++    }
++}
++
++void /* PRIVATE */
++png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++    png_ensure_sequence_number(png_ptr, length);
++
++    /* This function is only called from png_read_end(), png_read_info(),
++    * and png_push_read_chunk() which means that:
++    * - the user doesn't want to read this frame
++    * - or this is an out-of-place fdAT
++    * in either case it is safe to ignore the chunk with a warning */
++    png_warning(png_ptr, "ignoring fdAT chunk");
++    png_crc_finish(png_ptr, length - 4);
++    PNG_UNUSED(info_ptr)
++}
++
++void /* PRIVATE */
++png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
++{
++    png_byte data[4];
++    png_uint_32 sequence_number;
++
++    if (length < 4)
++        png_error(png_ptr, "invalid fcTL or fdAT chunk found");
++
++    png_crc_read(png_ptr, data, 4);
++    sequence_number = png_get_uint_31(png_ptr, data);
++
++    if (sequence_number != png_ptr->next_seq_num)
++        png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
++                           "number found");
++
++    png_ptr->next_seq_num++;
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
+ static int
+@@ -4166,7 +4344,38 @@
+       {
+          uInt avail_in;
+          png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++         png_uint_32 bytes_to_skip = 0;
++
++         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++         {
++            png_crc_finish(png_ptr, bytes_to_skip);
++            bytes_to_skip = 0;
+ 
++            png_ptr->idat_size = png_read_chunk_header(png_ptr);
++            if (png_ptr->num_frames_read == 0)
++            {
++               if (png_ptr->chunk_name != png_IDAT)
++                  png_error(png_ptr, "Not enough image data");
++            }
++            else
++            {
++               if (png_ptr->chunk_name == png_IEND)
++                  png_error(png_ptr, "Not enough image data");
++               if (png_ptr->chunk_name != png_fdAT)
++               {
++                  png_warning(png_ptr, "Skipped (ignored) a chunk "
++                                       "between APNG chunks");
++                  bytes_to_skip = png_ptr->idat_size;
++                  continue;
++               }
++
++               png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++               png_ptr->idat_size -= 4;
++            }
++         }
++#else
+          while (png_ptr->idat_size == 0)
+          {
+             png_crc_finish(png_ptr, 0);
+@@ -4178,7 +4387,7 @@
+             if (png_ptr->chunk_name != png_IDAT)
+                png_error(png_ptr, "Not enough image data");
+          }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+          avail_in = png_ptr->IDAT_read_size;
+ 
+          if (avail_in > png_ptr->idat_size)
+@@ -4241,6 +4450,9 @@
+ 
+          png_ptr->mode |= PNG_AFTER_IDAT;
+          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++         png_ptr->num_frames_read++;
++#endif
+ 
+          if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+             png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4678,4 +4890,80 @@
+ 
+    png_ptr->flags |= PNG_FLAG_ROW_INIT;
+ }
++
++#ifdef PNG_READ_APNG_SUPPORTED
++/* This function is to be called after the main IDAT set has been read and
++ * before a new IDAT is read. It resets some parts of png_ptr
++ * to make them usable by the read functions again */
++void /* PRIVATE */
++png_read_reset(png_structp png_ptr)
++{
++    png_ptr->mode &= ~PNG_HAVE_IDAT;
++    png_ptr->mode &= ~PNG_AFTER_IDAT;
++    png_ptr->row_number = 0;
++    png_ptr->pass = 0;
++}
++
++void /* PRIVATE */
++png_read_reinit(png_structp png_ptr, png_infop info_ptr)
++{
++    png_ptr->width = info_ptr->next_frame_width;
++    png_ptr->height = info_ptr->next_frame_height;
++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
++    png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
++        png_ptr->width);
++    if (png_ptr->prev_row)
++        memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
++}
++
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++/* same as png_read_reset() but for the progressive reader */
++void /* PRIVATE */
++png_progressive_read_reset(png_structp png_ptr)
++{
++#ifdef PNG_READ_INTERLACING_SUPPORTED
++   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
++
++   /* Start of interlace block */
++    const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
++
++    /* Offset to next interlace block */
++    const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
++
++    /* Start of interlace block in the y direction */
++    const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
++
++    /* Offset to next interlace block in the y direction */
++    const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
++
++    if (png_ptr->interlaced)
++    {
++        if (!(png_ptr->transformations & PNG_INTERLACE))
++            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
++                                png_pass_ystart[0]) / png_pass_yinc[0];
++        else
++            png_ptr->num_rows = png_ptr->height;
++
++        png_ptr->iwidth = (png_ptr->width +
++                           png_pass_inc[png_ptr->pass] - 1 -
++                           png_pass_start[png_ptr->pass]) /
++                           png_pass_inc[png_ptr->pass];
++    }
++    else
++#endif /* PNG_READ_INTERLACING_SUPPORTED */
++    {
++        png_ptr->num_rows = png_ptr->height;
++        png_ptr->iwidth = png_ptr->width;
++    }
++    png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
++    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
++        png_error(png_ptr, "inflateReset failed");
++    png_ptr->zstream.avail_in = 0;
++    png_ptr->zstream.next_in = 0;
++    png_ptr->zstream.next_out = png_ptr->row_buf;
++    png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
++        png_ptr->iwidth) + 1;
++}
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
+ #endif /* READ */
+diff -Naru libpng-1.6.40.org/pngset.c libpng-1.6.40/pngset.c
+--- libpng-1.6.40.org/pngset.c	2023-09-10 11:09:32.954139030 +0900
++++ libpng-1.6.40/pngset.c	2023-09-10 11:08:58.932075775 +0900
+@@ -280,6 +280,11 @@
+    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+ 
+    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
++
++#ifdef PNG_APNG_SUPPORTED
++   /* for non-animated png. this may be overwritten from an acTL chunk later */
++   info_ptr->num_frames = 1;
++#endif
+ }
+ 
+ #ifdef PNG_oFFs_SUPPORTED
+@@ -1149,6 +1154,147 @@
+ }
+ #endif /* sPLT */
+ 
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
++    png_uint_32 num_frames, png_uint_32 num_plays)
++{
++    png_debug1(1, "in %s storage function", "acTL");
++
++    if (png_ptr == NULL || info_ptr == NULL)
++    {
++        png_warning(png_ptr,
++                    "Call to png_set_acTL() with NULL png_ptr "
++                    "or info_ptr ignored");
++        return (0);
++    }
++    if (num_frames == 0)
++    {
++        png_warning(png_ptr,
++                    "Ignoring attempt to set acTL with num_frames zero");
++        return (0);
++    }
++    if (num_frames > PNG_UINT_31_MAX)
++    {
++        png_warning(png_ptr,
++                    "Ignoring attempt to set acTL with num_frames > 2^31-1");
++        return (0);
++    }
++    if (num_plays > PNG_UINT_31_MAX)
++    {
++        png_warning(png_ptr,
++                    "Ignoring attempt to set acTL with num_plays "
++                    "> 2^31-1");
++        return (0);
++    }
++
++    info_ptr->num_frames = num_frames;
++    info_ptr->num_plays = num_plays;
++
++    info_ptr->valid |= PNG_INFO_acTL;
++
++    return (1);
++}
++
++/* delay_num and delay_den can hold any 16-bit values including zero */
++png_uint_32 PNGAPI
++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++    png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den,
++    png_byte dispose_op, png_byte blend_op)
++{
++    png_debug1(1, "in %s storage function", "fcTL");
++
++    if (png_ptr == NULL || info_ptr == NULL)
++    {
++        png_warning(png_ptr,
++                    "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
++                    "ignored");
++        return (0);
++    }
++
++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++                             delay_num, delay_den, dispose_op, blend_op);
++
++    if (blend_op == PNG_BLEND_OP_OVER)
++    {
++        if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
++            !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
++        {
++          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
++                               "and wasteful for opaque images, ignored");
++          blend_op = PNG_BLEND_OP_SOURCE;
++        }
++    }
++
++    info_ptr->next_frame_width = width;
++    info_ptr->next_frame_height = height;
++    info_ptr->next_frame_x_offset = x_offset;
++    info_ptr->next_frame_y_offset = y_offset;
++    info_ptr->next_frame_delay_num = delay_num;
++    info_ptr->next_frame_delay_den = delay_den;
++    info_ptr->next_frame_dispose_op = dispose_op;
++    info_ptr->next_frame_blend_op = blend_op;
++
++    info_ptr->valid |= PNG_INFO_fcTL;
++
++    return (1);
++}
++
++void /* PRIVATE */
++png_ensure_fcTL_is_valid(png_structp png_ptr,
++    png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den,
++    png_byte dispose_op, png_byte blend_op)
++{
++    if (width == 0 || width > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
++    if (height == 0 || height > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
++    if (x_offset > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
++    if (y_offset > PNG_UINT_31_MAX)
++        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
++    if (width + x_offset > png_ptr->first_frame_width ||
++        height + y_offset > png_ptr->first_frame_height)
++        png_error(png_ptr, "dimensions of a frame are greater than"
++                           "the ones in IHDR");
++
++    if (dispose_op != PNG_DISPOSE_OP_NONE &&
++        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
++        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
++        png_error(png_ptr, "invalid dispose_op in fcTL");
++
++    if (blend_op != PNG_BLEND_OP_SOURCE &&
++        blend_op != PNG_BLEND_OP_OVER)
++        png_error(png_ptr, "invalid blend_op in fcTL");
++
++    PNG_UNUSED(delay_num)
++    PNG_UNUSED(delay_den)
++}
++
++png_uint_32 PNGAPI
++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
++                              png_byte is_hidden)
++{
++    png_debug(1, "in png_first_frame_is_hidden()");
++
++    if (png_ptr == NULL)
++        return 0;
++
++    if (is_hidden)
++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++    else
++        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
++
++    PNG_UNUSED(info_ptr)
++
++    return 1;
++}
++#endif /* PNG_APNG_SUPPORTED */
++
+ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ static png_byte
+ check_location(png_const_structrp png_ptr, int location)
+diff -Naru libpng-1.6.40.org/pngstruct.h libpng-1.6.40/pngstruct.h
+--- libpng-1.6.40.org/pngstruct.h	2022-11-24 08:37:51.510052177 +0900
++++ libpng-1.6.40/pngstruct.h	2023-09-10 11:08:58.924075760 +0900
+@@ -399,6 +399,27 @@
+    png_byte filter_type;
+ #endif
+ 
++#ifdef PNG_APNG_SUPPORTED
++   png_uint_32 apng_flags;
++   png_uint_32 next_seq_num;         /* next fcTL/fdAT chunk sequence number */
++   png_uint_32 first_frame_width;
++   png_uint_32 first_frame_height;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++   png_uint_32 num_frames_read;      /* incremented after all image data of */
++                                     /* a frame is read */
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++   png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
++   png_progressive_frame_ptr frame_end_fn;  /* frame data read callback */
++#endif
++#endif
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++   png_uint_32 num_frames_to_write;
++   png_uint_32 num_frames_written;
++#endif
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* New members added in libpng-1.2.0 */
+ 
+ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+diff -Naru libpng-1.6.40.org/pngtest.c libpng-1.6.40/pngtest.c
+--- libpng-1.6.40.org/pngtest.c	2023-09-10 11:12:23.044481879 +0900
++++ libpng-1.6.40/pngtest.c	2023-09-10 11:08:58.924075760 +0900
+@@ -875,6 +875,10 @@
+    volatile int num_passes;
+    int pass;
+    int bit_depth, color_type;
++#ifdef PNG_APNG_SUPPORTED
++   png_uint_32 num_frames;
++   png_uint_32 num_plays;
++#endif
+ 
+    row_buf = NULL;
+    error_parameters.file_name = inname;
+@@ -1383,6 +1387,22 @@
+       }
+    }
+ #endif
++
++#ifdef PNG_APNG_SUPPORTED
++   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++   {
++      if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
++      {
++         png_byte is_hidden;
++         pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
++                    num_frames, num_plays);
++         png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
++         is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
++         png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
++      }
++   }
++#endif
++
+ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+    {
+       png_unknown_chunkp unknowns;
+@@ -1463,6 +1483,110 @@
+    t_misc += (t_stop - t_start);
+    t_start = t_stop;
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++   {
++      png_uint_32 frame;
++      for (frame = 0; frame < num_frames; frame++)
++      {
++         png_uint_32 frame_width;
++         png_uint_32 frame_height;
++         png_uint_32 x_offset;
++         png_uint_32 y_offset;
++         png_uint_16 delay_num;
++         png_uint_16 delay_den;
++         png_byte dispose_op;
++         png_byte blend_op;
++         png_read_frame_head(read_ptr, read_info_ptr);
++         if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
++         {
++            png_get_next_frame_fcTL(read_ptr, read_info_ptr,
++                                    &frame_width, &frame_height,
++                                    &x_offset, &y_offset,
++                                    &delay_num, &delay_den,
++                                    &dispose_op, &blend_op);
++         }
++         else
++         {
++            frame_width = width;
++            frame_height = height;
++            x_offset = 0;
++            y_offset = 0;
++            delay_num = 1;
++            delay_den = 1;
++            dispose_op = PNG_DISPOSE_OP_NONE;
++            blend_op = PNG_BLEND_OP_SOURCE;
++         }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++         png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
++                              frame_width, frame_height,
++                              x_offset, y_offset,
++                              delay_num, delay_den,
++                              dispose_op, blend_op);
++#endif
++         for (pass = 0; pass < num_passes; pass++)
++         {
++#           ifdef calc_pass_height
++               png_uint_32 pass_height;
++
++               if (num_passes == 7) /* interlaced */
++               {
++                  if (PNG_PASS_COLS(frame_width, pass) > 0)
++                     pass_height = PNG_PASS_ROWS(frame_height, pass);
++
++                  else
++                     pass_height = 0;
++               }
++
++               else /* not interlaced */
++                  pass_height = frame_height;
++#           else
++#              define pass_height frame_height
++#           endif
++
++            pngtest_debug1("Writing row data for pass %d", pass);
++            for (y = 0; y < pass_height; y++)
++            {
++#ifndef SINGLE_ROWBUF_ALLOC
++               pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
++
++               row_buf = (png_bytep)png_malloc(read_ptr,
++                  png_get_rowbytes(read_ptr, read_info_ptr));
++
++               pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
++                  (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
++
++#endif /* !SINGLE_ROWBUF_ALLOC */
++               png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
++
++#ifdef PNG_WRITE_SUPPORTED
++#ifdef PNGTEST_TIMING
++               t_stop = (float)clock();
++               t_decode += (t_stop - t_start);
++               t_start = t_stop;
++#endif
++               png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
++#ifdef PNGTEST_TIMING
++               t_stop = (float)clock();
++               t_encode += (t_stop - t_start);
++               t_start = t_stop;
++#endif
++#endif /* PNG_WRITE_SUPPORTED */
++
++#ifndef SINGLE_ROWBUF_ALLOC
++               pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
++               png_free(read_ptr, row_buf);
++               row_buf = NULL;
++#endif /* !SINGLE_ROWBUF_ALLOC */
++            }
++         }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++         png_write_frame_tail(write_ptr, write_info_ptr);
++#endif
++      }
++   }
++   else
++#endif
+    for (pass = 0; pass < num_passes; pass++)
+    {
+ #     ifdef calc_pass_height
+diff -Naru libpng-1.6.40.org/pngwrite.c libpng-1.6.40/pngwrite.c
+--- libpng-1.6.40.org/pngwrite.c	2023-09-10 11:09:32.955139032 +0900
++++ libpng-1.6.40/pngwrite.c	2023-09-10 11:08:58.924075760 +0900
+@@ -128,6 +128,10 @@
+        * the application continues writing the PNG.  So check the 'invalid'
+        * flag here too.
+        */
++#ifdef PNG_WRITE_APNG_SUPPORTED
++      if (info_ptr->valid & PNG_INFO_acTL)
++         png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
++#endif
+ #ifdef PNG_GAMMA_SUPPORTED
+ #  ifdef PNG_WRITE_gAMA_SUPPORTED
+       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
+@@ -373,6 +377,11 @@
+       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+ #endif
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
++      png_error(png_ptr, "Not enough frames written");
++#endif
++
+    /* See if user wants us to write information chunks */
+    if (info_ptr != NULL)
+    {
+@@ -1475,6 +1484,43 @@
+ }
+ #endif
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void PNGAPI
++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
++    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++    png_byte blend_op)
++{
++    png_debug(1, "in png_write_frame_head");
++
++    /* there is a chance this has been set after png_write_info was called,
++    * so it would be set but not written. is there a way to be sure? */
++    if (!(info_ptr->valid & PNG_INFO_acTL))
++        png_error(png_ptr, "png_write_frame_head(): acTL not set");
++
++    png_write_reset(png_ptr);
++
++    png_write_reinit(png_ptr, info_ptr, width, height);
++
++    if ( !(png_ptr->num_frames_written == 0 &&
++           (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
++        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
++                       delay_num, delay_den, dispose_op, blend_op);
++
++    PNG_UNUSED(row_pointers)
++}
++
++void PNGAPI
++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
++{
++    png_debug(1, "in png_write_frame_tail");
++
++    png_ptr->num_frames_written++;
++
++    PNG_UNUSED(info_ptr)
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ 
+ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ /* Initialize the write structure - general purpose utility. */
+diff -Naru libpng-1.6.40.org/pngwutil.c libpng-1.6.40/pngwutil.c
+--- libpng-1.6.40.org/pngwutil.c	2022-11-24 08:37:51.511052176 +0900
++++ libpng-1.6.40/pngwutil.c	2023-09-10 11:08:58.952075811 +0900
+@@ -821,6 +821,11 @@
+    /* Write the chunk */
+    png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++   png_ptr->first_frame_width = width;
++   png_ptr->first_frame_height = height;
++#endif
++
+    if ((png_ptr->do_filter) == PNG_NO_FILTERS)
+    {
+       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+@@ -1002,8 +1007,17 @@
+                optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+ 
+-         if (size > 0)
+-            png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++            if (size > 0)
++#ifdef PNG_WRITE_APNG_SUPPORTED
++            {
++               if (png_ptr->num_frames_written == 0)
++#endif
++               png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++#ifdef PNG_WRITE_APNG_SUPPORTED
++               else
++                  png_write_fdAT(png_ptr, data, size);
++            }
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+          png_ptr->mode |= PNG_HAVE_IDAT;
+ 
+          png_ptr->zstream.next_out = data;
+@@ -1050,7 +1064,17 @@
+ #endif
+ 
+          if (size > 0)
++#ifdef PNG_WRITE_APNG_SUPPORTED
++         {
++            if (png_ptr->num_frames_written == 0)
++#endif
+             png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++#ifdef PNG_WRITE_APNG_SUPPORTED
++            else
++               png_write_fdAT(png_ptr, data, size);
++         }
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+          png_ptr->zstream.avail_out = 0;
+          png_ptr->zstream.next_out = NULL;
+          png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+@@ -1885,6 +1909,82 @@
+ }
+ #endif
+ 
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_acTL(png_structp png_ptr,
++    png_uint_32 num_frames, png_uint_32 num_plays)
++{
++    png_byte buf[8];
++
++    png_debug(1, "in png_write_acTL");
++
++    png_ptr->num_frames_to_write = num_frames;
++
++    if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
++        num_frames--;
++
++    png_save_uint_32(buf, num_frames);
++    png_save_uint_32(buf + 4, num_plays);
++
++    png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
++}
++
++void /* PRIVATE */
++png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
++    png_uint_32 x_offset, png_uint_32 y_offset,
++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++    png_byte blend_op)
++{
++    png_byte buf[26];
++
++    png_debug(1, "in png_write_fcTL");
++
++    if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
++        png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
++    if (png_ptr->num_frames_written == 0 &&
++        (width != png_ptr->first_frame_width ||
++         height != png_ptr->first_frame_height))
++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
++                           "don't match the ones in IHDR");
++
++    /* more error checking */
++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++                             delay_num, delay_den, dispose_op, blend_op);
++
++    png_save_uint_32(buf, png_ptr->next_seq_num);
++    png_save_uint_32(buf + 4, width);
++    png_save_uint_32(buf + 8, height);
++    png_save_uint_32(buf + 12, x_offset);
++    png_save_uint_32(buf + 16, y_offset);
++    png_save_uint_16(buf + 20, delay_num);
++    png_save_uint_16(buf + 22, delay_den);
++    buf[24] = dispose_op;
++    buf[25] = blend_op;
++
++    png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
++
++    png_ptr->next_seq_num++;
++}
++
++void /* PRIVATE */
++png_write_fdAT(png_structp png_ptr,
++    png_const_bytep data, png_size_t length)
++{
++    png_byte buf[4];
++
++    png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
++
++    png_save_uint_32(buf, png_ptr->next_seq_num);
++    png_write_chunk_data(png_ptr, buf, 4);
++
++    png_write_chunk_data(png_ptr, data, length);
++
++    png_write_chunk_end(png_ptr);
++
++    png_ptr->next_seq_num++;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ /* Initializes the row writing capability of libpng */
+ void /* PRIVATE */
+ png_write_start_row(png_structrp png_ptr)
+@@ -2778,4 +2878,39 @@
+    }
+ #endif /* WRITE_FLUSH */
+ }
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_reset(png_structp png_ptr)
++{
++    png_ptr->row_number = 0;
++    png_ptr->pass = 0;
++    png_ptr->mode &= ~PNG_HAVE_IDAT;
++}
++
++void /* PRIVATE */
++png_write_reinit(png_structp png_ptr, png_infop info_ptr,
++                 png_uint_32 width, png_uint_32 height)
++{
++    if (png_ptr->num_frames_written == 0 &&
++        (width != png_ptr->first_frame_width ||
++         height != png_ptr->first_frame_height))
++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
++                           "don't match the ones in IHDR");
++    if (width > png_ptr->first_frame_width ||
++        height > png_ptr->first_frame_height)
++        png_error(png_ptr, "width and/or height for a frame greater than"
++                           "the ones in IHDR");
++
++    png_set_IHDR(png_ptr, info_ptr, width, height,
++                 info_ptr->bit_depth, info_ptr->color_type,
++                 info_ptr->interlace_type, info_ptr->compression_type,
++                 info_ptr->filter_type);
++
++    png_ptr->width = width;
++    png_ptr->height = height;
++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
++    png_ptr->usr_width = png_ptr->width;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ #endif /* WRITE */
+diff -Naru libpng-1.6.40.org/scripts/symbols.def libpng-1.6.40/scripts/symbols.def
+--- libpng-1.6.40.org/scripts/symbols.def	2022-11-24 08:37:51.515052168 +0900
++++ libpng-1.6.40/scripts/symbols.def	2023-09-10 11:08:58.925075762 +0900
+@@ -253,3 +253,23 @@
+  png_set_eXIf @247
+  png_get_eXIf_1 @248
+  png_set_eXIf_1 @249
++ png_get_acTL @250
++ png_set_acTL @251
++ png_get_num_frames @252
++ png_get_num_plays @253
++ png_get_next_frame_fcTL @254
++ png_set_next_frame_fcTL @255
++ png_get_next_frame_width @256
++ png_get_next_frame_height @257
++ png_get_next_frame_x_offset @258
++ png_get_next_frame_y_offset @259
++ png_get_next_frame_delay_num @260
++ png_get_next_frame_delay_den @261
++ png_get_next_frame_dispose_op @262
++ png_get_next_frame_blend_op @263
++ png_get_first_frame_is_hidden @264
++ png_set_first_frame_is_hidden @265
++ png_read_frame_head @266
++ png_set_progressive_frame_fn @267
++ png_write_frame_head @268
++ png_write_frame_tail @269
diff --git a/thirdparty/openmpt_svn_version.h b/thirdparty/openmpt_svn_version.h
deleted file mode 100644
index a45ed9f22449e7a4164bd2a7881c5ae52f805087..0000000000000000000000000000000000000000
--- a/thirdparty/openmpt_svn_version.h
+++ /dev/null
@@ -1,10 +0,0 @@
-
-#pragma once
-#define OPENMPT_VERSION_SVNVERSION "17963"
-#define OPENMPT_VERSION_REVISION 17963
-#define OPENMPT_VERSION_DIRTY 0
-#define OPENMPT_VERSION_MIXEDREVISIONS 0
-#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.4.32"
-#define OPENMPT_VERSION_DATE "2022-09-25T14:19:05.052596Z"
-#define OPENMPT_VERSION_IS_PACKAGE 1
-
diff --git a/thirdparty/sdl2-mixer-ext.cmake b/thirdparty/sdl2-mixer-ext.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a52b11584ae747630ed4c44af6282fb8cc9dea75
--- /dev/null
+++ b/thirdparty/sdl2-mixer-ext.cmake
@@ -0,0 +1,39 @@
+if(TARGET SDL2_mixer_ext_Static)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'SDL2_mixer_ext::SDL2_mixer_ext'")
+
+set(SDL_MIXER_X_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES} CACHE BOOL "" FORCE)
+set(SDL_MIXER_X_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES} CACHE BOOL "" FORCE)
+set(SDL_MIXER_X_DISABLE_INSTALL ON CACHE BOOL "" FORCE)
+set(USE_SYSTEM_SDL2 ON CACHE BOOL "" FORCE)
+set(SDL2_INCLUDE_PATH ${SDL2_INCLUDE_DIR} CACHE PATH "" FORCE)
+set(USE_XMP OFF CACHE PATH "" FORCE)
+
+set(
+	internal_SDL2_mixer_ext_options
+		"SDL_MIXER_X_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
+		"SDL_MIXER_X_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}"
+		"SDL_MIXER_X_DISABLE_INSTALL ON"
+		"USE_SYSTEM_SDL2 ON"
+		"USE_XMP OFF"
+)
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	#list(APPEND internal_SDL2_mixer_ext_options "DOWNLOAD_AUDIO_CODECS_DEPENDENCY ON")
+	#set(DOWNLOAD_AUDIO_CODECS_DEPENDENCY ON CACHE BOOL "" FORCE)
+endif()
+
+include(FetchContent)
+
+
+FetchContent_Declare(
+	SDL2_mixer_ext
+	OPTIONS ${internal_SDL2_mixer_ext_options}
+	GIT_TAG "2.6.0-1"
+	GIT_REPOSITORY "https://github.com/STJr/SDL-Mixer-X.git"
+)
+
+FetchContent_MakeAvailable(SDL2_mixer_ext)
+
diff --git a/thirdparty/sdl2.cmake b/thirdparty/sdl2.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..16fbd7563b2f1c57a12a9202c3e89a69a2f9c191
--- /dev/null
+++ b/thirdparty/sdl2.cmake
@@ -0,0 +1,61 @@
+if(TARGET SDL2-static)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'SDL2::SDL2'")
+
+set(SDL_STATIC ON CACHE BOOL "" FORCE)
+set(SDL_SHARED OFF CACHE BOOL "" FORCE)
+set(SDL_TEST OFF CACHE BOOL "" FORCE)
+set(SDL2_DISABLE_INSTALL OFF CACHE BOOL "" FORCE)
+
+set(
+	internal_sdl2_options
+
+		"SDL_STATIC ON"
+		"SDL_SHARED OFF"
+		"SDL_TEST OFF"
+		"SDL2_DISABLE_INSTALL OFF"
+)
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
+	option(SDL2_DISABLE_SDL2MAIN   "Disable building/installation of SDL2main" OFF)
+	set(SDL2_DISABLE_SDL2MAIN OFF CACHE BOOL "" FORCE)
+endif()
+if(${CMAKE_SYSTEM} MATCHES Darwin)
+	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN OFF")
+	option(SDL2_DISABLE_SDL2MAIN   "Disable building/installation of SDL2main" OFF)
+	set(SDL2_DISABLE_SDL2MAIN OFF CACHE BOOL "" FORCE)
+endif()
+if(${CMAKE_SYSTEM} MATCHES Linux)
+	list(APPEND internal_sdl2_options "SDL2_DISABLE_SDL2MAIN ON")
+	option(SDL2_DISABLE_SDL2MAIN   "Disable building/installation of SDL2main" ON)
+	set(SDL2_DISABLE_SDL2MAIN ON CACHE BOOL "" FORCE)
+endif()
+
+include(FetchContent)
+
+if (SDL2_USE_THIRDPARTY)
+	FetchContent_Declare(
+		SDL2
+		VERSION 2.30.0
+		GITHUB_REPOSITORY "libsdl-org/SDL"
+		GIT_TAG release-2.30.0
+		OPTIONS ${internal_sdl2_options}
+		OVERRIDE_FIND_PACKAGE
+	)
+else()
+	FetchContent_Declare(
+		SDL2
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/SDL2/"
+		OPTIONS ${internal_sdl2_options}
+		OVERRIDE_FIND_PACKAGE
+	)
+endif()
+
+FetchContent_MakeAvailable(SDL2)
+
+set(SDL2_INCLUDE_DIR "${SDL2_BINARY_DIR}/include" CACHE PATH "" FORCE)
+set(SDL2_LIBRARY "${SDL2_BINARY_DIR}/SDL2-staticd.lib" CACHE PATH "" FORCE)
+set(SDL2_DIR ${SDL2_BINARY_DIR} CACHE PATH "" FORCE)
diff --git a/thirdparty/vcpkg-overlays/.placeholder b/thirdparty/vcpkg-overlays/.placeholder
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/thirdparty/zlib.cmake b/thirdparty/zlib.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..257609f775ae9f7c325665198f0e8804a5cb6030
--- /dev/null
+++ b/thirdparty/zlib.cmake
@@ -0,0 +1,36 @@
+if(TARGET ZLIB::ZLIB)
+    return()
+endif()
+
+message(STATUS "Third-party: creating target 'ZLIB::ZLIB'")
+
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
+
+include(FetchContent)
+
+if (zlib_USE_THIRDPARTY)
+	FetchContent_Declare(
+		ZLIB
+		GITHUB_REPOSITORY "madler/zlib"
+		GIT_TAG v1.3.1
+		OVERRIDE_FIND_PACKAGE
+		OPTIONS
+			"ZLIB_BUILD_EXAMPLES OFF"
+	)
+else()
+	FetchContent_Declare(
+		ZLIB
+		SOURCE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/zlib/"
+		OVERRIDE_FIND_PACKAGE
+		OPTIONS
+			"ZLIB_BUILD_EXAMPLES OFF"
+	)
+endif()
+
+FetchContent_MakeAvailable(ZLIB)
+
+
+add_library(ZLIB::ZLIB ALIAS zlibstatic)
+
+set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib" "${zlib_BINARY_DIR}" CACHE PATH "" FORCE)
+
diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json
new file mode 100644
index 0000000000000000000000000000000000000000..547114800f3088a704ec397b482c4bfed86cea3d
--- /dev/null
+++ b/vcpkg-configuration.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg-configuration.schema.json",
+  "overlay-ports": [
+    "./thirdparty/vcpkg-overlays"
+  ]
+}
diff --git a/vcpkg.json b/vcpkg.json
new file mode 100644
index 0000000000000000000000000000000000000000..07c4244ad3affde086c98bd46867ae8cd0d02b18
--- /dev/null
+++ b/vcpkg.json
@@ -0,0 +1,85 @@
+{
+  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
+  "name": "srb2",
+  "version": "1.0.0",
+  "builtin-baseline": "c823fd3e57035b10d970a96da2796a2db55e5df5",
+  "dependencies": [
+    "curl",
+    {
+      "name": "libgme",
+      "platform": "!(windows & mingw) & !native"
+    },
+    {
+      "name": "libopenmpt",
+      "platform": "!(windows & mingw)"
+    },
+    "libpng",
+    "miniupnpc",
+    "sdl2",
+    {
+      "name": "sdl2-mixer-ext",
+      "features": [
+        {
+          "name": "cmd",
+          "platform": "linux"
+        },
+        {
+          "name": "libflac",
+          "platform": "!(windows & mingw & !static)"
+        },
+        {
+          "name": "libgme",
+          "platform": "!(windows & mingw) & !native"
+        },
+        {
+          "name": "libmodplug",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "libopnmidi",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "libvorbis",
+          "platform": "!(windows & mingw & !static)"
+        },
+        {
+          "name": "libxmp",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "mpg123",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "nativemidi",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "opusfile",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "pxtone",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "timidity",
+          "platform": "!(windows & mingw)"
+        },
+        {
+          "name": "wavpack",
+          "platform": "!(windows & mingw)"
+        }
+      ]
+    },
+    "zlib"
+  ],
+  "overrides": [
+    {
+      "name": "sdl2",
+      "version": "2.28.5",
+      "port-version": 1
+    }
+  ]
+}