diff --git a/.circleci/config.yml b/.circleci/config.yml
index b86b39f752a38aee24f50bb260f7b6b45d8b722f..9cf3c2a4e36338e88a9f08201a4df200395fdcf9 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,6 +7,7 @@ jobs:
         environment:
           CC: ccache gcc
           CCACHE_COMPRESS: true
+          CFLAGS: -Wno-error=unused-result
       #- image: ubuntu:trusty
       #  environment:
       #    CC: ccache gcc -m32
@@ -49,12 +50,15 @@ jobs:
           paths:
             - /home/circleci/.cache/apt
       - checkout
+      - run:
+         name: Create deps folder as needed
+         command: mkdir -p make/linux/64/SDL/deps/
       - run:
           name: make master depend file
-          command: find make/linux64/SDL/deps/ -type f -print0 | sort -z | xargs -r0 cat > make/linux64/SDL.deps
+          command: find make/linux/64/SDL/deps/ -type f -print0 | sort -z | xargs -r0 cat > make/linux/64/SDL.deps
       - restore_cache:
           keys:
-            - v1-SRB2-{{ .Branch }}-{{ checksum "make/linux64/SDL.deps" }}
+            - v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/64/SDL.deps" }}
       - run:
           name: Compile
           command: make -C src LINUX64=1 ERRORMODE=1 -k -j4
@@ -62,6 +66,6 @@ jobs:
           path: /home/circleci/SRB2/bin/
           destination: bin
       - save_cache:
-          key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux64/SDL.deps" }}
+          key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/64/SDL.deps" }}
           paths:
             - /home/circleci/.ccache
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml b/.gitlab/ci/jobs/alpine-3-gcc-dedicated-makefile.yml
similarity index 86%
rename from .gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
rename to .gitlab/ci/jobs/alpine-3-gcc-dedicated-makefile.yml
index 242ddd0eaa3f0e45504fa0fe258e08c63e0845df..fe63e09c8368cca1da7203b81411f55b3165ac44 100644
--- a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
+++ b/.gitlab/ci/jobs/alpine-3-gcc-dedicated-makefile.yml
@@ -1,18 +1,18 @@
-Alpine 3 GCC Dedicated:
-  extends: Alpine 3 GCC
+Alpine 3 GCC Dedicated Makefile:
+  extends: Alpine 3 GCC Makefile
 
   artifacts:
     paths:
       - "bin/"
       - "src/comptime.h"
-    expose_as: "Apline-3-Dedicated"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
+    expose_as: "Apline-3-Dedicated-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated-makefile"
 
   script:
     - - |
           # apk_toolchain
           echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
+      - apk add gcc g++
       - |
           # apk_toolchain
           echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-makefile.yml b/.gitlab/ci/jobs/alpine-3-gcc-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2cc656ca78a5641a594ee894a07f591c628ee36f
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc-makefile.yml
@@ -0,0 +1,135 @@
+Alpine 3 GCC Makefile:
+  stage: build
+
+  when: manual
+
+  image: alpine:3
+
+  allow_failure: true
+
+  cache:
+    - key: apk-$CI_JOB_IMAGE-makefile
+      paths:
+        - apk-cache
+      unprotect: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-makefile"
+
+  before_script:
+    - - |
+          # apk_cache
+          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
+      - export APK_CACHE_DIR=`pwd`/apk-cache
+      - mkdir --parents --verbose $APK_CACHE_DIR/
+      - ln -sf /etc/apk/cache $APK_CACHE_DIR
+      - |
+          # apk_cache
+          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
+
+    - - |
+          # apk_update
+          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
+      - apk update
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
+
+    - - |
+          # apk_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apk upgrade
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
+
+    - - |
+          # apk_common
+          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apk add make git ccache nasm
+      - |
+          # apk_common
+          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc g++
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add cmake musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev elfutils-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+  after_script:
+    - - |
+           # apk_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
+      - apk cache clean
+      - |
+          # apk_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats --verbose
+      - ccache --show-log-stats --verbose
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/.gitlab/ci/jobs/alpine-3-gcc.yml b/.gitlab/ci/jobs/alpine-3-gcc.yml
index b3b12e40167a568e3ced2abc7a09ed0045e0cc99..1881bf3c2a445b3a517e20f49fd2ecec34b81460 100644
--- a/.gitlab/ci/jobs/alpine-3-gcc.yml
+++ b/.gitlab/ci/jobs/alpine-3-gcc.yml
@@ -15,8 +15,8 @@ Alpine 3 GCC:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.alpine3/bin/"
+      - "build.alpine3/src/config.h"
     expose_as: "Apline-3"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
 
@@ -50,7 +50,7 @@ Alpine 3 GCC:
     - - |
           # apk_common
           echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apk add make git ccache nasm
+      - apk add cmake make git ccache nasm
       - |
           # apk_common
           echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
@@ -95,7 +95,7 @@ Alpine 3 GCC:
     - - |
           # apk_toolchain
           echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
+      - apk add gcc g++
       - |
           # apk_toolchain
           echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
@@ -103,15 +103,23 @@ Alpine 3 GCC:
     - - |
           # apk_development
           echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
+      - apk add cmake musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev elfutils-dev
       - |
           # apk_development
           echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.alpine3 -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_EXECINFO=NO -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
+      - make --directory=build.alpine3 --keep-going || make --directory=build.alpine3 --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/batocera-arm64-makefile.yml b/.gitlab/ci/jobs/batocera-arm64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9a590807de1d819d2be713011a2d8a1fbb61d1d1
--- /dev/null
+++ b/.gitlab/ci/jobs/batocera-arm64-makefile.yml
@@ -0,0 +1,38 @@
+batocera:arm64 Makefile:
+  extends: Debian stable:arm64 Makefile
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64-makefile"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/batocera-arm64.yml b/.gitlab/ci/jobs/batocera-arm64.yml
index 3e43aa8753a0a1500abdc52e9f594863bd4b3691..c83a5badb0e096a48a83cc6fc32388a05ed245dd 100644
--- a/.gitlab/ci/jobs/batocera-arm64.yml
+++ b/.gitlab/ci/jobs/batocera-arm64.yml
@@ -7,8 +7,8 @@ batocera:arm64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian old arm64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
 
@@ -29,10 +29,18 @@ batocera:arm64:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS=ON -DSRB2_CONFIG_USE_GME=OFF -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-amd64-makefile.yml b/.gitlab/ci/jobs/debian-oldstable-amd64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ba2e745bd423326fa326e18ee2985f659a235401
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64-makefile.yml
@@ -0,0 +1,40 @@
+Debian oldstable:amd64 Makefile:
+  extends: Debian stable:amd64 Makefile
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old amd64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64-makefile"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-amd64.yml b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
index 3929ecdcd10f8f448072d2c859de6a7dd31d94c7..32c7f3e40f6f9ac8145a6c679c86856ff879212a 100644
--- a/.gitlab/ci/jobs/debian-oldstable-amd64.yml
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
@@ -9,8 +9,8 @@ Debian oldstable:amd64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian old amd64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
 
@@ -31,10 +31,18 @@ Debian oldstable:amd64:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_USE_GME=OFF -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-arm64-makefile.yml b/.gitlab/ci/jobs/debian-oldstable-arm64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..79e282bc62bbaf450e67da14041cb89bfbd910ca
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64-makefile.yml
@@ -0,0 +1,40 @@
+Debian oldstable:arm64 Makefile:
+  extends: Debian stable:arm64 Makefile
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64-makefile"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-arm64.yml b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
index b18d538cd0824041650f3f8a5361b7b07c85f206..4bf324e3be14425830c4ff6d218d5ec33c35e559 100644
--- a/.gitlab/ci/jobs/debian-oldstable-arm64.yml
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
@@ -9,8 +9,8 @@ Debian oldstable:arm64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian old arm64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
 
@@ -31,10 +31,18 @@ Debian oldstable:arm64:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS=ON -DSRB2_CONFIG_USE_GME=OFF -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-amd64-makefile.yml b/.gitlab/ci/jobs/debian-stable-amd64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6dfe176cd5fda3b28f545f8d5e7907e2538f07de
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-amd64-makefile.yml
@@ -0,0 +1,45 @@
+Debian stable:amd64 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian amd64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64-makefile"
+
+  variables:
+    CC: x86_64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: x86_64-linux-gnu-objcopy
+    OBJDUMP: x86_64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
+
+  when: on_success
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-amd64.yml b/.gitlab/ci/jobs/debian-stable-amd64.yml
index 4a757afe0d519f268bb4541cda49ba03a3181600..533a3151d5d81e1d9df62e31471269c6bf2b89da 100644
--- a/.gitlab/ci/jobs/debian-stable-amd64.yml
+++ b/.gitlab/ci/jobs/debian-stable-amd64.yml
@@ -5,8 +5,8 @@ Debian stable:amd64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian amd64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
 
@@ -36,10 +36,18 @@ Debian stable:amd64:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-arm64-makefile.yml b/.gitlab/ci/jobs/debian-stable-arm64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d932e9f4236d1983950ca61a9e41715af4aed5f5
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-arm64-makefile.yml
@@ -0,0 +1,46 @@
+Debian stable:arm64 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian arm64 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64-makefile"
+
+  variables:
+    CC: aarch64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: aarch64-linux-gnu-objcopy
+    OBJDUMP: aarch64-linux-gnu-objdump
+    LD: aarch64-linux-gnu-ld
+    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-arm64.yml b/.gitlab/ci/jobs/debian-stable-arm64.yml
index 879391affebe7586e019e7bb7f8d77a0599983e2..db82ee38a0ac4c7ad483479bb81ab78cdba0a98a 100644
--- a/.gitlab/ci/jobs/debian-stable-arm64.yml
+++ b/.gitlab/ci/jobs/debian-stable-arm64.yml
@@ -7,8 +7,8 @@ Debian stable:arm64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian arm64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
 
@@ -17,6 +17,7 @@ Debian stable:arm64:
     LDFLAGS: -Wl,-fuse-ld=gold
     OBJCOPY: aarch64-linux-gnu-objcopy
     OBJDUMP: aarch64-linux-gnu-objdump
+    LD: aarch64-linux-gnu-ld
     PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
 
   script:
@@ -36,10 +37,18 @@ Debian stable:arm64:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS=ON -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-i386-makefile.yml b/.gitlab/ci/jobs/debian-stable-i386-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bbabee4a6cde37050ee3e6bbbc89e918914e275f
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-i386-makefile.yml
@@ -0,0 +1,45 @@
+Debian stable:i386 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian i386 makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686-makefile"
+
+  variables:
+    CC: i686-linux-gnu-gcc
+    OBJCOPY: i686-linux-gnu-objcopy
+    OBJDUMP: i686-linux-gnu-objdump
+    LD: i686-linux-gnu-ld
+    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-i386.yml b/.gitlab/ci/jobs/debian-stable-i386.yml
index cd6206e55e9a497d7065d3ea652c1ed3c6bd8d23..8d9ea49644a700490c471414248e671eef8e3e00 100644
--- a/.gitlab/ci/jobs/debian-stable-i386.yml
+++ b/.gitlab/ci/jobs/debian-stable-i386.yml
@@ -7,8 +7,8 @@ Debian stable:i386:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Debian i386"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
 
@@ -16,6 +16,7 @@ Debian stable:i386:
     CC: i686-linux-gnu-gcc
     OBJCOPY: i686-linux-gnu-objcopy
     OBJDUMP: i686-linux-gnu-objdump
+    LD: i686-linux-gnu-ld
     PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
 
   script:
@@ -35,10 +36,18 @@ Debian stable:i386:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-testing-gcc-amd64-makefile.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5edaddf3373e3cdcad9d0a6eda0167df2d813c2e
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64-makefile.yml
@@ -0,0 +1,46 @@
+Debian testing GCC Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  image: debian:testing-slim
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "testing-gcc-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc-makefile"
+
+  variables:
+    CC: gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
index 10799b3053e45a3d98fcfa1f63281e36ebadae9d..458c6d1efdc203da3d248a41ac5a29e583a53882 100644
--- a/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
@@ -11,8 +11,8 @@ Debian testing GCC:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "testing-gcc"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
 
@@ -37,10 +37,18 @@ Debian testing GCC:
           # apt_development
           echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
 
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-arm64.yml b/.gitlab/ci/jobs/macos-arm64.yml
index 3928413610a048460dfe05d0dfc8f92e9da76848..a9e31773e6b2d58ffa4fce856085a83ad0f8bece 100644
--- a/.gitlab/ci/jobs/macos-arm64.yml
+++ b/.gitlab/ci/jobs/macos-arm64.yml
@@ -30,7 +30,7 @@ osxcross arm64:
     - - |
           # cmake
           echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_FORCE_NO_MS_BITFIELDS:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-x86_64.yml b/.gitlab/ci/jobs/macos-x86_64.yml
index 818028e49a43624f3e29a357d7d7614ef4dd5118..525a919c8a6976308d752bc82e68143233d59798 100644
--- a/.gitlab/ci/jobs/macos-x86_64.yml
+++ b/.gitlab/ci/jobs/macos-x86_64.yml
@@ -3,6 +3,30 @@ osxcross x86_64:
 
   stage: build
 
+  cache:
+    - key: ccache-$CI_JOB_NAME_SLUG-$CI_COMMIT_REF_SLUG
+      fallback_keys:
+        - ccache-$CI_JOB_NAME_SLUG-$CI_DEFAULT_BRANCH
+        - ccache-$CI_JOB_NAME_SLUG-master
+      paths:
+        - build/ccache
+        - build/ccache_statslog
+
+    - key: apt-$CI_JOB_IMAGE
+      paths:
+        - build/apt-cache
+      unprotect: true
+
+    - key: vcpkg-root
+      paths:
+        - build/vcpkg-root
+      unprotect: true
+
+    - key: vcpkg-binary-cache-x64-osx
+      paths:
+        - build/vcpkg-binary-cache
+      unprotect: true
+
   artifacts:
     paths:
       - "build.osxcross/bin/"
@@ -15,6 +39,27 @@ osxcross x86_64:
     LD: x86_64-apple-darwin21.4-ld
 
   script:
+    - |
+        # vcpkg
+        echo -e "\e[0Ksection_start:`date +%s`:vcpkg-root[collapsed=true]\r\e[0KUpdating vcpkg"
+
+        if [ -d "build/vcpkg-root" ]; then
+          pushd build/vcpkg-root
+          git fetch https://github.com/Microsoft/vcpkg master
+          git reset --hard FETCH_HEAD
+          popd
+        else
+          mkdir -p build
+          git clone https://github.com/Microsoft/vcpkg build/vcpkg-root
+        fi
+
+        export VCPKG_ROOT=$(pwd)/build/vcpkg-root
+        export VCPKG_BINARY_SOURCES="clear;files,$(pwd)/build/vcpkg-binary-cache,readwrite"
+
+        mkdir -p "build/vcpkg-binary-cache"
+
+        echo -e "\e[0Ksection_end:`date +%s`:vcpkg-root\r\e[0K"
+
     - - |
           # apt_development
           echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
@@ -38,3 +83,33 @@ osxcross x86_64:
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+  after_script:
+    - - |
+           # apt_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
+      - apt-get autoclean
+      - |
+          # apt_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
+
+    - - |
+          # vcpkg_clean
+          echo -e "\e[0Ksection_start:`date +%s`:vcpkg_clean[collapsed=true]\r\e[0KCleaning vcpkg-root"
+
+          if [ -d "build/vcpkg-root" ]; then
+            pushd "build/vcpkg-root"
+            git clean
+            popd
+          fi
+
+          echo -e "\e[0Ksection_end:`date +%s`:vcpkg_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats
+      - ccache --show-log-stats || true
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x64-makefile.yml b/.gitlab/ci/jobs/windows-x64-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f28fa219cc09550684abeddb5300927f00882d1a
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x64-makefile.yml
@@ -0,0 +1,35 @@
+Windows x64 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win64-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64-makefile"
+
+  variables:
+    PREFIX: x86_64-w64-mingw32
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-x86-64-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x64.yml b/.gitlab/ci/jobs/windows-x64.yml
index da8d960bd1330229a2265ed9b015a487f1040e75..180fa773c34823e9eebd8254500233d1be8215a7 100644
--- a/.gitlab/ci/jobs/windows-x64.yml
+++ b/.gitlab/ci/jobs/windows-x64.yml
@@ -9,8 +9,8 @@ Windows x64:
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build.cmake/bin/"
+      - "build.cmake/src/config.h"
     expose_as: "Win64"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
 
@@ -26,10 +26,26 @@ Windows x64:
           # apt_toolchain
           echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
 
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install ninja-build
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.cmake -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-mingw-static -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/toolchains/mingw.cmake
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
+      - make --directory=build.cmake --keep-going || make --directory=build.cmake --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x86-makefile.yml b/.gitlab/ci/jobs/windows-x86-makefile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9601cd6e68013b1971b6d3276802bad932a5a95c
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x86-makefile.yml
@@ -0,0 +1,35 @@
+Windows x86 Makefile:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win32-makefile"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32-makefile"
+
+  variables:
+    PREFIX: i686-w64-mingw32
+    CC: /usr/bin/i686-w64-mingw32-gcc-posix
+    CXX: /usr/bin/i686-w64-mingw32-g++-posix
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-i686-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x86.yml b/.gitlab/ci/jobs/windows-x86.yml
index 311c767bbd9cd31d1063a248f68c0a6793dd47d5..2d885508570913bdb71bbb2bab1bd34f03c7e67a 100644
--- a/.gitlab/ci/jobs/windows-x86.yml
+++ b/.gitlab/ci/jobs/windows-x86.yml
@@ -3,12 +3,38 @@ Windows x86:
 
   stage: build
 
-  when: on_success
+  when: manual
+
+  allow_failure: true
+
+  cache:
+    - key: ccache-$CI_JOB_NAME_SLUG-$CI_COMMIT_REF_SLUG
+      fallback_keys:
+        - ccache-$CI_JOB_NAME_SLUG-$CI_DEFAULT_BRANCH
+        - ccache-$CI_JOB_NAME_SLUG-master
+      paths:
+        - build/ccache
+        - build/ccache_statslog
+
+    - key: apt-$CI_JOB_IMAGE
+      paths:
+        - build/apt-cache
+      unprotect: true
+
+    - key: vcpkg-root
+      paths:
+        - build/vcpkg-root
+      unprotect: true
+
+    - key: vcpkg-binary-cache-x86-mingw-static
+      paths:
+        - build/vcpkg-binary-cache
+      unprotect: true
 
   artifacts:
     paths:
-      - "bin/"
-      - "src/comptime.h"
+      - "build/ninja-x86_mingw_static_vcpkg-debug/bin/"
+      - "build/ninja-x86_mingw_static_vcpkg-debug/src/config.h"
     expose_as: "Win32"
     name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
 
@@ -18,6 +44,27 @@ Windows x86:
     CXX: /usr/bin/i686-w64-mingw32-g++-posix
 
   script:
+    - |
+        # vcpkg
+        echo -e "\e[0Ksection_start:`date +%s`:vcpkg-root[collapsed=true]\r\e[0KUpdating vcpkg"
+
+        if [ -d "build/vcpkg-root" ]; then
+          pushd build/vcpkg-root
+          git fetch https://github.com/Microsoft/vcpkg master
+          git reset --hard FETCH_HEAD
+          popd
+        else
+          mkdir -p build
+          git clone https://github.com/Microsoft/vcpkg build/vcpkg-root
+        fi
+
+        export VCPKG_ROOT=$(pwd)/build/vcpkg-root
+        export VCPKG_BINARY_SOURCES="clear;files,$(pwd)/build/vcpkg-binary-cache,readwrite"
+
+        mkdir -p "build/vcpkg-binary-cache"
+
+        echo -e "\e[0Ksection_end:`date +%s`:vcpkg-root\r\e[0K"
+
     - - |
           # apt_toolchain
           echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
@@ -26,10 +73,58 @@ Windows x86:
           # apt_toolchain
           echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
 
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install ninja-build
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake --preset ninja-x86_mingw_static_vcpkg-debug -G "Unix Makefiles" -DSRB2_USE_CCACHE=YES -DSRB2_CONFIG_ERRORMODE=ON -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
     - - |
           # make
           echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
+      - cmake --build --preset ninja-x86_mingw_static_vcpkg-debug --parallel 1 -- --keep-going || cmake --build --preset ninja-x86_mingw_static_vcpkg-debug --parallel 1 -- --keep-going
       - |
           # make
           echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+  after_script:
+    - - |
+           # apt_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
+      - apt-get autoclean
+      - |
+          # apt_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
+
+    - - |
+          # vcpkg_clean
+          echo -e "\e[0Ksection_start:`date +%s`:vcpkg_clean[collapsed=true]\r\e[0KCleaning vcpkg-root"
+
+          if [ -d "build/vcpkg-root" ]; then
+            pushd "build/vcpkg-root"
+            git clean -f
+            popd
+          fi
+
+          echo -e "\e[0Ksection_end:`date +%s`:vcpkg_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats
+      - ccache --show-log-stats || true
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3b08a9facc348aad76f77b55a5700b8929859333..a4c631102606ee3177c94f1bb7a35b100694bf4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,7 @@ endif()
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
 include(CMakeDependentOption)
+include(CheckCXXCompilerFlag)
 
 file(STRINGS src/version.h SRB2_VERSION)
 string(REGEX MATCH "[0-9]+\\.[0-9.]+" SRB2_VERSION ${SRB2_VERSION})
@@ -72,6 +73,7 @@ option(SRB2_CONFIG_MOBJCONSISTANCY "Compile with MOBJCONSISTANCY defined." OFF)
 option(SRB2_CONFIG_PACKETDROP "Compile with PACKETDROP defined." OFF)
 option(SRB2_CONFIG_EXECINFO "Enable stack trace dump support." ON)
 option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF)
+option(SRB2_CONFIG_FORCE_NO_MS_BITFIELDS "Compile without -mno-ms-bitfields compiler flag" OFF)
 # SRB2_CONFIG_PROFILEMODE is probably superceded by some CMake setting.
 option(SRB2_CONFIG_PROFILEMODE "Compile for profiling (GCC only)." OFF)
 set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.")
diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg
index 41ad998891154f56fe850cdfe457a48189dd648f..7ef5ab1e170dcb00041a0a341a8d7a82da0072d2 100644
--- a/extras/conf/SRB2-22.cfg
+++ b/extras/conf/SRB2-22.cfg
@@ -41,7 +41,7 @@ linetagindicatesectors = true;
 
 // The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
 formatinterface = "SRB2MapSetIO";
-	
+
 //Maximum safe map size check (0 means skip check)
 safeboundary = 0;
 
@@ -502,7 +502,7 @@ gen_sectortypes
 	{
 		0 = "Normal";
 		512 = "Wind/Current <deprecated>";
-		1024 = "Conveyor Belt <deprecated>";		 
+		1024 = "Conveyor Belt <deprecated>";
 		1280 = "Speed Pad";
 		1536 = "Flip Gravity on Jump";
 	}
@@ -3730,7 +3730,7 @@ thingtypes
 
 		3328 = "3D Mode Start";
 	}
-	
+
 	starts
 	{
 		color = 1; // Blue
diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg
index e5cafead431c0d79eaaef734eee008eeab89dd15..9bf882f56a11346709b7c7c263e37dd86ffad173 100644
--- a/extras/conf/udb/Includes/SRB222_common.cfg
+++ b/extras/conf/udb/Includes/SRB222_common.cfg
@@ -96,7 +96,7 @@ mapformat_udmf
 	{
 		include("SRB222_misc.cfg", "universalfields");
 	}
-	
+
 	// Disable Doom-related modes that don't make sense for SRB2
 	soundsupport = false;
 	automapsupport = false;
@@ -195,4 +195,4 @@ mapformat_udmf
 	{
 		include("SRB222_linedefs.cfg", "udmf");
 	}
-}
\ No newline at end of file
+}
diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index fc505fb6025b02782d1a309b247f569a63dd96fd..ce1979581fb7e1251ad76882154eab80ec204f06 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -8,7 +8,7 @@ udmf
 		{
 			title = "None";
 		}
-		
+
 		6
 		{
 			title = "Sector Set Portal";
@@ -897,7 +897,7 @@ udmf
 				}
 			}
 		}
-		
+
 		190
 		{
 			title = "Rising";
diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index c37c29ce0def1f471565d7d4494ac7ab833eb054..e5786977bd4e9c3a543c2113d0f20fa8b84939a1 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -240,7 +240,7 @@ universalfields
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		comment
 		{
 			type = 2;
@@ -252,19 +252,19 @@ universalfields
 			type = 2;
 			default = "";
 		}
-		
+
 		stringarg0
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		stringarg1
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		executordelay
 		{
 			type = 0;
@@ -279,19 +279,19 @@ universalfields
 			type = 2;
 			default = "";
 		}
-		
+
 		light
 		{
 			type = 0;
 			default = 0;
 		}
-		
+
 		lightabsolute
 		{
 			type = 3;
 			default = false;
 		}
-		
+
 		//light_top
 		//{
 		//	type = 0;
@@ -326,8 +326,8 @@ universalfields
 		//{
 		//	type = 3;
 		//	default = false;
-		//}		
-		
+		//}
+
 		offsetx_bottom
 		{
 			type = 1;
@@ -339,7 +339,7 @@ universalfields
 			type = 1;
 			default = 0.0;
 		}
-		
+
 		offsetx_top
 		{
 			type = 1;
@@ -357,43 +357,43 @@ universalfields
 			type = 1;
 			default = 0.0;
 		}
-		
+
 		offsety_top
 		{
 			type = 1;
 			default = 0.0;
 		}
-		
+
 		scalex_bottom
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scalex_mid
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scalex_top
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley_bottom
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley_mid
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley_top
 		{
 			type = 1;
@@ -408,41 +408,41 @@ universalfields
 			type = 2;
 			default = "";
 		}
-		
+
 		pitch
 		{
 			type = 0;
 		}
-		
+
 		roll
 		{
 			type = 0;
 		}
-		
+
 		scalex
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		scaley
 		{
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		stringarg0
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		stringarg1
 		{
 			type = 2;
 			default = "";
 		}
-		
+
 		mobjscale
 		{
 			type = 1;
@@ -450,7 +450,7 @@ universalfields
 			managed = false;
 		}
 	}
-	
+
 	sector
 	{
 		comment
@@ -530,7 +530,7 @@ universalfields
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		yscalefloor
 		{
 			type = 1;
@@ -542,7 +542,7 @@ universalfields
 			type = 0;
 			default = 0;
 		}
-		
+
 		lightfloorabsolute
 		{
 			type = 3;
@@ -572,7 +572,7 @@ universalfields
 			type = 1;
 			default = 1.0;
 		}
-		
+
 		yscaleceiling
 		{
 			type = 1;
@@ -584,7 +584,7 @@ universalfields
 			type = 0;
 			default = 0;
 		}
-		
+
 		lightceilingabsolute
 		{
 			type = 3;
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index c028f9439c493d156e1ded87f7a116cc4b14d9d7..8b1e29751b7bb4b3e771813b414d80f9017a4f68 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -1127,12 +1127,12 @@ udmf
 				}
 			}
 		}
-		
+
 		bossinvisibles
 		{
 			title = "Misc. Invisible";
 			color = 15; // White
-			
+
 			290
 			{
 				arrow = 0;
@@ -2021,7 +2021,7 @@ udmf
 			}
 		}
 	}
-	
+
 	hazards
 	{
 		color = 17; // Orange
@@ -2983,7 +2983,7 @@ udmf
 		{
 			title = "Mace Spawnpoints";
 			color = 11;
-			
+
 			1104
 			{
 				title = "Mace Spawn";
@@ -3188,7 +3188,7 @@ udmf
 					title = "Flags";
 					type = 12;
 					enum = "maceflags";
-	
+
 				}
 			}
 			1108
@@ -3320,7 +3320,7 @@ udmf
 				}
 			}
 		}
-		
+
 		1100
 		{
 			title = "Chain (Decorative)";
@@ -3570,12 +3570,12 @@ udmf
 		color = 2; // Green
 		title = "Arid Canyon";
 
-		
+
 		cacti
 		{
 			title = "Cacti";
 			color = 17;
-			
+
 			1203
 			{
 				title = "Tiny Red Flower Cactus";
@@ -3654,12 +3654,12 @@ udmf
 				height = 60;
 			}
 		}
-		
+
 		minecarts
 		{
 			title = "Minecart";
 			color = 11;
-			
+
 			1219
 			{
 				title = "Minecart Spawner";
@@ -3706,7 +3706,7 @@ udmf
 				}
 			}
 		}
-		
+
 		1200
 		{
 			title = "Tumbleweed (Big)";
@@ -4611,7 +4611,7 @@ udmf
 		title = "Botanic Serenity";
 		width = 16;
 		height = 32;
-		
+
 		flowers
 		{
 			title = "Flowers";
@@ -4706,7 +4706,7 @@ udmf
 				sprite = "BSZ3F0";
 			}
 		}
-		
+
 		tulips
 		{
 			title = "Tulips";
@@ -4771,7 +4771,7 @@ udmf
 				sprite = "BSZ5F0";
 			}
 		}
-		
+
 		bushes
 		{
 			title = "Bushes";
@@ -4806,7 +4806,7 @@ udmf
 				sprite = "BSZ6F0";
 			}
 		}
-		
+
 		vines
 		{
 			title = "Vines";
@@ -5063,7 +5063,7 @@ udmf
 			}
 		}
 	}
-	
+
 	mario
 	{
 		color = 2; // Green
@@ -5574,7 +5574,7 @@ udmf
 			}
 		}
 	}
-	
+
 	editor
 	{
 		color = 15; // White
@@ -5587,4 +5587,4 @@ udmf
 
 		3328 = "3D Mode Start";
 	}
-}
\ No newline at end of file
+}
diff --git a/extras/conf/udb/SRB2-22binary.cfg b/extras/conf/udb/SRB2-22binary.cfg
index 3073b76c4570cb9a8f7f62a3e675cbffc7814614..2144ff7a61591b1c9a6865013cd44499179f2183 100644
--- a/extras/conf/udb/SRB2-22binary.cfg
+++ b/extras/conf/udb/SRB2-22binary.cfg
@@ -41,7 +41,7 @@ linetagindicatesectors = true;
 
 // The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
 formatinterface = "DoomMapSetIO";
-	
+
 //Maximum safe map size check (0 means skip check)
 safeboundary = 0;
 
@@ -502,7 +502,7 @@ gen_sectortypes
 	{
 		0 = "Normal";
 		512 = "Wind/Current <deprecated>";
-		1024 = "Conveyor Belt <deprecated>";		 
+		1024 = "Conveyor Belt <deprecated>";
 		1280 = "Speed Pad";
 		1536 = "Flip Gravity on Jump";
 	}
@@ -3636,7 +3636,7 @@ thingtypes
 
 		3328 = "3D Mode Start";
 	}
-	
+
 	starts
 	{
 		color = 1; // Blue
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fbd29cddda5e3caae29aaee01bbed579375730a5..2cfb56f6e9645b126320f1242da095737ac866d5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -234,9 +234,12 @@ endif()
 
 # Compatibility flag with later versions of GCC
 # We should really fix our code to not need this
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
-	if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64|em64t|EM64T)")
-		target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+if (NOT SRB2_CONFIG_FORCE_NO_MS_BITFIELDS)
+	if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+		check_cxx_compiler_flag("-mno-ms-bitfields" HAS_NO_MS_BITFIELDS)
+		if(HAS_NO_MS_BITFIELDS)
+			target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+		endif()
 	endif()
 endif()
 
diff --git a/src/command.c b/src/command.c
index 29f491e295d7378be64cf72a2c0115c5dd51e676..ab6cfc08af7c4cde9f756d868b02e42ffd29229d 100644
--- a/src/command.c
+++ b/src/command.c
@@ -705,7 +705,7 @@ static void add_alias(char *newname, char *newcmd)
 	{
 		if (!stricmp(newname, a->name))
 		{
-			Z_Free(a->value); // Free old cmd 
+			Z_Free(a->value); // Free old cmd
 			a->value = newcmd;
 			return;
 		}
diff --git a/src/d_player.h b/src/d_player.h
index 5f5bf53d63f04f356aee6850752ac51126e38d3e..3c6df8ec0117c1ff98836f321278aaaf45aa8b20 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -158,7 +158,7 @@ typedef enum
 	PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs
 	PF_CANCARRY    = 1<<29, // Can carry another player?
 	PF_FINISHED    = 1<<30, // The player finished the level. NOT the same as exiting
-	
+
 	// True if shield button down last tic
 	// This may be the final flag, but 2.3 could free up the others
 	PF_SHIELDDOWN    = 1<<31,
diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h
index 43eb0f00b8df58da69c2dc7123d274d69070c104..0f1eca46041037939028690b419c79c30e4e1797 100644
--- a/src/d_ticcmd.h
+++ b/src/d_ticcmd.h
@@ -28,7 +28,7 @@ typedef enum
 {
 	// First 3 bits are weapon change info, DO NOT USE!
 	BT_WEAPONMASK = 0x07,  //our first three bits.
-	
+
 	BT_SHIELD     = 1<<3,  // shield or super action
 
 	BT_WEAPONNEXT = 1<<4,  // select next weapon
@@ -41,7 +41,7 @@ typedef enum
 	BT_TOSSFLAG   = 1<<10, // toss flag or emeralds
 	BT_JUMP       = 1<<11, // jump action
 	BT_FIRENORMAL = 1<<12, // fire a normal ring no matter what
-	
+
 	// custom lua buttons
 	BT_CUSTOM1    = 1<<13,
 	BT_CUSTOM2    = 1<<14,
diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c
index ab872713a850be2a8b8ca9cf86c121594b34f16f..643e24f5afb677f450dab073097388661c35c98a 100644
--- a/src/dedicated/i_system.c
+++ b/src/dedicated/i_system.c
@@ -1573,4 +1573,3 @@ boolean I_GetTextInputMode(void)
 }
 
 #include "../sdl/dosstr.c"
-
diff --git a/src/dedicated/i_video.c b/src/dedicated/i_video.c
index 2c998117accb71be25850438bdac2ee6c4db0509..19f2d0cbd51bba44266ca0b92627b542cb8c948b 100644
--- a/src/dedicated/i_video.c
+++ b/src/dedicated/i_video.c
@@ -1,4 +1,4 @@
-#include "../doomdef.h"
+#include "../doomdef.h"
 #include "../command.h"
 #include "../i_video.h"
 
@@ -76,4 +76,3 @@ void I_ReadScreen(UINT8 *scr)
 void I_BeginRead(void){}
 
 void I_EndRead(void){}
-
diff --git a/src/deh_tables.c b/src/deh_tables.c
index 8fa32558baf8338d68a485ea6ef0b64edfb78db4..744b52d36b76d409f6265cae6be5244547d84857 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -3371,7 +3371,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 
 	"S_SPEEDWINGS",
 	"S_SPEEDWINGSD",
-	
+
 	"S_PARTICLEPICKUP1",
 	"S_PARTICLEPICKUP2",
 	"S_1000SCOREAWARD",
diff --git a/src/f_finale.c b/src/f_finale.c
index 06db0b44f5edaecca1888470879afec0bfd975b0..119e6daba7290ae61d66a8c15b71c7268aa19dcc 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -3658,7 +3658,7 @@ static void F_DrawContinueCharacter(INT32 dx, INT32 dy, UINT8 n)
 		(
 			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)
+			(INT32)(contskins[n]->skinnum), 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
 		);
 	}
@@ -3724,7 +3724,7 @@ void F_ContinueDrawer(void)
 	else if (ncontinues > 10)
 	{
 		if (!(continuetime & 1) || continuetime > 17)
-			V_DrawContinueIcon(x, 68, 0, (INT32)(&contskins[0] - skins), contColors[0]);
+			V_DrawContinueIcon(x, 68, 0, contskins[0]->skinnum, contColors[0]);
 		V_DrawScaledPatch(x+12, 66, 0, stlivex);
 		V_DrawRightAlignedString(x+38, 64, 0,
 			va("%d",(imcontinuing ? ncontinues-1 : ncontinues)));
@@ -3738,7 +3738,7 @@ void F_ContinueDrawer(void)
 		{
 			if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17))
 				continue;
-			V_DrawContinueIcon(x - (i*30), 68, 0, (INT32)(&contskins[0] - skins), contColors[0]);
+			V_DrawContinueIcon(x - (i*30), 68, 0, contskins[0]->skinnum, contColors[0]);
 		}
 		x = BASEVIDWIDTH>>1;
 	}
diff --git a/src/filesrch.c b/src/filesrch.c
index 67a2e8976f88548c0f6f77b2143fbef6888d820f..7f104f8cac58ba1e109605b5b0598f14b3a86ce6 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -698,7 +698,7 @@ static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
 		dirpathindex[depthleft]--;
 }
 
-//sortdir by name? 
+//sortdir by name?
 static int lumpnamecompare(const void *A, const void *B)
 {
 	const lumpinfo_t *pA = A;
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index e426bcdddf56d36c3796c101d4b3a628b964ed5b..a5befe112c60bc704e58b3c3467944b2dd1ed971 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -2491,16 +2491,16 @@ static void HWR_Subsector(size_t num)
 			rover; rover = rover->next)
 		{
 			fixed_t bottomCullHeight, topCullHeight, centerHeight;
-			
+
 			if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES))
 				continue;
 			if (sub->validcount == validcount)
 				continue;
-			
+
 			// rendering heights for bottom and top planes
 			bottomCullHeight = P_GetFFloorBottomZAt(rover, viewx, viewy);
 			topCullHeight = P_GetFFloorTopZAt(rover, viewx, viewy);
-			
+
 			if (gl_frontsector->cullheight)
 			{
 				if (HWR_DoCulling(gl_frontsector->cullheight, viewsector->cullheight, gl_viewz, FIXED_TO_FLOAT(*rover->bottomheight), FIXED_TO_FLOAT(*rover->topheight)))
@@ -3105,7 +3105,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 	// baseWallVerts is used to know the final shape to easily get the vertex
 	// co-ordinates
 	memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
-	
+
 	fixed_t newalpha = spr->mobj->alpha;
 
 	// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
@@ -3150,7 +3150,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 		blend = HWR_GetBlendModeFlag(blendmode)|occlusion;
 		if (!occlusion) use_linkdraw_hack = true;
 	}
-	
+
 	Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
 
 	if (HWR_UseShader())
@@ -3349,7 +3349,7 @@ static void HWR_DrawBoundingBox(gl_vissprite_t *vis)
 		v[15].y = v[16].y = v[17].y = v[21].y = v[22].y = v[23].y = vis->gzt; // top
 
 	Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj));
-	
+
 	HWR_ProcessPolygon(&Surf, v, 24, (cv_renderhitboxgldepth.value ? 0 : PF_NoDepthTest)|PF_Modulated|PF_NoTexture|PF_WireFrame, SHADER_NONE, false);
 }
 
@@ -3645,7 +3645,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
 			blend = HWR_GetBlendModeFlag(blendmode)|occlusion;
 			if (!occlusion) use_linkdraw_hack = true;
 		}
-		
+
 		Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
 
 		if (spr->renderflags & RF_SHADOWEFFECTS)
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 011b478e58c38c95813dfe8170a7facaa2fa178d..931867142200338b7635d7b04307df587eafa129 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1373,7 +1373,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		// Apparently people don't like jump frames like that, so back it goes
 		if (tics > durs)
 			durs = tics;
-		
+
 		// Make linkdraw objects use their tracer's alpha value
 		fixed_t newalpha = spr->mobj->alpha;
 		if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
@@ -1392,7 +1392,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff;
 			Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode);
 		}
-		
+
 		Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
 
 		// don't forget to enable the depth test because we can't do this
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index e11dd4f166cb8e068cc8fb99d2e2bd0661832755..02a32957a2b940ac15490c0e83fb57658da24c5e 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -713,7 +713,7 @@ EXPORT boolean HWRAPI(InitShaders) (void)
 #ifdef GL_SHADERS
 	if (!pglUseProgram)
 		return false;
-	
+
 	gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER);
 	gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER);
 
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 081a30ef8f6ffee18b73766a491134356dbc85ab..7f2560bcc4adc2f398d87aa8066119ee9ec3b455 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -590,6 +590,45 @@ static void Command_CSay_f(void)
 UINT8 spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent.
 tic_t spam_tics[MAXPLAYERS];
 
+static const char *GetChatColorFromSkinColor(INT32 skincolor)
+{
+	const char *textcolor = NULL;
+	UINT16 chatcolor = skincolors[skincolor].chatcolor;
+	if (!chatcolor || chatcolor%0x1000 || chatcolor>V_INVERTMAP)
+		textcolor = "\x80";
+	else if (chatcolor == V_MAGENTAMAP)
+		textcolor = "\x81";
+	else if (chatcolor == V_YELLOWMAP)
+		textcolor = "\x82";
+	else if (chatcolor == V_GREENMAP)
+		textcolor = "\x83";
+	else if (chatcolor == V_BLUEMAP)
+		textcolor = "\x84";
+	else if (chatcolor == V_REDMAP)
+		textcolor = "\x85";
+	else if (chatcolor == V_GRAYMAP)
+		textcolor = "\x86";
+	else if (chatcolor == V_ORANGEMAP)
+		textcolor = "\x87";
+	else if (chatcolor == V_SKYMAP)
+		textcolor = "\x88";
+	else if (chatcolor == V_PURPLEMAP)
+		textcolor = "\x89";
+	else if (chatcolor == V_AQUAMAP)
+		textcolor = "\x8a";
+	else if (chatcolor == V_PERIDOTMAP)
+		textcolor = "\x8b";
+	else if (chatcolor == V_AZUREMAP)
+		textcolor = "\x8c";
+	else if (chatcolor == V_BROWNMAP)
+		textcolor = "\x8d";
+	else if (chatcolor == V_ROSYMAP)
+		textcolor = "\x8e";
+	else if (chatcolor == V_INVERTMAP)
+		textcolor = "\x8f";
+	return textcolor;
+}
+
 /** Receives a message, processing an ::XD_SAY command.
   * \sa DoSayCommand
   * \author Graue <graue@oceanbase.org>
@@ -710,51 +749,27 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
 		{
 			if (players[playernum].ctfteam == 1) // red
 			{
-				cstart = "\x85";
-				textcolor = "\x85";
+				cstart = textcolor = GetChatColorFromSkinColor(skincolor_redteam);
 			}
 			else // blue
 			{
-				cstart = "\x84";
-				textcolor = "\x84";
+				cstart = textcolor = GetChatColorFromSkinColor(skincolor_blueteam);
 			}
 		}
 		else
         {
-			UINT16 chatcolor = skincolors[players[playernum].skincolor].chatcolor;
-
-			if (!chatcolor || chatcolor%0x1000 || chatcolor>V_INVERTMAP)
-				cstart = "\x80";
-			else if (chatcolor == V_MAGENTAMAP)
-				cstart = "\x81";
-			else if (chatcolor == V_YELLOWMAP)
-				cstart = "\x82";
-			else if (chatcolor == V_GREENMAP)
-				cstart = "\x83";
-			else if (chatcolor == V_BLUEMAP)
-				cstart = "\x84";
-			else if (chatcolor == V_REDMAP)
-				cstart = "\x85";
-			else if (chatcolor == V_GRAYMAP)
-				cstart = "\x86";
-			else if (chatcolor == V_ORANGEMAP)
-				cstart = "\x87";
-			else if (chatcolor == V_SKYMAP)
-				cstart = "\x88";
-			else if (chatcolor == V_PURPLEMAP)
-				cstart = "\x89";
-			else if (chatcolor == V_AQUAMAP)
-				cstart = "\x8a";
-			else if (chatcolor == V_PERIDOTMAP)
-				cstart = "\x8b";
-			else if (chatcolor == V_AZUREMAP)
-				cstart = "\x8c";
-			else if (chatcolor == V_BROWNMAP)
-				cstart = "\x8d";
-			else if (chatcolor == V_ROSYMAP)
-				cstart = "\x8e";
-			else if (chatcolor == V_INVERTMAP)
-				cstart = "\x8f";
+			cstart = GetChatColorFromSkinColor(players[playernum].skincolor);
+			if (G_GametypeHasTeams())
+			{
+				if (players[playernum].ctfteam == 1) // red
+				{
+					cstart = GetChatColorFromSkinColor(skincolor_redteam);
+				}
+				else // blue
+				{
+					cstart = GetChatColorFromSkinColor(skincolor_blueteam);
+				}
+			}
         }
 		prefix = cstart;
 
@@ -1289,7 +1304,7 @@ static void HU_drawMiniChat(void)
 
 				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_MONOSPACE|transflag, true, colormap);
 				dx += charwidth;
-				
+
 				if (dx >= boxw-charwidth-2)
 				{
 					dx = 0;
@@ -1540,9 +1555,9 @@ static void HU_DrawChat(void)
 				else if ((n == 1) && !(w_chat[3] == '0') && (!((i == 1) || ((i >= 10) && (i <= 19)))))
 					continue;
 				else if ((n == 2) && !(w_chat[3] == '0') && (!((i == 2) || ((i >= 20) && (i <= 29)))))
-					continue; 
+					continue;
 				else if ((n == 3) && !(w_chat[3] == '0') && (!((i == 3) || ((i >= 30) && (i <= 31)))))
-					continue; 
+					continue;
 				else	// general case.
 					if (i != n) continue;
 			}
diff --git a/src/info.c b/src/info.c
index cf635c0114b16a838503b44752ab83ef7e4d41e8..2ac815134950a1114b4b116843ccfa4b222d9d9d 100644
--- a/src/info.c
+++ b/src/info.c
@@ -3395,7 +3395,7 @@ state_t states[NUMSTATES] =
 	{SPR_MSWB, 3, 1, {NULL}, 0, 0, S_HORIZBLUETRAMPOLINE4, 0},   // S_HORIZBLUETRAMPOLINE3
 	{SPR_MSWB, 2, 1, {NULL}, 0, 0, S_HORIZBLUETRAMPOLINE5, 0},   // S_HORIZBLUETRAMPOLINE4
 	{SPR_MSWB, 1, 1, {NULL}, 0, 0, S_HORIZBLUETRAMPOLINE, 0},   // S_HORIZBLUETRAMPOLINE5
-	
+
 	// Yellow diagonal trampoline
 	{SPR_MDIY, 0, -1, {NULL}, 0, 0, S_NULL, 0},    // S_DIAGYELLOWTRAMPOLINE
 	{SPR_MDIY, 4, 4, {A_Pain}, 0, 0, S_DIAGYELLOWTRAMPOLINE3, 0}, // S_DIAGYELLOWTRAMPOLINE2
@@ -23045,15 +23045,15 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Moss",      {0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f}, SKINCOLOR_BEIGE,     13, V_GREENMAP,  true}, // SKINCOLOR_MOSS
 	{"Azure",     {0x90, 0x90, 0x91, 0x91, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf}, SKINCOLOR_PINK,      5,  V_AZUREMAP,  true}, // SKINCOLOR_AZURE
 	{"Eggplant",  {   4,   8,    11,   11,   16,  195,  195,  195,  196,  186,  187,  187,  254,  254,   30,   31}, SKINCOLOR_ROSEBUSH,  5,  V_PURPLEMAP, true}, // SKINCOLOR_EGGPLANT
-	{"Lavender",  {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_GOLD,      4,  V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER
+	{"Lavender",  {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_HEADLIGHT, 8,  V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER
 
 	// Viv's vivid colours (toast 21/07/17)
 	// Tweaks & additions (Lach, Chrispy, sphere, Alice, MotorRoach & Saneko 26/10/22)
 	{"Ruby",       {0xb0, 0xb0, 0xc9, 0xca, 0xcc, 0x26, 0x27, 0x28, 0x29, 0x2a, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfd}, SKINCOLOR_EMERALD,    10, V_REDMAP,     true}, // SKINCOLOR_RUBY
 	{"Cherry",     { 202,  203,  204,  205,  206,   40,   41,   42,   43,   44,  186,  187,   28,   29,   30,   31}, SKINCOLOR_MIDNIGHT,   10, V_REDMAP,     true}, // SKINCOLOR_CHERRY
 	{"Salmon",     {0xd0, 0xd0, 0xd1, 0xd2, 0x20, 0x21, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e}, SKINCOLOR_FOREST,     6,  V_REDMAP,     true}, // SKINCOLOR_SALMON
-	{"Pepper",     { 210,   32,   33,   34,   35,   35,   36,   37,   38,   39,   41,   43,   45,   45,   46,   47}, SKINCOLOR_MASTER,     8,  V_REDMAP,     true}, // SKINCOLOR_PEPPER
-	{"Red",        {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, SKINCOLOR_GREEN,      10, V_REDMAP,     true}, // SKINCOLOR_RED
+	{"Pepper",     { 210,   32,   33,   34,   35,   35,   36,   37,   38,   39,   41,   43,   45,   45,   46,   47}, SKINCOLOR_GREEN,      10, V_REDMAP,     true}, // SKINCOLOR_PEPPER
+	{"Red",        {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, SKINCOLOR_MASTER,     8,  V_REDMAP,     true}, // SKINCOLOR_RED
 	{"Crimson",    {0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x1f}, SKINCOLOR_ICY,        10, V_REDMAP,     true}, // SKINCOLOR_CRIMSON
 	{"Flame",      {0x31, 0x32, 0x33, 0x36, 0x22, 0x22, 0x25, 0x25, 0x25, 0xcd, 0xcf, 0xcf, 0xc5, 0xc5, 0xc7, 0xc7}, SKINCOLOR_PURPLE,     8,  V_REDMAP,     true}, // SKINCOLOR_FLAME
 	{"Garnet",     {   0,   83,   50,   53,   34,   35,   37,   38,   39,   40,   42,   44,   45,   46,   47,   47}, SKINCOLOR_AQUAMARINE, 6,  V_REDMAP,     true}, // SKINCOLOR_GARNET
@@ -23068,7 +23068,7 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Rust",       {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3f, 0x2c, 0x2d, 0x47, 0x2e, 0x2f, 0x2f}, SKINCOLOR_YOGURT,     8,  V_ORANGEMAP,  true}, // SKINCOLOR_RUST
 	{"Tangerine",  {  81,   83,   64,   64,   51,   52,   53,   54,   56,   58,   60,   61,   63,   45,   46,   47}, SKINCOLOR_OCEAN,      12, V_ORANGEMAP,  true}, // SKINCOLOR_TANGERINE
 	{"Topaz",      {   0,   81,   83,   73,   74,   74,   65,   52,   53,   54,   56,   58,   60,   42,   43,   45}, SKINCOLOR_MOONSTONE,  10, V_YELLOWMAP,  true}, // SKINCOLOR_TOPAZ
-	{"Gold",       {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_LAVENDER,   10, V_YELLOWMAP,  true}, // SKINCOLOR_GOLD
+	{"Gold",       {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_MAUVE,      8,  V_YELLOWMAP,  true}, // SKINCOLOR_GOLD
 	{"Sandy",      {0x53, 0x40, 0x41, 0x42, 0x43, 0xe6, 0xe9, 0xe9, 0xea, 0xec, 0xec, 0xc6, 0xc6, 0xc7, 0xc7, 0xfe}, SKINCOLOR_SKY,        8,  V_YELLOWMAP,  true}, // SKINCOLOR_SANDY
 	{"Goldenrod",  {   0,   80,   81,   81,   83,   73,   73,   64,   65,   66,   67,   68,   69,   62,   44,   45}, SKINCOLOR_MAJESTY,    8,  V_YELLOWMAP,  true}, // SKINCOLOR_GOLDENROD
 	{"Yellow",     {0x52, 0x53, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0xed}, SKINCOLOR_CORNFLOWER, 8,  V_YELLOWMAP,  true}, // SKINCOLOR_YELLOW
@@ -23078,19 +23078,19 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Lime",       {0x50, 0x51, 0x52, 0x53, 0x48, 0xbc, 0xbd, 0xbe, 0xbe, 0xbf, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_MAGENTA,    9,  V_PERIDOTMAP, true}, // SKINCOLOR_LIME
 	{"Peridot",    {0x58, 0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0x5e, 0x5e, 0x5f, 0x5f, 0x77, 0x77}, SKINCOLOR_COBALT,     2,  V_PERIDOTMAP, true}, // SKINCOLOR_PERIDOT
 	{"Apple",      {0x49, 0x49, 0xbc, 0xbd, 0xbe, 0xbe, 0xbe, 0x67, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6d}, SKINCOLOR_RASPBERRY,  13, V_PERIDOTMAP, true}, // SKINCOLOR_APPLE
-	{"Headlight",  {   0,   80,   81,   82,   73,   84,   64,   65,   91,   91,  124,  125,  126,  137,  138,  139}, SKINCOLOR_MAUVE,      8,  V_YELLOWMAP,  true}, // SKINCOLOR_HEADLIGHT
+	{"Headlight",  {   0,   80,   81,   82,   73,   84,   64,   65,   91,   91,  124,  125,  126,  137,  138,  139}, SKINCOLOR_LAVENDER,   10, V_YELLOWMAP,  true}, // SKINCOLOR_HEADLIGHT
 	{"Chartreuse", {  80,   82,   72,   73,  188,  188,  113,  114,  114,  125,  126,  137,  138,  139,  253,  254}, SKINCOLOR_NOBLE,      9,  V_PERIDOTMAP, true}, // SKINCOLOR_CHARTREUSE
-	{"Green",      {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_RED,        6,  V_GREENMAP,   true}, // SKINCOLOR_GREEN
+	{"Green",      {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_PEPPER,     8,  V_GREENMAP,   true}, // SKINCOLOR_GREEN
 	{"Forest",     {0x65, 0x66, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f}, SKINCOLOR_SALMON,     9,  V_GREENMAP,   true}, // SKINCOLOR_FOREST
 	{"Shamrock",   {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, SKINCOLOR_SIBERITE,   10, V_GREENMAP,   true}, // SKINCOLOR_SHAMROCK
-	{"Jade",       { 128,  120,  121,  122,  122,  113,  114,  114,  115,  116,  117,  118,  119,  110,  111,   30}, SKINCOLOR_TAFFY,      10, V_GREENMAP,   true}, // SKINCOLOR_JADE
+	{"Jade",       { 128,  120,  121,  122,  122,  113,  114,  114,  115,  116,  117,  118,  119,  110,  111,   30}, SKINCOLOR_ROSY,       7,  V_GREENMAP,   true}, // SKINCOLOR_JADE
 	{"Mint",       {0x00, 0x00, 0x58, 0x58, 0x59, 0x62, 0x62, 0x62, 0x64, 0x67, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a}, SKINCOLOR_VIOLET,     5,  V_GREENMAP,   true}, // SKINCOLOR_MINT
-	{"Master",     {   0,   80,   88,   96,  112,  113,   99,  100,  124,  125,  126,  117,  107,  118,  119,  111}, SKINCOLOR_PEPPER,     8,  V_GREENMAP,   true}, // SKINCOLOR_MASTER
+	{"Master",     {   0,   80,   88,   96,  112,  113,   99,  100,  124,  125,  126,  117,  107,  118,  119,  111}, SKINCOLOR_RED,        6,  V_GREENMAP,   true}, // SKINCOLOR_MASTER
 	{"Emerald",    {  80,   96,  112,  113,  114,  114,  125,  125,  126,  126,  137,  137,  138,  138,  139,  139}, SKINCOLOR_RUBY,       9,  V_GREENMAP,   true}, // SKINCOLOR_EMERALD
 	{"Seafoam",    {0x01, 0x58, 0x59, 0x5a, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a, 0x8b, 0xfd, 0xfd}, SKINCOLOR_PLUM,       6,  V_AQUAMAP,    true}, // SKINCOLOR_SEAFOAM
 	{"Island",     {  96,   97,  113,  113,  114,  124,  142,  136,  136,  150,  151,  153,  168,  168,  169,  169}, SKINCOLOR_GALAXY,     7,  V_AQUAMAP,    true}, // SKINCOLOR_ISLAND
 	{"Bottle",     {   0,    1,    3,    4,    5,  140,  141,  141,  124,  125,  126,  127,  118,  119,  111,  111}, SKINCOLOR_LATTE,      14, V_AQUAMAP,    true}, // SKINCOLOR_BOTTLE
-	{"Aqua",       {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_ROSY,       7,  V_AQUAMAP,    true}, // SKINCOLOR_AQUA
+	{"Aqua",       {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_TAFFY,      10, V_AQUAMAP,    true}, // SKINCOLOR_AQUA
 	{"Teal",       {0x78, 0x78, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0x8a}, SKINCOLOR_PEACHY,     7,  V_SKYMAP,     true}, // SKINCOLOR_TEAL
 	{"Ocean",      { 120,  121,  122,  122,  123,  141,  142,  142,  136,  137,  138,  138,  139,  139,  253,  253}, SKINCOLOR_TANGERINE,  4,  V_AQUAMAP,    true}, // SKINCOLOR_OCEAN
 	{"Wave",       {0x00, 0x78, 0x78, 0x79, 0x8d, 0x87, 0x88, 0x89, 0x89, 0xae, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfd}, SKINCOLOR_QUAIL,      5,  V_SKYMAP,     true}, // SKINCOLOR_WAVE
@@ -23124,12 +23124,12 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
 	{"Violet",     {0xd0, 0xd1, 0xd2, 0xca, 0xcc, 0xb8, 0xb9, 0xb9, 0xba, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfe, 0xfe}, SKINCOLOR_MINT,       6,  V_MAGENTAMAP, true}, // SKINCOLOR_VIOLET
 	{"Royal",      { 208,  209,  192,  192,  192,  193,  193,  194,  194,  172,  173,  174,  175,  175,  139,  139}, SKINCOLOR_FANCY,      9,  V_PURPLEMAP,  true}, // SKINCOLOR_ROYAL
 	{"Lilac",      {0x00, 0xd0, 0xd1, 0xd2, 0xd3, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xfe, 0x1f}, SKINCOLOR_VAPOR,      4,  V_ROSYMAP,    true}, // SKINCOLOR_LILAC
-	{"Mauve",      { 176,  177,  178,  192,  193,  194,  195,  195,  196,  185,  185,  186,  186,  187,  187,  253}, SKINCOLOR_HEADLIGHT,  8,  V_PURPLEMAP,  true}, // SKINCOLOR_MAUVE
+	{"Mauve",      { 176,  177,  178,  192,  193,  194,  195,  195,  196,  185,  185,  186,  186,  187,  187,  253}, SKINCOLOR_GOLD,       4,  V_PURPLEMAP,  true}, // SKINCOLOR_MAUVE
 	{"Eventide",   {  51,   52,   53,   33,   34,  204,  183,  183,  184,  184,  166,  167,  168,  169,  253,  254}, SKINCOLOR_DAYBREAK,   13, V_MAGENTAMAP, true}, // SKINCOLOR_EVENTIDE
 	{"Plum",       {0xc8, 0xd3, 0xd5, 0xd6, 0xd7, 0xce, 0xcf, 0xb9, 0xb9, 0xba, 0xba, 0xa9, 0xa9, 0xa9, 0xfd, 0xfe}, SKINCOLOR_MINT,       7,  V_ROSYMAP,    true}, // SKINCOLOR_PLUM
 	{"Raspberry",  {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, SKINCOLOR_APPLE,      13, V_ROSYMAP,    true}, // SKINCOLOR_RASPBERRY
-	{"Taffy",      {   1,  176,  176,  177,  178,  179,  202,  203,  204,  204,  205,  206,  207,   44,   45,   46}, SKINCOLOR_JADE,       8,  V_ROSYMAP,    true}, // SKINCOLOR_TAFFY
-	{"Rosy",       {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_AQUA,       1,  V_ROSYMAP,    true}, // SKINCOLOR_ROSY
+	{"Taffy",      {   1,  176,  176,  177,  178,  179,  202,  203,  204,  204,  205,  206,  207,   44,   45,   46}, SKINCOLOR_AQUA,       1,  V_ROSYMAP,    true}, // SKINCOLOR_TAFFY
+	{"Rosy",       {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_JADE,       8,  V_ROSYMAP,    true}, // SKINCOLOR_ROSY
 	{"Fancy",      {   0,  208,   49,  210,  210,  202,  202,  203,  204,  204,  205,  206,  207,  207,  186,  186}, SKINCOLOR_ROYAL,      9,  V_ROSYMAP,    true}, // SKINCOLOR_FANCY
 	{"Sangria",    { 210,   32,   33,   34,   34,  215,  215,  207,  207,  185,  186,  186,  186,  169,  169,  253}, SKINCOLOR_TURQUOISE,  12, V_ROSYMAP,    true}, // SKINCOLOR_SANGRIA
 	{"Volcanic",   {  54,   36,   42,   44,   45,   46,   46,   47,   28,  253,  253,  254,  254,   30,   31,   31}, SKINCOLOR_BRONZE,     9,  V_REDMAP,     true}, // SKINCOLOR_VOLCANIC
diff --git a/src/info.h b/src/info.h
index bf83068877c850457f2f50bd16fa7aee7cbfb3be..225f45f6630317525bd203c9771d7585b6beebc1 100644
--- a/src/info.h
+++ b/src/info.h
@@ -4231,7 +4231,7 @@ typedef enum state
 
 	S_SPEEDWINGS,
 	S_SPEEDWINGSD,
-	
+
 	S_PARTICLEPICKUP1,
 	S_PARTICLEPICKUP2,
 	S_1000SCOREAWARD,
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 0d828df85ede18d44a1d7ad2a7d4afcc68786dbe..ecd1ee55e648019fb883917ca361cc45ba8847b2 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -1987,7 +1987,7 @@ static int lib_pLineIsBlocking(lua_State *L)
 		return LUA_ErrInvalid(L, "mobj_t");
 	if (!line)
 		return LUA_ErrInvalid(L, "line_t");
-	
+
 	// P_LineOpening in P_LineIsBlocking sets these variables.
 	// We want to keep their old values after so that whatever
 	// map collision code uses them doesn't get messed up.
@@ -2000,9 +2000,9 @@ static int lib_pLineIsBlocking(lua_State *L)
 	pslope_t *oldopenbottomslope = openbottomslope;
 	ffloor_t *oldopenfloorrover = openfloorrover;
 	ffloor_t *oldopenceilingrover = openceilingrover;
-	
+
 	lua_pushboolean(L, P_LineIsBlocking(mo, line));
-	
+
 	opentop = oldopentop;
 	openbottom = oldopenbottom;
 	openrange = oldopenrange;
@@ -2012,7 +2012,7 @@ static int lib_pLineIsBlocking(lua_State *L)
 	openbottomslope = oldopenbottomslope;
 	openfloorrover = oldopenfloorrover;
 	openceilingrover = oldopenceilingrover;
-	
+
 	return 1;
 }
 
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index d2b3d96790ffe7a92701d713ffe7def862f8e9c1..c8327658a64cf8b87f7ee281b266e85ef65c4e3e 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -613,6 +613,10 @@ static int libd_getSprite2Patch(lua_State *L)
 	if (super)
 		j |= SPR2F_SUPER;
 
+	// If there is no "super" variation of this sprite, try with the normal one.
+	if (!P_IsValidSprite2(skins[i], j))
+		j &= ~SPR2F_SUPER;
+
 	sprdef = P_GetSkinSpritedef(skins[i], j);
 
 	// set frame number
diff --git a/src/m_cond.c b/src/m_cond.c
index 418b2ff2b1384af7a2231921ec02b100ac71e318..9706f76c83e06c2537bf1d57051ed80f0b3f0f84 100644
--- a/src/m_cond.c
+++ b/src/m_cond.c
@@ -475,7 +475,7 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
 		// that's better than making dedicated server's lives hell.
 		return false;
 	}
-	
+
 	if (cv_debug || devparm)
 		return false; // Unlock every level when in devmode.
 
diff --git a/src/m_menu.c b/src/m_menu.c
index d92f56ffaf795b4a06d07ad78e06de409d634f9d..e345a6a87f3be80dc7da620e7342f9d8efc71287 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -3917,12 +3917,16 @@ void M_StartControlPanel(void)
 	}
 	else if (!(netgame || multiplayer)) // Single Player
 	{
-		// Devmode unlocks Pandora's Box in the pause menu
-		boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) || cv_debug || devparm) && !marathonmode);
+		// Devmode unlocks Pandora's Box and Level Select in the pause menu
+		boolean isforbidden = (marathonmode || ultimatemode);
+		boolean isdebug = ((cv_debug || devparm) && !isforbidden);
+		boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !isforbidden) || isdebug);
+		boolean lselect = ((maplistoption != 0 && !isforbidden) || isdebug);
 
-		if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff.
+		if (gamestate != GS_LEVEL) // intermission, so gray out stuff.
 		{
 			SPauseMenu[spause_pandora].status = (pandora) ? (IT_GRAYEDOUT) : (IT_DISABLED);
+			SPauseMenu[spause_levelselect].status = (lselect) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 			SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
 		}
 		else
@@ -3932,6 +3936,11 @@ void M_StartControlPanel(void)
 				++numlives;
 
 			SPauseMenu[spause_pandora].status = (pandora) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
+			SPauseMenu[spause_levelselect].status = (lselect) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
+			if (ultimatemode)
+			{
+				SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
+			}
 
 			// The list of things that can disable retrying is (was?) a little too complex
 			// for me to want to use the short if statement syntax
@@ -3941,13 +3950,6 @@ void M_StartControlPanel(void)
 				SPauseMenu[spause_retry].status = (IT_STRING | IT_CALL);
 		}
 
-		// We can always use level select though. :33
-		// Guarantee it if we have either it unlocked or devmode is enabled
-		if ((maplistoption != 0 || M_SecretUnlocked(SECRET_LEVELSELECT, serverGamedata) || cv_debug || devparm) && !marathonmode)
-			SPauseMenu[spause_levelselect].status = (IT_STRING | IT_CALL);
-		else
-			SPauseMenu[spause_levelselect].status = (IT_DISABLED);
-
 		// And emblem hints.
 		SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 
@@ -7788,13 +7790,9 @@ static void M_PauseLevelSelect(INT32 choice)
 	SP_PauseLevelSelectDef.prevMenu = currentMenu;
 	levellistmode = LLM_LEVELSELECT;
 
-	// maplistoption is only specified if not set already
-	// and we have the level select unlocked so that it
+	// maplistoption is NOT specified, so that this
 	// transfers the level select list from the menu
 	// used to enter the game to the pause menu.
-	if (maplistoption == 0 && M_SecretUnlocked(SECRET_LEVELSELECT, serverGamedata))
-		maplistoption = 1;
-
 	if (!M_PrepareLevelPlatter(-1, true))
 	{
 		M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
@@ -11373,7 +11371,7 @@ static void M_Refresh(INT32 choice)
 
 	// note: this is the one case where 0 is a valid room number
 	// because it corresponds to "All"
-	CL_UpdateServerList(!(ms_RoomId < 0), ms_RoomId);
+	CL_UpdateServerList(cv_masterserver_room_id.value >= 0, cv_masterserver_room_id.value);
 
 	// first page of servers
 	serverlistpage = 0;
@@ -11459,7 +11457,7 @@ static void M_DrawConnectMenu(void)
 		numPages = 1;
 
 	// Room name
-	if (ms_RoomId < 0)
+	if (cv_masterserver_room_id.value < 0)
 		V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey,
 		                         V_YELLOWMAP, (itemOn == mp_connect_room) ? "<Select to change>" : "<Unlisted Mode>");
 	else
@@ -11687,7 +11685,7 @@ static void M_ConnectMenu(INT32 choice)
 
 	// first page of servers
 	serverlistpage = 0;
-	if (ms_RoomId < 0)
+	if (cv_masterserver_room_id.value < 0)
 	{
 		M_RoomMenu(0); // Select a room instead of staring at an empty list
 		// This prevents us from returning to the modified game alert.
@@ -11783,7 +11781,7 @@ static void M_ChooseRoom(INT32 choice)
 #endif
 
 	if (choice == 0)
-		CV_SetValue(&cv_masterserver_room_id, 0);
+		CV_SetValue(&cv_masterserver_room_id, -1);
 	else
 	{
 		CV_SetValue(&cv_masterserver_room_id, roomIds[choice-1]);
@@ -11855,7 +11853,7 @@ static void M_DrawServerMenu(void)
 	if (currentMenu == &MP_ServerDef)
 	{
 		M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true, false);
-		if (ms_RoomId < 0)
+		if (cv_masterserver_room_id.value < 0)
 			V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
 			                         V_YELLOWMAP, (itemOn == mp_server_room) ? "<Select to change>" : "<Unlisted Mode>");
 		else
@@ -11951,7 +11949,7 @@ static void M_ServerOptions(INT32 choice)
 static void M_StartServerMenu(INT32 choice)
 {
 	(void)choice;
-	ms_RoomId = -1;
+	CV_SetValue(&cv_masterserver_room_id, -1);
 	levellistmode = LLM_CREATESERVER;
 	Newgametype_OnChange();
 	M_SetupNextMenu(&MP_ServerDef);
diff --git a/src/m_random.c b/src/m_random.c
index 536fbfbbd1077abf6ae400bd4d8773a7574e4b08..a063e88f47ccc40f10ffa09d441016d3bd20c13b 100644
--- a/src/m_random.c
+++ b/src/m_random.c
@@ -193,9 +193,9 @@ INT32 M_RandomKey(INT32 a)
   */
 INT32 M_RandomRange(INT32 a, INT32 b)
 {
-  	if (b < a)
+	if (b < a)
 	{
-    	INT32 temp;
+		INT32 temp;
 
 		temp = a;
 		a = b;
diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c
index 067458852e69b1bf1e37d8cd5b6b0de10cc95f27..6702e2591254349a9bd3dde6d08b7fa86ef7fb29 100644
--- a/src/netcode/d_clisrv.c
+++ b/src/netcode/d_clisrv.c
@@ -663,7 +663,7 @@ void D_QuitNetGame(void)
 			if (netnodes[i].ingame)
 				HSendPacket(i, true, 0, 0);
 #ifdef MASTERSERVER
-		if (serverrunning && ms_RoomId > 0)
+		if (serverrunning && cv_masterserver_room_id.value > 0)
 			UnregisterServer();
 #endif
 	}
@@ -797,7 +797,7 @@ void SV_SpawnServer(void)
 		{
 			I_NetOpenSocket();
 #ifdef MASTERSERVER
-			if (ms_RoomId > 0)
+			if (cv_masterserver_room_id.value > 0)
 				RegisterServer();
 #endif
 		}
diff --git a/src/netcode/d_netfil.c b/src/netcode/d_netfil.c
index 313905f438e0203e4d757a1c41b6db596fe48941..bfb67838ff68e3831914e77dd029ffa19942eaac 100644
--- a/src/netcode/d_netfil.c
+++ b/src/netcode/d_netfil.c
@@ -1345,9 +1345,9 @@ void PT_FileFragment(SINT8 node, INT32 netconsole)
 
 	if (!(strcmp(filename, "srb2.pk3")
 		&& strcmp(filename, "zones.pk3")
-		&& strcmp(filename, "player.dta")
+		&& strcmp(filename, "characters.pk3")
 		&& strcmp(filename, "patch.pk3")
-		&& strcmp(filename, "music.dta")
+		&& strcmp(filename, "music.pk3")
 		))
 		I_Error("Tried to download \"%s\"", filename);
 
diff --git a/src/netcode/http-mserv.c b/src/netcode/http-mserv.c
index 4a080498455234f234655f505e4bf0df956dd9a6..8ce20af956008d2e522a08dc0aa98756174252d8 100644
--- a/src/netcode/http-mserv.c
+++ b/src/netcode/http-mserv.c
@@ -426,7 +426,7 @@ HMS_register (void)
 
 	char *title;
 
-	hms = HMS_connect(PROTO_V4, "rooms/%d/register", ms_RoomId);
+	hms = HMS_connect(PROTO_V4, "rooms/%d/register", cv_masterserver_room_id.value);
 
 	if (! hms)
 		return 0;
@@ -462,7 +462,7 @@ HMS_register (void)
 	if (!hms_allow_ipv6)
 		return ok;
 
-	hms = HMS_connect(PROTO_V6, "rooms/%d/register", ms_RoomId);
+	hms = HMS_connect(PROTO_V6, "rooms/%d/register", cv_masterserver_room_id.value);
 
 	if (! hms)
 		return 0;
diff --git a/src/netcode/mserv.c b/src/netcode/mserv.c
index fba36a3babddc507dd9d3c7601682ac50baa7a45..f17db4b6e32e59a08a7ac5c9c3a44e867c0ffff2 100644
--- a/src/netcode/mserv.c
+++ b/src/netcode/mserv.c
@@ -67,9 +67,10 @@ consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://ds.ms.srb2.org/M
 consvar_t cv_servername = CVAR_INIT_WITH_CALLBACKS ("servername", "SRB2 server", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT|CV_ALLOWLUA, NULL, Update_parameters, ServerName_CanChange);
 
 consvar_t cv_masterserver_update_rate = CVAR_INIT ("masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters);
-consvar_t cv_masterserver_room_id = CVAR_INIT ("masterserver_room_id", "0", CV_CALL, CV_Unsigned, RoomId_OnChange);
+CV_PossibleValue_t cv_masterserver_room_values[] = {{-1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
+consvar_t cv_masterserver_room_id = CVAR_INIT ("masterserver_room_id", "-1", CV_CALL, cv_masterserver_room_values, RoomId_OnChange);
 
-INT16 ms_RoomId = 0;
+static INT16 ms_RoomId = -1;
 
 #if defined (MASTERSERVER) && defined (HAVE_THREADS)
 int           ms_QueryId;
@@ -449,7 +450,7 @@ void UnregisterServer(void)
 static boolean
 Online (void)
 {
-	return ( serverrunning && ms_RoomId > 0 );
+	return ( serverrunning && cv_masterserver_room_id.value > 0 );
 }
 
 static inline void SendPingToMasterServer(void)
diff --git a/src/netcode/mserv.h b/src/netcode/mserv.h
index 419c11a89409d7491249d159f669285c344fdee5..ed3c9b27b8f6d9f52b1c8cc4e2640b5501653dff 100644
--- a/src/netcode/mserv.h
+++ b/src/netcode/mserv.h
@@ -71,11 +71,6 @@ extern consvar_t cv_masterserver_timeout;
 extern consvar_t cv_masterserver_debug;
 extern consvar_t cv_masterserver_token;
 
-// < 0 to not connect (usually -1) (offline mode)
-// == 0 to show all rooms, not a valid hosting room
-// anything else is whatever room the MS assigns to that number (online mode)
-extern INT16 ms_RoomId;
-
 #ifdef HAVE_THREADS
 extern int           ms_QueryId;
 extern I_mutex       ms_QueryId_mutex;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 9ebd32069cb84ac3d50c487f595e660813f67f4d..568483d58ff71825ea6f5759b163c10930b80761 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -3922,7 +3922,7 @@ static void P_DoBoss5Death(mobj_t *mo)
 				pole->angle = mo->tracer->angle;
 				pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
 				pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
-				
+
 				P_SetTarget(&pole->tracer, P_SpawnMobj(
 					pole->x, pole->y,
 					pole->z - 256*FRACUNIT,
@@ -8333,7 +8333,7 @@ void A_Shockwave(mobj_t *actor)
 		ang += interval;
 		sprev = shock;
 	}
-	
+
 	S_StartSound(actor, shock->info->seesound);
 }
 
diff --git a/src/p_inter.c b/src/p_inter.c
index 0e63fea1b9500cb8b9d22642bfb9f0d9c7fd2b20..27e612154dc87c1b88fec2e42e890af0d27c382e 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -538,14 +538,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1) && (!(player->powers[pw_strong] & STR_HEAVY)))
 			{
 				fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce
-				
+
 				if (elementalpierce == 2) // Reset bubblewrap, part 1
 					P_DoBubbleBounce(player);
 				toucher->momz = setmomz;
 				if (elementalpierce == 2) // Reset bubblewrap, part 2
 				{
 					boolean underwater = toucher->eflags & MFE_UNDERWATER;
-							
+
 					if (underwater)
 						toucher->momz /= 2;
 					toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height!
@@ -2572,7 +2572,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			if (!(target->flags2 & MF2_DONTRESPAWN))
 			{
 				if (!(netgame || multiplayer))
-					target->fuse = atoi(cv_itemrespawntime.defaultvalue)*TICRATE + 2; 
+					target->fuse = atoi(cv_itemrespawntime.defaultvalue)*TICRATE + 2;
 				else if (cv_itemrespawn.value)
 					target->fuse = cv_itemrespawntime.value*TICRATE + 2;
 			}
diff --git a/src/p_mobj.c b/src/p_mobj.c
index aa846a93c734f872b18dd9b663664095cc20edfb..85ae8b256f3f0d397342b2c5cd03b94cac6dc16c 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -178,27 +178,6 @@ static void P_CycleMobjState(mobj_t *mobj)
 	}
 }
 
-//
-// P_CycleMobjState for players.
-//
-static void P_CyclePlayerMobjState(mobj_t *mobj)
-{
-	// state animations
-	P_CycleStateAnimation(mobj);
-
-	// cycle through states,
-	// calling action functions at transitions
-	if (mobj->tics != -1)
-	{
-		mobj->tics--;
-
-		// you can cycle through multiple states in a tic
-		if (!mobj->tics && mobj->state)
-			if (!P_SetMobjState(mobj, mobj->state->nextstate))
-				return; // freed itself
-	}
-}
-
 //
 // P_SetPlayerMobjState
 // Returns true if the mobj is still present.
@@ -3803,7 +3782,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 	}
 
 animonly:
-	P_CyclePlayerMobjState(mobj);
+	P_CycleMobjState(mobj);
 }
 
 static void CalculatePrecipFloor(precipmobj_t *mobj)
@@ -6660,12 +6639,12 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
 	if (scale < 1) {
 		P_SetScale(thing, thing->target->scale, true);
 		thing->old_scale = thing->target->old_scale;
-		
+
 		thing->flags2 |= (MF2_DONTDRAW|MF2_JUSTATTACKED); //Hide and indicate we're hidden
 	} else {
 		P_SetScale(thing, scale, true);
 		thing->old_scale = FixedMul(thing->target->old_scale, thing->target->player->shieldscale);
-		
+
 		//Only unhide if we were hidden by the above code
 		if (thing->flags2 & MF2_JUSTATTACKED)
 			thing->flags2 &= ~(MF2_DONTDRAW|MF2_JUSTATTACKED);
@@ -6794,6 +6773,12 @@ void P_RunOverlays(void)
 		else
 			zoffs = 0;
 
+		// hide the overlay as well if we're part of a hidden shield
+		if ((mo->target->flags2 & (MF2_JUSTATTACKED|MF2_DONTDRAW)) == (MF2_JUSTATTACKED|MF2_DONTDRAW))
+			mo->flags2 |= (MF2_DONTDRAW|MF2_JUSTATTACKED);
+		else if (mo->flags2 & MF2_JUSTATTACKED)
+			mo->flags2 &= ~(MF2_DONTDRAW|MF2_JUSTATTACKED);
+
 		P_UnsetThingPosition(mo);
 		mo->x = mo->target->x;
 		mo->y = mo->target->y;
@@ -10334,10 +10319,7 @@ void P_MobjThinker(mobj_t *mobj)
 	}
 
 	// Can end up here if a player dies.
-	if (mobj->player)
-		P_CyclePlayerMobjState(mobj);
-	else
-		P_CycleMobjState(mobj);
+	P_CycleMobjState(mobj);
 
 	if (P_MobjWasRemoved(mobj))
 		return;
@@ -11020,13 +11002,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				mcsolid->angle = mobj->angle + ANGLE_90;
 			}
 			break;
-		case MT_TORCHFLOWER:
-			{
-				mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME);
-				if (!P_MobjWasRemoved(fire))
-					P_SetTarget(&mobj->target, fire);
-				break;
-			}
 		case MT_PYREFLY:
 			mobj->extravalue1 = (FixedHypot(mobj->x, mobj->y)/FRACUNIT) % 360;
 			mobj->extravalue2 = 0;
@@ -13019,6 +12994,13 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 			}
 		}
 		break;
+	case MT_TORCHFLOWER:
+		{
+			mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME);
+			if (!P_MobjWasRemoved(fire))
+				P_SetTarget(&mobj->target, fire);
+			break;
+		}
 	case MT_CANDLE:
 	case MT_CANDLEPRICKET:
 		if (mthing->args[0])
diff --git a/src/p_slopes.c b/src/p_slopes.c
index 7f070e2a1793b4d02a44fefa374f4a887a8da4a1..7390329369b4b5dfbb9b084e4396234f99b1fb57 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -181,7 +181,7 @@ void T_DynamicSlopeLine (dynlineplanethink_t* th)
 {
 	pslope_t* slope = th->slope;
 	line_t* srcline = th->sourceline;
-	
+
 	fixed_t zdelta, oldoz = slope->o.z;
 
 	switch(th->type) {
diff --git a/src/p_spec.c b/src/p_spec.c
index e402180fedd857156d4183bd3d982d457e94f7c4..529a60a10ca20cd5ee5a4c968cadf26ea71e7a93 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -2406,7 +2406,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					z = line->args[4] << FRACBITS;
 
 					P_SetOrigin(mo, mo->x + x, mo->y + y, mo->z + z);
-					
+
 					if (mo->player)
 					{
 						if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3
diff --git a/src/p_user.c b/src/p_user.c
index bb5d8f44fb9d4b5ecb51ab84edc6691e9eedbafe..5fc77106a2f121c5b574388f9d1847a3ccbda5f6 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -978,7 +978,7 @@ boolean P_PlayerInPain(player_t *player)
 {
 	if (P_MobjWasRemoved(player->mo))
 		return false;
-		
+
 	// no silly, sliding isn't pain
 	if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing])
 		return true;
diff --git a/src/r_bbox.c b/src/r_bbox.c
index 8ccad2bb58186098810f299405fc0f4d23fa9b5a..93fa2dca28c4a1f923c69ff4f44958c7e583310c 100644
--- a/src/r_bbox.c
+++ b/src/r_bbox.c
@@ -275,7 +275,7 @@ boolean R_ThingBoundingBoxVisible(mobj_t *thing)
 	switch (thing->type)
 	{
 		default:
-			// First person / awayviewmobj -- rendering a bbox 
+			// First person / awayviewmobj -- rendering a bbox
 			// too close to the viewpoint causes anomalies
 			// and these are exactly on the viewpoint!
 			if (thing != r_viewmobj)
diff --git a/src/r_main.c b/src/r_main.c
index ee05876da1395f4375515457e552b36cffcfd486..46bac9dc76a1886cb3ddc60167772312721b6a53 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1095,7 +1095,7 @@ void R_SetupFrame(player_t *player)
 	camera_t *thiscam;
 	boolean chasecam = R_ViewpointHasChasecam(player);
 	boolean ispaused = paused || P_AutoPause();
-	
+
 	if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
 		thiscam = &camera2;
 	else
@@ -1375,7 +1375,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
 		chasecam = true; // force chasecam on
 	else if (player->spectator) // no spectator chasecam
 		chasecam = false; // force chasecam off
-		
+
 	if (chasecam && !thiscam->chase)
 	{
 		P_ResetCamera(player, thiscam);
@@ -1386,7 +1386,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
 		P_ResetCamera(player, thiscam);
 		thiscam->chase = false;
 	}
-	
+
 	if (isplayer2)
 	{
 		R_SetViewContext(VIEWCONTEXT_PLAYER2);
diff --git a/src/r_textures.c b/src/r_textures.c
index bd22a2df13443e7596b303704eecae93281ab418..4c52f75ebe169607d8f367bf07c03bc7f2eb70af 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -1110,7 +1110,7 @@ static lumpnum_t W_GetTexPatchLumpNum(const char *name)
 
 	lumpnum_t lump = LUMPERROR;
 	INT32 lump_type_it;
-	
+
 
 	for (lump_type_it = 0; lump_type_it < USE__MAX; lump_type_it++)
 	{
@@ -1716,7 +1716,7 @@ const char *R_CheckTextureNameForNum(INT32 num)
 {
 	if (num > 0 && num < numtextures)
 		return textures[num]->name;
-	
+
 	return "-";
 }
 
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index 99425108e69b3761fd03de7790d02232e44bb898..8950846ee4f43cf794bd6d2505bbf039e6c71d2f 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -14,8 +14,13 @@ target_sources(SRB2SDL2 PRIVATE
 
 # Compatibility flag with later versions of GCC
 # We should really fix our code to not need this
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
-    target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+if (NOT SRB2_CONFIG_FORCE_NO_MS_BITFIELDS)
+	if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+		check_cxx_compiler_flag("-mno-ms-bitfields" HAS_NO_MS_BITFIELDS)
+		if(HAS_NO_MS_BITFIELDS)
+			target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+		endif()
+	endif()
 endif()
 
 # Yes we know we use insecure CRT functions...
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 391d038a4a129b5334bdfb566edf29f76e253ead..23f2f3b291f5adca0d0b105dc0b27719a1d13dd8 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -2822,7 +2822,7 @@ static void ST_overlayDrawer(void)
 		}
 		else if (cv_powerupdisplay.value == 2 && LUA_HudEnabled(hud_powerups))
 			ST_drawPowerupHUD();  // same as it ever was...
-		
+
 	}
 	else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2 && LUA_HudEnabled(hud_powerups))
 		ST_drawPowerupHUD(); // same as it ever was...
diff --git a/src/string.c b/src/string.c
index c5d95b224fffd63b43d0682ae0a05408844271d6..79573283e10bee24ef70a394899c6f5585f67521 100644
--- a/src/string.c
+++ b/src/string.c
@@ -83,7 +83,7 @@ char *xstrtok(char *line, const char *delims)
 		return NULL;
 
 	p = saveline; // save start of this token
-	
+
 	saveline += strcspn(saveline, delims); // get the number of non-delims characters, go past delimiter
 
 	if(*saveline != '\0') // trash the delim if necessary
@@ -91,4 +91,3 @@ char *xstrtok(char *line, const char *delims)
 
 	return p;
 }
-
diff --git a/src/v_video.c b/src/v_video.c
index 42a4aaa009bc32584d553f1182ec31badebf0a42..39a1001d199952077fc783875b4d104c819a8fcd 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1137,7 +1137,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
 	}
 #endif
 
-	
+
 
 	if (splitscreen && (c & V_PERPLAYER))
 	{
@@ -1953,7 +1953,7 @@ char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *
 	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
 	slen = strlen(string);
-	
+
 	if (w == 0)
 		w = BASEVIDWIDTH;
 	w -= x;
@@ -2131,7 +2131,7 @@ void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t
 				lx = x - (V_FontStringWidth(line, option, font)*pscale);
 				break;
 		}
-		
+
 		V_DrawFontStringAtFixed(lx, ly, option, pscale, vscale, line, font);
 
 		ly += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, vscale);
@@ -2422,7 +2422,7 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 			if (wline < w) wline = w;
 			w = 0;
 			continue;
-		}	
+		}
 		if (string[i] & 0x80)
 			continue;
 
@@ -2455,7 +2455,7 @@ INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font)
 			{
 				result += (option & V_RETURN8) ? 8 : font.linespacing;
 				h = 0;
-			}	
+			}
 			continue;
 		}
 
diff --git a/src/y_inter.c b/src/y_inter.c
index 331a3da386bb37c7d37d18e68861821bd6e6f9e2..086c0d860582ecaa8ee210431c17e7d4cdcdc21c 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -1623,6 +1623,7 @@ static void Y_CalculateMatchWinners(void)
 	boolean completed[MAXPLAYERS];
 
 	// Initialize variables
+	memset(data.match.ctfteam, 0, sizeof (data.match.ctfteam));
 	memset(data.match.scores, 0, sizeof (data.match.scores));
 	memset(data.match.color, 0, sizeof (data.match.color));
 	memset(data.match.character, 0, sizeof (data.match.character));
@@ -1643,8 +1644,15 @@ static void Y_CalculateMatchWinners(void)
 
 			if (players[i].score >= data.match.scores[data.match.numplayers] && completed[i] == false)
 			{
+				data.match.ctfteam[data.match.numplayers] = players[i].ctfteam;
 				data.match.scores[data.match.numplayers] = players[i].score;
 				data.match.color[data.match.numplayers] = &players[i].skincolor;
+				if (data.match.ctfteam[data.match.numplayers] == 1) // red team
+					data.match.color[data.match.numplayers] = &skincolor_redteam;
+
+				if (data.match.ctfteam[data.match.numplayers] == 2) // blue team
+					data.match.color[data.match.numplayers] = &skincolor_blueteam;
+
 				data.match.character[data.match.numplayers] = &players[i].skin;
 				data.match.name[data.match.numplayers] = player_names[i];
 				data.match.spectator[data.match.numplayers] = players[i].spectator;
@@ -1688,7 +1696,6 @@ static void Y_CalculateTimeRaceWinners(void)
 
 			if (players[i].realtime <= data.match.scores[data.match.numplayers] && completed[i] == false)
 			{
-				data.match.ctfteam[data.match.numplayers] = players[i].ctfteam;
 				data.match.scores[data.match.numplayers] = players[i].realtime;
 				data.match.color[data.match.numplayers] = &players[i].skincolor;
 				data.match.character[data.match.numplayers] = &players[i].skin;
@@ -2067,7 +2074,7 @@ static void Y_AwardCoopBonuses(void)
 				(bonuses_list[bonusnum][j])(&players[i], &localbonuses[j]);
 			else
 				Y_SetNullBonus(&players[i], &localbonuses[j]);
-			
+
 			players[i].score += localbonuses[j].points;
 			if (players[i].score > MAXSCORE)
 				players[i].score = MAXSCORE;
diff --git a/thirdparty/curl.cmake b/thirdparty/curl.cmake
index 5c3aa26e35882d64ca8a6cf99517d28e9fc56dcc..7b6c3a299f951139fe18e0c25d18074d0deae300 100644
--- a/thirdparty/curl.cmake
+++ b/thirdparty/curl.cmake
@@ -55,4 +55,3 @@ else()
 endif()
 
 FetchContent_MakeAvailable(curl)
-
diff --git a/thirdparty/sdl2-mixer-ext.cmake b/thirdparty/sdl2-mixer-ext.cmake
index a52b11584ae747630ed4c44af6282fb8cc9dea75..1998a7bd9217c2bdfd9da5f1b5de544e48cd6c5d 100644
--- a/thirdparty/sdl2-mixer-ext.cmake
+++ b/thirdparty/sdl2-mixer-ext.cmake
@@ -36,4 +36,3 @@ FetchContent_Declare(
 )
 
 FetchContent_MakeAvailable(SDL2_mixer_ext)
-
diff --git a/thirdparty/zlib.cmake b/thirdparty/zlib.cmake
index 257609f775ae9f7c325665198f0e8804a5cb6030..50c567dda9e664632c709fc374276c401ee59203 100644
--- a/thirdparty/zlib.cmake
+++ b/thirdparty/zlib.cmake
@@ -33,4 +33,3 @@ FetchContent_MakeAvailable(ZLIB)
 add_library(ZLIB::ZLIB ALIAS zlibstatic)
 
 set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib" "${zlib_BINARY_DIR}" CACHE PATH "" FORCE)
-