diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b21ce1b00313089705addb772b455a8308d21795..29f5ef5fff9f1bc4afb83006c65f54088762e6dc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,848 +1,19 @@
-variables:
-  GIT_STRATEGY: clone
-  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
-
-default:
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:stable
-
-  cache:
-    - key: ccache-$CI_PROJECT_PATH_SLUG-$CI_JOB_NAME_SLUG
-      fallback_keys:
-        - cache-$CI_PROJECT_PATH_SLUG-$CI_DEFAULT_BRANCH
-        - cache-$CI_PROJECT_PATH_SLUG-default
-      paths:
-        - ccache
-        - ccache_statslog
-
-    - key: apt-$CI_JOB_IMAGE
-      paths:
-        - apt-cache
-      unprotect: true
-
-    - key: apk-$CI_JOB_IMAGE
-      paths:
-        - apk-cache
-      unprotect: true
-
-  before_script:
-    - - |
-         # debconf
-         echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
-      - export DEBIAN_FRONTEND="noninteractive"
-      - export DEBIAN_PRIORITY="low"
-      - export DEBCONF_NONINTERACTIVE_SEEN="true"
-      - |
-          # debconf
-          echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
-    - - |
-          # dpkg_aa
-          echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
-      - dpkg --add-architecture i386
-      - dpkg --add-architecture amd64
-      - dpkg --add-architecture arm64
-      - |
-          # dpkg_aa
-          echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
-    - - |
-          # apt_conf
-          echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
-      - export APT_CACHE_DIR=`pwd`/apt-cache
-      - mkdir --parents --verbose $APT_CACHE_DIR/partial/
-      - touch /etc/apt/apt.conf.d/99build
-      - |
-          # apt.conf
-          echo Adding options to apt.conf':'
-      - |
-          # APT::Install-Recommends
-          echo APT::Install-Recommends "false"\;       | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # quit
-          echo quiet "1"\;                             | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # APT::Get::Assume-Yes
-          echo APT::Get::Assume-Yes "true"\;           | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # Dir::Cache::Archives
-          echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
-      - |
-          # apt_conf
-          echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
-    - - |
-          # apt_update
-          echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
-      - apt-get update
-      - |
-          # apt_update
-          echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
-
-    - - |
-          # apt_pre
-          echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
-      - apt-get install apt-utils
-      - |
-          # apt_pre
-          echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
-
-    - - |
-          # apt_upgrade
-          echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
-      - apt-get upgrade
-      - |
-          # apt_update
-          echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
+include:
+  - '.gitlab/ci/templates/*.yml'
+  - '.gitlab/ci/jobs/*.yml'
 
-    - - |
-          # apt_common
-          echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apt-get install make git ccache nasm cmake ca-certificates
-      - |
-          # apt_common
-          echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
+workflow:
+  auto_cancel:
+    on_new_commit: interruptible
 
-    - - |
-          # ccache_config
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
-      - mkdir --parents --verbose ~/.ccache/
-      - touch ~/.ccache/ccache.conf
-      - |
-          # cache.conf
-          echo Adding ccache configution option
-      - |
-          # base_dir
-          echo base_dir = $PWD                  | tee --append ~/.ccache/ccache.conf
-      - |
-          # cache_dir
-          echo cache_dir = $PWD/ccache          | tee --append ~/.ccache/ccache.conf
-      - |
-          # compiler_check
-          echo compiler_check = content         | tee --append ~/.ccache/ccache.conf
-      - |
-          # stats_log
-          echo stats_log = $PWD/ccache_statslog | tee --append ~/.ccache/ccache.conf
-      - |
-          # max_size
-          echo max_size = 50M                   | tee --append ~/.ccache/ccache.conf
-      - |
-          # ccache_config
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
-
-    - - |
-          # cache_reset
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
-      - ccache --zero-stats
-      - ccache --show-stats
-      - |
-          # ccache_reset
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME_SLUG"
-
-  after_script:
-    - - |
-           # apt_clean
-           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
-      - apt-get autoclean
-      - |
-          # apt_clean
-          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
-
-    - - |
-          # ccache_stats
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
-      - ccache --show-stats
-      - ccache --show-log-stats || true
-      - |
-          # ccahe_stats
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
+variables:
+  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
+  GIT_DEPTH: 20
 
 stages:
   - build
 
-Debian testing GCC:
-  stage: build
-
-  when: manual
-
-  image: debian:testing-slim
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "testing-gcc"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
-
-  variables:
-    CC: gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Windows x86:
-  stage: build
-
-  when: on_success
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Win32"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
-
-  variables:
-    PREFIX: i686-w64-mingw32
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-mingw-w64-i686-win32
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:amd64:
-  stage: build
-
-  when: on_success
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian amd64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
-
-  variables:
-    CC: x86_64-linux-gnu-gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-    OBJCOPY: x86_64-linux-gnu-objcopy
-    OBJDUMP: x86_64-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian oldstable:amd64:
-  extends: Debian stable:amd64
-
-  when: manual
-
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old amd64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:i386:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian i386"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
-
-  variables:
-    CC: i686-linux-gnu-gcc
-    OBJCOPY: i686-linux-gnu-objcopy
-    OBJDUMP: i686-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable:arm64:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
-
-  variables:
-    CC: aarch64-linux-gnu-gcc
-    LDFLAGS: -Wl,-fuse-ld=gold
-    OBJCOPY: aarch64-linux-gnu-objcopy
-    OBJDUMP: aarch64-linux-gnu-objdump
-    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian oldstable:arm64:
-  extends: Debian stable:arm64
-
-  when: manual
-
-  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-batocera:arm64:
-  extends: Debian stable:arm64
-
-  when: manual
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Debian old arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Windows x64:
-  stage: build
-
-  when: manual
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Win64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
-
-  variables:
-    PREFIX: x86_64-w64-mingw32
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install gcc-mingw-w64-x86-64-win32
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian stable Clang:
-  stage: build
-
-  when: on_success
-
-  allow_failure: false
-
-  artifacts:
-    paths:
-      - "build.clang/bin/"
-      - "build.clang/src/config.h"
-    expose_as: "clang"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    CC: clang
-    CXX: clang
-    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
-    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-  script:
-    - - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apt-get install clang
-      - |
-          # apt_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
-
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
-
-    - - |
-          # cmake
-          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.clang -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_USE_LIBGME:BOOL=OFF -G "Unix Makefiles"
-      - |
-          # cmake
-          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.clang --keep-going || make --directory=build.clang --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-Debian testing Clang:
-  extends: Debian stable Clang
-
-  when: manual
-
-  allow_failure: true
-
-  image: debian:testing-slim
-
-  artifacts:
-    paths:
-      - "build.clang/bin/"
-      - "build.clang/src/config.h"
-    expose_as: "testing-clang"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
-
-  variables:
-    CC: clang
-    CXX: clang
-    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
-    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
-    LDFLAGS: -Wl,-fuse-ld=gold
-
-Alpine 3 GCC:
-  stage: build
-
-  when: on_success
-
-  image: alpine:3
-
-  allow_failure: true
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Apline-3"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
-
-  before_script:
-    - - |
-          # apk_cache
-          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
-      - export APK_CACHE_DIR=`pwd`/apk-cache
-      - mkdir --parents --verbose $APK_CACHE_DIR/
-      - ln -sf /etc/apk/cache $APK_CACHE_DIR
-      - |
-          # apk_cache
-          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
-
-    - - |
-          # apk_update
-          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
-      - apk update
-      - |
-          # apk_update
-          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
-
-    - - |
-          # apk_upgrade
-          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
-      - apk upgrade
-      - |
-          # apk_update
-          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
-
-    - - |
-          # apk_common
-          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
-      - apk add make git ccache nasm
-      - |
-          # apk_common
-          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
-
-    - - |
-          # ccache_config
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
-      - mkdir --parents --verbose ~/.ccache/
-      - touch ~/.ccache/ccache.conf
-      - |
-          # cache.conf
-          echo Adding ccache configution option
-      - |
-          # base_dir
-          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
-      - |
-          # cache_dir
-          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
-      - |
-          # compiler_check
-          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
-      - |
-          # stats_log
-          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
-      - |
-          # max_size
-          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
-      - |
-          # ccache_config
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
-
-    - - |
-          # cache_reset
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
-      - ccache --zero-stats
-      - ccache --show-stats
-      - |
-          # ccache_reset
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
-
-  script:
-    - - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
-      - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
-
-    - - |
-          # apk_development
-          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
-      - |
-          # apk_development
-          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-  after_script:
-    - - |
-           # apk_clean
-           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
-      - apk cache clean
-      - |
-          # apk_clean
-          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
-
-    - - |
-          # ccache_stats
-          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
-      - ccache --show-stats --verbose
-      - ccache --show-log-stats --verbose
-      - |
-          # ccahe_stats
-          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
-
-Alpine 3 GCC Dedicated:
-  extends: Alpine 3 GCC
-
-  artifacts:
-    paths:
-      - "bin/"
-      - "src/comptime.h"
-    expose_as: "Apline-3-Dedicated"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
-
-  script:
-    - - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
-      - apk add gcc
-      - |
-          # apk_toolchain
-          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
-
-    - - |
-          # apk_development
-          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
-      - apk add musl-dev libpng-dev curl-dev
-      - |
-          # apk_development
-          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-osxcross x86_64:
-  stage: build
-
-  artifacts:
-    paths:
-      - "build.osxcross/bin/"
-      - "build.osxcross/src/config.h"
-    expose_as: "Mac x86_64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    OSXCROSS_HOST: x86_64-apple-darwin21.4
-    LD: x86_64-apple-darwin21.4-ld
-
-  script:
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
-      - osxcross-macports install curl libopenmpt libsdl2_mixer
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-osxcross arm64:
-  stage: build
-
-  when: manual
-
-  allow_failure: true
-
+default:
+  interruptible: true
   artifacts:
-    paths:
-      - "build.osxcross/bin/"
-      - "build.osxcross/src/config.h"
-    expose_as: "Mac arm64"
-    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
-
-  variables:
-    OSXCROSS_HOST: arm64-apple-darwin21.4
-    LD: arm64-apple-darwin21.4-ld
-
-  script:
-    - - |
-          # apt_development
-          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
-      - osxcross-macports install --arm64 curl libopenmpt libsdl2_mixer
-      - |
-          # apt_development
-          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KBuilding Makefiles"
-      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
-
-    - - |
-          # make
-          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
-      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
-      - |
-          # make
-          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+    expire_in: 1 day
diff --git a/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml b/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
new file mode 100644
index 0000000000000000000000000000000000000000..242ddd0eaa3f0e45504fa0fe258e08c63e0845df
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc-dedicated.yml
@@ -0,0 +1,34 @@
+Alpine 3 GCC Dedicated:
+  extends: Alpine 3 GCC
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3-Dedicated"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3-Dedicated"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add musl-dev libpng-dev curl-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 DEDICATED=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/alpine-3-gcc.yml b/.gitlab/ci/jobs/alpine-3-gcc.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b3b12e40167a568e3ced2abc7a09ed0045e0cc99
--- /dev/null
+++ b/.gitlab/ci/jobs/alpine-3-gcc.yml
@@ -0,0 +1,135 @@
+Alpine 3 GCC:
+  stage: build
+
+  when: manual
+
+  image: alpine:3
+
+  allow_failure: true
+
+  cache:
+    - key: apk-$CI_JOB_IMAGE
+      paths:
+        - apk-cache
+      unprotect: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Apline-3"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Apline-3"
+
+  before_script:
+    - - |
+          # apk_cache
+          echo -e "\e[0Ksection_start:`date +%s`:apk_cache[collapsed=true]\r\e[0KUpdating APK listing"
+      - export APK_CACHE_DIR=`pwd`/apk-cache
+      - mkdir --parents --verbose $APK_CACHE_DIR/
+      - ln -sf /etc/apk/cache $APK_CACHE_DIR
+      - |
+          # apk_cache
+          echo -e "\e[0Ksection_end:`date +%s`:apk_cache\r\e[0K"
+
+    - - |
+          # apk_update
+          echo -e "\e[0Ksection_start:`date +%s`:apk_update[collapsed=true]\r\e[0KUpdating APK listing"
+      - apk update
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_update\r\e[0K"
+
+    - - |
+          # apk_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apk_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apk upgrade
+      - |
+          # apk_update
+          echo -e "\e[0Ksection_end:`date +%s`:apk_upgrade\r\e[0K"
+
+    - - |
+          # apk_common
+          echo -e "\e[0Ksection_start:`date +%s`:apk_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apk add make git ccache nasm
+      - |
+          # apk_common
+          echo -e "\e[0Ksection_end:`date +%s`:apk_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $PWD                  | tee -a ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $PWD/ccache          | tee -a ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content         | tee -a ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $PWD/ccache_statslog | tee -a ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 50M                   | tee -a ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  script:
+    - - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apk_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apk add gcc
+      - |
+          # apk_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apk_toolchain\r\e[0K"
+
+    - - |
+          # apk_development
+          echo -e "\e[0Ksection_start:`date +%s`:apk_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apk add musl-dev sdl2_mixer-dev libpng-dev curl-dev libgme-dev libopenmpt-dev miniupnpc-dev
+      - |
+          # apk_development
+          echo -e "\e[0Ksection_end:`date +%s`:apk_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 NOEXECINFO=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+  after_script:
+    - - |
+           # apk_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apk_clean[collapsed=true]\r\e[0KCleaning of unneeded APK packages"
+      - apk cache clean
+      - |
+          # apk_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apk_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats --verbose
+      - ccache --show-log-stats --verbose
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/.gitlab/ci/jobs/batocera-arm64.yml b/.gitlab/ci/jobs/batocera-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3e43aa8753a0a1500abdc52e9f594863bd4b3691
--- /dev/null
+++ b/.gitlab/ci/jobs/batocera-arm64.yml
@@ -0,0 +1,38 @@
+batocera:arm64:
+  extends: Debian stable:arm64
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-batocera-aarch64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-amd64.yml b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3929ecdcd10f8f448072d2c859de6a7dd31d94c7
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-amd64.yml
@@ -0,0 +1,40 @@
+Debian oldstable:amd64:
+  extends: Debian stable:amd64
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old amd64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-x86-64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-oldstable-arm64.yml b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b18d538cd0824041650f3f8a5361b7b07c85f206
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-oldstable-arm64.yml
@@ -0,0 +1,40 @@
+Debian oldstable:arm64:
+  extends: Debian stable:arm64
+
+  when: manual
+
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:oldstable
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian old arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-old-aarch64"
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 NOGME=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1 NOGME=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-amd64.yml b/.gitlab/ci/jobs/debian-stable-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4a757afe0d519f268bb4541cda49ba03a3181600
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-amd64.yml
@@ -0,0 +1,45 @@
+Debian stable:amd64:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian amd64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
+
+  variables:
+    CC: x86_64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: x86_64-linux-gnu-objcopy
+    OBJDUMP: x86_64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
+
+  when: on_success
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 libminiupnpc-dev:amd64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-arm64.yml b/.gitlab/ci/jobs/debian-stable-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..879391affebe7586e019e7bb7f8d77a0599983e2
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-arm64.yml
@@ -0,0 +1,45 @@
+Debian stable:arm64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
+
+  variables:
+    CC: aarch64-linux-gnu-gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+    OBJCOPY: aarch64-linux-gnu-objcopy
+    OBJDUMP: aarch64-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 libminiupnpc-dev:arm64
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 ARM64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 ARM64=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-clang-amd64.yml b/.gitlab/ci/jobs/debian-stable-clang-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4686c1849196d3be6cbee936c1ad910c0f93627c
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-clang-amd64.yml
@@ -0,0 +1,55 @@
+Debian stable Clang:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  allow_failure: false
+
+  artifacts:
+    paths:
+      - "build.clang/bin/"
+      - "build.clang/src/config.h"
+    expose_as: "clang"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    CC: clang
+    CXX: clang
+    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
+    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install clang
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.clang -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_USE_LIBGME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # cmake
+          echo -e "\e[0Ksection_end:`date +%s`:cmake\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.clang --keep-going || make --directory=build.clang --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-stable-i386.yml b/.gitlab/ci/jobs/debian-stable-i386.yml
new file mode 100644
index 0000000000000000000000000000000000000000..cd6206e55e9a497d7065d3ea652c1ed3c6bd8d23
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-stable-i386.yml
@@ -0,0 +1,44 @@
+Debian stable:i386:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Debian i386"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
+
+  variables:
+    CC: i686-linux-gnu-gcc
+    OBJCOPY: i686-linux-gnu-objcopy
+    OBJDUMP: i686-linux-gnu-objdump
+    PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-i686-linux-gnu || apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 libminiupnpc-dev:i386
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/debian-testing-clang-amd64.yml b/.gitlab/ci/jobs/debian-testing-clang-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dc790b397f2187b47a75c05bcf3e5973d5a175e1
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-clang-amd64.yml
@@ -0,0 +1,22 @@
+Debian testing Clang:
+  extends: Debian stable Clang
+
+  when: manual
+
+  allow_failure: true
+
+  image: debian:testing-slim
+
+  artifacts:
+    paths:
+      - "build.clang/bin/"
+      - "build.clang/src/config.h"
+    expose_as: "testing-clang"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
+
+  variables:
+    CC: clang
+    CXX: clang
+    WFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
+    CFLAGS: -Wno-cast-align -Wno-implicit-const-int-float-conversion -Werror -Wno-deprecated-non-prototype -Wno-single-bit-bitfield-constant-conversion
+    LDFLAGS: -Wl,-fuse-ld=gold
diff --git a/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..10799b3053e45a3d98fcfa1f63281e36ebadae9d
--- /dev/null
+++ b/.gitlab/ci/jobs/debian-testing-gcc-amd64.yml
@@ -0,0 +1,46 @@
+Debian testing GCC:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  image: debian:testing-slim
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "testing-gcc"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
+
+  variables:
+    CC: gcc
+    LDFLAGS: -Wl,-fuse-ld=gold
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
+      - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev libminiupnpc-dev
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-arm64.yml b/.gitlab/ci/jobs/macos-arm64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3928413610a048460dfe05d0dfc8f92e9da76848
--- /dev/null
+++ b/.gitlab/ci/jobs/macos-arm64.yml
@@ -0,0 +1,44 @@
+osxcross arm64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "build.osxcross/bin/"
+      - "build.osxcross/src/config.h"
+    expose_as: "Mac arm64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    OSXCROSS_HOST: arm64-apple-darwin21.4
+    LD: arm64-apple-darwin21.4-ld
+
+  script:
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
+      - osxcross-macports install --arm64 curl libopenmpt libsdl2_mixer
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/macos-x86_64.yml b/.gitlab/ci/jobs/macos-x86_64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..818028e49a43624f3e29a357d7d7614ef4dd5118
--- /dev/null
+++ b/.gitlab/ci/jobs/macos-x86_64.yml
@@ -0,0 +1,40 @@
+osxcross x86_64:
+  extends: .srb2ci
+
+  stage: build
+
+  artifacts:
+    paths:
+      - "build.osxcross/bin/"
+      - "build.osxcross/src/config.h"
+    expose_as: "Mac x86_64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
+
+  variables:
+    OSXCROSS_HOST: x86_64-apple-darwin21.4
+    LD: x86_64-apple-darwin21.4-ld
+
+  script:
+    - - |
+          # apt_development
+          echo -e "\e[0Ksection_start:`date +%s`:macports_development[collapsed=true]\r\e[0KInstalling development packages"
+      - osxcross-macports install curl libopenmpt libsdl2_mixer
+      - |
+          # apt_development
+          echo -e "\e[0Ksection_end:`date +%s`:macports_development\r\e[0K"
+
+    - - |
+          # cmake
+          echo -e "\e[0Ksection_start:`date +%s`:cmake[collapsed=false]\r\e[0KBuilding Makefiles"
+      - cmake -B build.osxcross --toolchain /osxcross/toolchain.cmake -DCPM_USE_LOCAL_PACKAGES:BOOL=ON -DOPENMPT_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/include" -DSDL2_INCLUDE_DIR:PATH="/osxcross/macports/pkgs/opt/local/lib" -DSRB2_CONFIG_ENABLE_TESTS:BOOL=OFF -DSRB2_CONFIG_SYSTEM_LIBRARIES:BOOL=ON -DSRB2_CONFIG_USE_GME:BOOL=OFF -G "Unix Makefiles"
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=build.osxcross --keep-going || make --directory=build.osxcross --keep-going
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x64.yml b/.gitlab/ci/jobs/windows-x64.yml
new file mode 100644
index 0000000000000000000000000000000000000000..da8d960bd1330229a2265ed9b015a487f1040e75
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x64.yml
@@ -0,0 +1,35 @@
+Windows x64:
+  extends: .srb2ci
+
+  stage: build
+
+  when: manual
+
+  allow_failure: true
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win64"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
+
+  variables:
+    PREFIX: x86_64-w64-mingw32
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-x86-64-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/jobs/windows-x86.yml b/.gitlab/ci/jobs/windows-x86.yml
new file mode 100644
index 0000000000000000000000000000000000000000..311c767bbd9cd31d1063a248f68c0a6793dd47d5
--- /dev/null
+++ b/.gitlab/ci/jobs/windows-x86.yml
@@ -0,0 +1,35 @@
+Windows x86:
+  extends: .srb2ci
+
+  stage: build
+
+  when: on_success
+
+  artifacts:
+    paths:
+      - "bin/"
+      - "src/comptime.h"
+    expose_as: "Win32"
+    name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
+
+  variables:
+    PREFIX: i686-w64-mingw32
+    CC: /usr/bin/i686-w64-mingw32-gcc-posix
+    CXX: /usr/bin/i686-w64-mingw32-g++-posix
+
+  script:
+    - - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
+      - apt-get install gcc-mingw-w64-i686-win32
+      - |
+          # apt_toolchain
+          echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
+
+    - - |
+          # make
+          echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
+      - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
+      - |
+          # make
+          echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
diff --git a/.gitlab/ci/templates/srb2ci.yml b/.gitlab/ci/templates/srb2ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3716d9df921407cb29081af301a5b6a3d92db459
--- /dev/null
+++ b/.gitlab/ci/templates/srb2ci.yml
@@ -0,0 +1,145 @@
+.srb2ci:
+  image: git.do.srb2.org:5050/stjr/srb2ci/srb2ci:stable
+
+  cache:
+    - key: ccache-$CI_JOB_NAME_SLUG-$CI_COMMIT_REF_SLUG
+      fallback_keys:
+        - ccache-$CI_JOB_NAME_SLUG-$CI_DEFAULT_BRANCH
+        - ccache-$CI_JOB_NAME_SLUG-master
+      paths:
+        - build/ccache
+        - build/ccache_statslog
+
+    - key: apt-$CI_JOB_IMAGE
+      paths:
+        - build/apt-cache
+      unprotect: true
+
+  before_script:
+    - - |
+         # debconf
+         echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
+      - export DEBIAN_FRONTEND="noninteractive"
+      - export DEBIAN_PRIORITY="low"
+      - export DEBCONF_NONINTERACTIVE_SEEN="true"
+      - |
+          # debconf
+          echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
+    - - |
+          # dpkg_aa
+          echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
+      - dpkg --add-architecture i386
+      - dpkg --add-architecture amd64
+      - dpkg --add-architecture arm64
+      - |
+          # dpkg_aa
+          echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
+    - - |
+          # apt_conf
+          echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
+      - export APT_CACHE_DIR=$CI_PROJECT_DIR/build/apt-cache
+      - mkdir --parents --verbose $APT_CACHE_DIR/partial/
+      - touch /etc/apt/apt.conf.d/99build
+      - |
+          # apt.conf
+          echo Adding options to apt.conf':'
+      - |
+          # APT::Install-Recommends
+          echo APT::Install-Recommends "false"\;       | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # quit
+          echo quiet "1"\;                             | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # APT::Get::Assume-Yes
+          echo APT::Get::Assume-Yes "true"\;           | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # Dir::Cache::Archives
+          echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
+      - |
+          # apt_conf
+          echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
+    - - |
+          # apt_update
+          echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
+      - apt-get update
+      - |
+          # apt_update
+          echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
+
+    - - |
+          # apt_pre
+          echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
+      - apt-get install apt-utils
+      - |
+          # apt_pre
+          echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
+
+    - - |
+          # apt_upgrade
+          echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
+      - apt-get upgrade
+      - |
+          # apt_update
+          echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
+
+    - - |
+          # apt_common
+          echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
+      - apt-get install make git ccache nasm cmake ca-certificates
+      - |
+          # apt_common
+          echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
+
+    - - |
+          # ccache_config
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
+      - mkdir --parents --verbose ~/.ccache/
+      - touch ~/.ccache/ccache.conf
+      - |
+          # cache.conf
+          echo Adding ccache configution option
+      - |
+          # base_dir
+          echo base_dir = $CI_PROJECT_DIR                        | tee --append ~/.ccache/ccache.conf
+      - |
+          # cache_dir
+          echo cache_dir = $CI_PROJECT_DIR/build/ccache          | tee --append ~/.ccache/ccache.conf
+      - |
+          # compiler_check
+          echo compiler_check = content                          | tee --append ~/.ccache/ccache.conf
+      - |
+          # stats_log
+          echo stats_log = $CI_PROJECT_DIR/build/ccache_statslog | tee --append ~/.ccache/ccache.conf
+      - |
+          # max_size
+          echo max_size = 300M                                   | tee --append ~/.ccache/ccache.conf
+      - |
+          # ccache_config
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
+
+    - - |
+          # cache_reset
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
+      - ccache --zero-stats
+      - ccache --show-stats
+      - |
+          # ccache_reset
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
+
+  after_script:
+    - - |
+           # apt_clean
+           echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
+      - apt-get autoclean
+      - |
+          # apt_clean
+          echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
+
+    - - |
+          # ccache_stats
+          echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
+      - ccache --show-stats
+      - ccache --show-log-stats || true
+      - |
+          # ccahe_stats
+          echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg
index aee7a70e4e0a4b806d8c0a055d77f06fce476ea6..90c85cdea40827970a7b44222e9a2f6a5e2668f6 100644
--- a/extras/conf/udb/Includes/SRB222_common.cfg
+++ b/extras/conf/udb/Includes/SRB222_common.cfg
@@ -39,6 +39,7 @@ common
 	defaulttexturescale = 1.0f;
 	defaultflatscale = 1.0f;
 	scaledtextureoffsets = true;
+	scaledflatoffsets = true;
 
 	// Colormap/fade related options
 	maxcolormapalpha = 25;
diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index e297f473fd46d2848f3835765988bb913147e84f..fc505fb6025b02782d1a309b247f569a63dd96fd 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -7,13 +7,11 @@ udmf
 		0
 		{
 			title = "None";
-			prefix = "(0)";
 		}
 		
 		6
 		{
 			title = "Sector Set Portal";
-			prefix = "(6)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -52,7 +50,6 @@ udmf
 		7
 		{
 			title = "Sector Flat Alignment";
-			prefix = "(7)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -70,7 +67,6 @@ udmf
 		10
 		{
 			title = "Culling Plane";
-			prefix = "(10)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -91,20 +87,17 @@ udmf
 		40
 		{
 			title = "Visual Portal Between Tagged Linedefs";
-			prefix = "(40)";
 		}
 
 		41
 		{
 			title = "Horizon Effect";
 			id = "srb2_horizonline";
-			prefix = "(41)";
 		}
 
 		63
 		{
 			title = "Fake Floor/Ceiling Planes";
-			prefix = "(63)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -120,7 +113,6 @@ udmf
 		2
 		{
 			title = "Custom Exit";
-			prefix = "(2)";
 			arg0
 			{
 				title = "Next map";
@@ -144,7 +136,6 @@ udmf
 		3
 		{
 			title = "Zoom Tube Parameters";
-			prefix = "(3)";
 			arg0
 			{
 				title = "Speed";
@@ -166,7 +157,6 @@ udmf
 		4
 		{
 			title = "Speed Pad Parameters";
-			prefix = "(4)";
 			arg0
 			{
 				title = "Speed";
@@ -193,7 +183,6 @@ udmf
 		8
 		{
 			title = "Set Camera Collision Planes";
-			prefix = "(8)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -204,7 +193,6 @@ udmf
 		11
 		{
 			title = "Rope Hang Parameters";
-			prefix = "(11)";
 			arg0
 			{
 				title = "Speed";
@@ -226,7 +214,6 @@ udmf
 		14
 		{
 			title = "Bustable Block Parameters";
-			prefix = "(14)";
 			arg0
 			{
 				title = "Debris spacing";
@@ -252,13 +239,11 @@ udmf
 		15
 		{
 			title = "Fan Particle Generator Heights";
-			prefix = "(15)";
 		}
 
 		16
 		{
 			title = "Minecart Parameters";
-			prefix = "(16)";
 			arg0
 			{
 				title = "Order";
@@ -268,7 +253,6 @@ udmf
 		64
 		{
 			title = "Continuously Appearing/Disappearing FOF";
-			prefix = "(64)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -307,7 +291,6 @@ udmf
 		20
 		{
 			title = "PolyObject First Line";
-			prefix = "(20)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -348,7 +331,6 @@ udmf
 		30
 		{
 			title = "Waving PolyObject Flag";
-			prefix = "(30)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -369,7 +351,6 @@ udmf
 		31
 		{
 			title = "Move PolyObject by Front Sector Displacement";
-			prefix = "(31)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -385,7 +366,6 @@ udmf
 		32
 		{
 			title = "Rotate PolyObject by Front Sector Displacement";
-			prefix = "(32)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -421,7 +401,6 @@ udmf
 		52
 		{
 			title = "Continuously Falling Sector";
-			prefix = "(52)";
 			arg0
 			{
 				title = "Speed";
@@ -442,7 +421,6 @@ udmf
 		53
 		{
 			title = "Continuous Plane Mover (Slowdown)";
-			prefix = "(53)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -477,7 +455,6 @@ udmf
 		56
 		{
 			title = "Continuous Plane Mover (Constant)";
-			prefix = "(56)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -512,7 +489,6 @@ udmf
 		60
 		{
 			title = "Activate Moving Platform";
-			prefix = "(60)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -542,7 +518,6 @@ udmf
 		61
 		{
 			title = "Ceiling Crusher";
-			prefix = "(61)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -573,7 +548,6 @@ udmf
 		66
 		{
 			title = "Move Planes by Front Sector Displacement";
-			prefix = "(66)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -600,7 +574,6 @@ udmf
 		70
 		{
 			title = "Add Raise Thinker";
-			prefix = "(70)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -626,7 +599,6 @@ udmf
 		71
 		{
 			title = "Add Air Bobbing Thinker";
-			prefix = "(71)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -652,7 +624,6 @@ udmf
 		72
 		{
 			title = "Add Thwomp Thinker";
-			prefix = "(72)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -679,7 +650,6 @@ udmf
 		73
 		{
 			title = "Add Laser Thinker";
-			prefix = "(73)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -696,7 +666,6 @@ udmf
 		74
 		{
 			title = "Make FOF Bustable";
-			prefix = "(74)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -735,7 +704,6 @@ udmf
 		75
 		{
 			title = "Make FOF Quicksand";
-			prefix = "(75)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -755,7 +723,6 @@ udmf
 		76
 		{
 			title = "Make FOF Bouncy";
-			prefix = "(76)";
 			arg0
 			{
 				title = "Control linedef tag";
@@ -775,7 +742,6 @@ udmf
 		100
 		{
 			title = "Solid";
-			prefix = "(100)";
 			id = "srb2_fofsolid";
 			arg0
 			{
@@ -819,7 +785,6 @@ udmf
 		120
 		{
 			title = "Water";
-			prefix = "(120)";
 			id = "srb2_fofwater";
 			arg0
 			{
@@ -857,7 +822,6 @@ udmf
 		150
 		{
 			title = "Air Bobbing";
-			prefix = "(150)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -884,7 +848,6 @@ udmf
 		160
 		{
 			title = "Water Bobbing";
-			prefix = "(160)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -896,7 +859,6 @@ udmf
 		170
 		{
 			title = "Crumbling";
-			prefix = "(170)";
 			id = "srb2_fofcrumbling";
 			arg0
 			{
@@ -939,7 +901,6 @@ udmf
 		190
 		{
 			title = "Rising";
-			prefix = "(190)";
 			id = "srb2_fofsolid";
 			arg0
 			{
@@ -998,7 +959,6 @@ udmf
 		200
 		{
 			title = "Light Block";
-			prefix = "(200)";
 			id = "srb2_foflight";
 			arg0
 			{
@@ -1016,7 +976,6 @@ udmf
 		202
 		{
 			title = "Fog Block";
-			prefix = "(202)";
 			id = "srb2_foffog";
 			arg0
 			{
@@ -1028,7 +987,6 @@ udmf
 		220
 		{
 			title = "Intangible";
-			prefix = "(220)";
 			id = "srb2_fofintangible";
 			arg0
 			{
@@ -1066,7 +1024,6 @@ udmf
 		223
 		{
 			title = "Intangible, Invisible";
-			prefix = "(223)";
 			id = "srb2_fofintangibleinvisible";
 			arg0
 			{
@@ -1078,7 +1035,6 @@ udmf
 		250
 		{
 			title = "Mario Block";
-			prefix = "(250)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1100,7 +1056,6 @@ udmf
 		251
 		{
 			title = "Thwomp Block";
-			prefix = "(251)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1128,7 +1083,6 @@ udmf
 		254
 		{
 			title = "Bustable Block";
-			prefix = "(254)";
 			id = "srb2_fofbustable";
 			arg0
 			{
@@ -1181,7 +1135,6 @@ udmf
 		257
 		{
 			title = "Quicksand";
-			prefix = "(257)";
 			id = "srb2_fofsolidopaque";
 			arg0
 			{
@@ -1208,7 +1161,6 @@ udmf
 		258
 		{
 			title = "Laser";
-			prefix = "(258)";
 			id = "srb2_foflaser";
 			arg0
 			{
@@ -1242,7 +1194,6 @@ udmf
 		259
 		{
 			title = "Custom";
-			prefix = "(259)";
 			id = "srb2_fofcustom";
 			arg0
 			{
@@ -1307,7 +1258,6 @@ udmf
 		300
 		{
 			title = "Basic";
-			prefix = "(300)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1319,7 +1269,6 @@ udmf
 		303
 		{
 			title = "Ring Count";
-			prefix = "(303)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1347,7 +1296,6 @@ udmf
 		305
 		{
 			title = "Character Ability";
-			prefix = "(305)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1383,7 +1331,6 @@ udmf
 		308
 		{
 			title = "Gametype";
-			prefix = "(308)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1441,7 +1388,6 @@ udmf
 		309
 		{
 			title = "CTF Team";
-			prefix = "(309)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1459,7 +1405,6 @@ udmf
 		313
 		{
 			title = "No More Enemies";
-			prefix = "(313)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1470,7 +1415,6 @@ udmf
 		314
 		{
 			title = "Number of Pushables";
-			prefix = "(314)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1492,7 +1436,6 @@ udmf
 		317
 		{
 			title = "Condition Set Trigger";
-			prefix = "(317)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1508,7 +1451,6 @@ udmf
 		319
 		{
 			title = "Unlockable";
-			prefix = "(319)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1524,7 +1466,6 @@ udmf
 		321
 		{
 			title = "Trigger After X Calls";
-			prefix = "(321)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1550,7 +1491,6 @@ udmf
 		323
 		{
 			title = "NiGHTSerize";
-			prefix = "(323)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1617,7 +1557,6 @@ udmf
 		325
 		{
 			title = "De-NiGHTSerize";
-			prefix = "(325)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1680,7 +1619,6 @@ udmf
 		327
 		{
 			title = "NiGHTS Lap";
-			prefix = "(327)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1732,7 +1670,6 @@ udmf
 		329
 		{
 			title = "Ideya Capture Touch";
-			prefix = "(329)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1800,7 +1737,6 @@ udmf
 		331
 		{
 			title = "Player Skin";
-			prefix = "(331)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1823,7 +1759,6 @@ udmf
 		334
 		{
 			title = "Object Dye";
-			prefix = "(334)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1846,7 +1781,6 @@ udmf
 		337
 		{
 			title = "Emerald Check";
-			prefix = "(337)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1879,7 +1813,6 @@ udmf
 		340
 		{
 			title = "NiGHTS Mare";
-			prefix = "(340)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1901,7 +1834,6 @@ udmf
 		343
 		{
 			title = "Gravity Check";
-			prefix = "(343)";
 			arg0
 			{
 				title = "Trigger type";
@@ -1924,7 +1856,6 @@ udmf
 		399
 		{
 			title = "Level Load";
-			prefix = "(399)";
 		}
 	}
 
@@ -1935,7 +1866,6 @@ udmf
 		400
 		{
 			title = "Set Tagged Sector's Heights/Textures";
-			prefix = "(400)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1958,7 +1888,6 @@ udmf
 		402
 		{
 			title = "Copy Light Level to Tagged Sectors";
-			prefix = "(402)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1980,7 +1909,6 @@ udmf
 		408
 		{
 			title = "Set Tagged Sector's Flats";
-			prefix = "(408)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -1997,7 +1925,6 @@ udmf
 		409
 		{
 			title = "Change Tagged Sector's Tag";
-			prefix = "(409)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2025,7 +1952,6 @@ udmf
 		410
 		{
 			title = "Change Front Sector's Tag";
-			prefix = "(410)";
 			arg0
 			{
 				title = "Tag";
@@ -2048,7 +1974,6 @@ udmf
 		416
 		{
 			title = "Start Adjustable Flickering Light";
-			prefix = "(416)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2077,7 +2002,6 @@ udmf
 		417
 		{
 			title = "Start Adjustable Pulsating Light";
-			prefix = "(417)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2106,7 +2030,6 @@ udmf
 		418
 		{
 			title = "Start Adjustable Blinking Light";
-			prefix = "(418)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2143,7 +2066,6 @@ udmf
 		420
 		{
 			title = "Fade Light Level";
-			prefix = "(420)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2173,7 +2095,6 @@ udmf
 		421
 		{
 			title = "Stop Lighting Effect";
-			prefix = "(421)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2184,7 +2105,6 @@ udmf
 		435
 		{
 			title = "Change Plane Scroller Direction";
-			prefix = "(435)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2200,7 +2120,6 @@ udmf
 		467
 		{
 			title = "Set Tagged Sector's Light Level";
-			prefix = "(467)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2232,7 +2151,6 @@ udmf
 		469
 		{
 			title = "Change Tagged Sector's Gravity";
-			prefix = "(469)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2284,7 +2202,6 @@ udmf
 		403
 		{
 			title = "Move Tagged Sector's Planes";
-			prefix = "(403)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2317,7 +2234,6 @@ udmf
 		405
 		{
 			title = "Move Planes by Set Distance";
-			prefix = "(405)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2349,7 +2265,6 @@ udmf
 		411
 		{
 			title = "Stop Plane Movement";
-			prefix = "(411)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2360,7 +2275,6 @@ udmf
 		428
 		{
 			title = "Start Platform Movement";
-			prefix = "(428)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2394,7 +2308,6 @@ udmf
 		429
 		{
 			title = "Crush Planes Once";
-			prefix = "(429)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2426,7 +2339,6 @@ udmf
 		412
 		{
 			title = "Teleporter";
-			prefix = "(412)";
 			arg0
 			{
 				title = "Destination thing tag";
@@ -2461,7 +2373,6 @@ udmf
 		425
 		{
 			title = "Change Object State";
-			prefix = "(425)";
 			stringarg0
 			{
 				title = "State";
@@ -2472,7 +2383,6 @@ udmf
 		426
 		{
 			title = "Stop Object";
-			prefix = "(426)";
 			arg0
 			{
 				title = "Move to center?";
@@ -2484,7 +2394,6 @@ udmf
 		427
 		{
 			title = "Award Score";
-			prefix = "(427)";
 			arg0
 			{
 				title = "Score";
@@ -2494,7 +2403,6 @@ udmf
 		432
 		{
 			title = "Enable/Disable 2D Mode";
-			prefix = "(432)";
 			arg0
 			{
 				title = "Mode";
@@ -2510,7 +2418,6 @@ udmf
 		433
 		{
 			title = "Enable/Disable Gravity Flip";
-			prefix = "(433)";
 			arg0
 			{
 				title = "Set gravity";
@@ -2546,7 +2453,6 @@ udmf
 		434
 		{
 			title = "Award Power-Up";
-			prefix = "(434)";
 			stringarg0
 			{
 				title = "Power";
@@ -2562,7 +2468,6 @@ udmf
 		437
 		{
 			title = "Disable Player Control";
-			prefix = "(437)";
 			arg0
 			{
 				title = "Time";
@@ -2578,7 +2483,6 @@ udmf
 		438
 		{
 			title = "Change Object Size";
-			prefix = "(438)";
 			arg0
 			{
 				title = "Size (%)";
@@ -2589,7 +2493,6 @@ udmf
 		442
 		{
 			title = "Change Object Type State";
-			prefix = "(442)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2620,7 +2523,6 @@ udmf
 		457
 		{
 			title = "Track Object's Angle";
-			prefix = "(457)";
 			arg0
 			{
 				title = "Anchor tag";
@@ -2651,13 +2553,11 @@ udmf
 		458
 		{
 			title = "Stop Tracking Object's Angle";
-			prefix = "(458)";
 		}
 
 		460
 		{
 			title = "Award Rings";
-			prefix = "(460)";
 			arg0
 			{
 				title = "Rings";
@@ -2671,7 +2571,6 @@ udmf
 		461
 		{
 			title = "Spawn Object";
-			prefix = "(461)";
 			arg0
 			{
 				title = "X position";
@@ -2717,13 +2616,11 @@ udmf
 		462
 		{
 			title = "Stop Timer/Exit Stage in Record Attack";
-			prefix = "(462)";
 		}
 
 		463
 		{
 			title = "Dye Object";
-			prefix = "(463)";
 			stringarg0
 			{
 				title = "Skin color";
@@ -2734,7 +2631,6 @@ udmf
 		464
 		{
 			title = "Trigger Egg Capsule";
-			prefix = "(464)";
 			arg0
 			{
 				title = "Egg Capsule tag";
@@ -2751,7 +2647,6 @@ udmf
 		466
 		{
 			title = "Set Level Failure State";
-			prefix = "(466)";
 			arg0
 			{
 				title = "State";
@@ -2772,7 +2667,6 @@ udmf
 		413
 		{
 			title = "Change Music";
-			prefix = "(413)";
 			arg0
 			{
 				title = "Flags";
@@ -2823,7 +2717,6 @@ udmf
 		414
 		{
 			title = "Play Sound Effect";
-			prefix = "(414)";
 			arg0
 			{
 				title = "Source";
@@ -2863,7 +2756,6 @@ udmf
 		415
 		{
 			title = "Run Script";
-			prefix = "(415)";
 			stringarg0
 			{
 				title = "Lump name";
@@ -2874,7 +2766,6 @@ udmf
 		422
 		{
 			title = "Switch to Cut-Away View";
-			prefix = "(422)";
 			arg0
 			{
 				title = "Viewpoint tag";
@@ -2889,7 +2780,6 @@ udmf
 		423
 		{
 			title = "Change Sky";
-			prefix = "(423)";
 			arg0
 			{
 				title = "Sky number";
@@ -2905,7 +2795,6 @@ udmf
 		424
 		{
 			title = "Change Weather";
-			prefix = "(424)";
 			arg0
 			{
 				title = "Weather";
@@ -2932,7 +2821,6 @@ udmf
 		436
 		{
 			title = "Shatter FOF";
-			prefix = "(436)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -2948,7 +2836,6 @@ udmf
 		439
 		{
 			title = "Change Tagged Linedef's Textures";
-			prefix = "(439)";
 			arg0
 			{
 				title = "Target linedef tag";
@@ -2977,13 +2864,11 @@ udmf
 		440
 		{
 			title = "Start Metal Sonic Race";
-			prefix = "(440)";
 		}
 
 		441
 		{
 			title = "Condition Set Trigger";
-			prefix = "(441)";
 			arg0
 			{
 				title = "Trigger number";
@@ -2993,7 +2878,6 @@ udmf
 		443
 		{
 			title = "Call Lua Function";
-			prefix = "(443)";
 			stringarg0
 			{
 				title = "Function name";
@@ -3004,7 +2888,6 @@ udmf
 		444
 		{
 			title = "Earthquake";
-			prefix = "(444)";
 			arg0
 			{
 				title = "Duration";
@@ -3018,7 +2901,6 @@ udmf
 		445
 		{
 			title = "Make FOF Disappear/Reappear";
-			prefix = "(445)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3044,7 +2926,6 @@ udmf
 		446
 		{
 			title = "Make FOF Crumble";
-			prefix = "(446)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3072,7 +2953,6 @@ udmf
 		447
 		{
 			title = "Change Tagged Sector's Colormap";
-			prefix = "(447)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3108,7 +2988,6 @@ udmf
 		448
 		{
 			title = "Change Skybox";
-			prefix = "(448)";
 			arg0
 			{
 				title = "Viewpoint thing tag";
@@ -3139,7 +3018,6 @@ udmf
 		449
 		{
 			title = "Enable Bosses with Parameter";
-			prefix = "(449)";
 			arg0
 			{
 				title = "Boss ID";
@@ -3159,7 +3037,6 @@ udmf
 		450
 		{
 			title = "Execute Linedef Executor (specific tag)";
-			prefix = "(450)";
 			arg0
 			{
 				title = "Trigger linedef tag";
@@ -3170,7 +3047,6 @@ udmf
 		451
 		{
 			title = "Execute Linedef Executor (random tag in range)";
-			prefix = "(451)";
 			arg0
 			{
 				title = "Start of tag range";
@@ -3186,7 +3062,6 @@ udmf
 		452
 		{
 			title = "Set FOF Translucency";
-			prefix = "(452)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3217,7 +3092,6 @@ udmf
 		453
 		{
 			title = "Fade FOF";
-			prefix = "(453)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3260,7 +3134,6 @@ udmf
 		454
 		{
 			title = "Stop Fading FOF";
-			prefix = "(454)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3282,7 +3155,6 @@ udmf
 		455
 		{
 			title = "Fade Tagged Sector's Colormap";
-			prefix = "(455)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3324,7 +3196,6 @@ udmf
 		456
 		{
 			title = "Stop Fading Tagged Sector's Colormap";
-			prefix = "(456)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3335,7 +3206,6 @@ udmf
 		459
 		{
 			title = "Control Text Prompt";
-			prefix = "(459)";
 			arg0
 			{
 				title = "Prompt number";
@@ -3371,7 +3241,6 @@ udmf
 		465
 		{
 			title = "Set Linedef Executor Delay";
-			prefix = "(465)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3392,7 +3261,6 @@ udmf
 		468
 		{
 			title = "Change Linedef Argument";
-			prefix = "(468)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3422,7 +3290,6 @@ udmf
 		480
 		{
 			title = "PolyObject Door Slide";
-			prefix = "(480)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3446,7 +3313,6 @@ udmf
 		481
 		{
 			title = "PolyObject Door Swing";
-			prefix = "(481)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3471,7 +3337,6 @@ udmf
 		482
 		{
 			title = "Move PolyObject";
-			prefix = "(482)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3497,7 +3362,6 @@ udmf
 		484
 		{
 			title = "Rotate PolyObject";
-			prefix = "(484)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3531,7 +3395,6 @@ udmf
 		488
 		{
 			title = "Move PolyObject by Waypoints";
-			prefix = "(488)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3573,7 +3436,6 @@ udmf
 		489
 		{
 			title = "Set PolyObject Visibility/Tangibility";
-			prefix = "(489)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3606,7 +3468,6 @@ udmf
 		491
 		{
 			title = "Set PolyObject Translucency";
-			prefix = "(491)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3628,7 +3489,6 @@ udmf
 		492
 		{
 			title = "Fade PolyObject Translucency";
-			prefix = "(492)";
 			arg0
 			{
 				title = "PolyObject tag";
@@ -3666,7 +3526,6 @@ udmf
 		500
 		{
 			title = "Scroll Wall";
-			prefix = "(500)";
 			arg0
 			{
 				title = "Side";
@@ -3686,7 +3545,6 @@ udmf
 		502
 		{
 			title = "Scroll Tagged Walls";
-			prefix = "(502)";
 			arg0
 			{
 				title = "Linedef tag";
@@ -3717,7 +3575,6 @@ udmf
 		510
 		{
 			title = "Scroll Planes";
-			prefix = "(510)";
 			arg0
 			{
 				title = "Sector tag";
@@ -3755,7 +3612,6 @@ udmf
 		541
 		{
 			title = "Wind/Current";
-			prefix = "(541)";
 			arg0
 			{
 				title = "Sector tag";
@@ -3800,7 +3656,6 @@ udmf
 		600
 		{
 			title = "Copy Light Level to Tagged Sector's Planes";
-			prefix = "(600)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3817,7 +3672,6 @@ udmf
 		602
 		{
 			title = "Adjustable Pulsating Light";
-			prefix = "(602)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3846,7 +3700,6 @@ udmf
 		603
 		{
 			title = "Adjustable Flickering Light";
-			prefix = "(603)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3875,7 +3728,6 @@ udmf
 		604
 		{
 			title = "Adjustable Blinking Light";
-			prefix = "(604)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3912,7 +3764,6 @@ udmf
 		606
 		{
 			title = "Copy Colormap";
-			prefix = "(606)";
 			arg0
 			{
 				title = "Target sector tag";
@@ -3933,7 +3784,6 @@ udmf
 		700
 		{
 			title = "Create Sector-Based Slope";
-			prefix = "(700)";
 			id = "plane_align";
 			arg0
 			{
@@ -3963,7 +3813,6 @@ udmf
 		704
 		{
 			title = "Create Vertex-Based Slope";
-			prefix = "(704)";
 			id = "srb2_vertexslope";
 			arg0
 			{
@@ -4007,7 +3856,6 @@ udmf
 		720
 		{
 			title = "Copy Slope";
-			prefix = "(720)";
 			id = "plane_copy";
 			arg0
 			{
@@ -4046,7 +3894,6 @@ udmf
 		799
 		{
 			title = "Set Tagged Dynamic Slope Vertex to Front Sector Height";
-			prefix = "(799)";
 			arg0
 			{
 				title = "Apply height";
diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index 0b94a5a87a37a5ce7cf6a2a4c9e5799f7c738eab..37b01d7dd56eadaeb1eb3ae4759fb74efc79e61f 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -590,6 +590,12 @@ universalfields
 			type = 3;
 			default = false;
 		}
+
+		triggertag
+		{
+			type = 0;
+			default = 0;
+		}
 	}
 }
 
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index 990f8dca9f505b57f1797c49ed0d8ae003d18d5d..c028f9439c493d156e1ded87f7a116cc4b14d9d7 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -3938,6 +3938,7 @@ udmf
 			width = 30;
 			height = 32;
 			color = 17;
+			hangs = 1;
 			arg0
 			{
 				title = "Initial delay";
diff --git a/src/console.c b/src/console.c
index 874fc2a4f288eb261a367efd68c488dcd770fb72..69160c24004ca45f1c561d6b205f3ffc1a5a71e5 100644
--- a/src/console.c
+++ b/src/console.c
@@ -922,8 +922,6 @@ static void CON_InputDelChar(void)
 //
 boolean CON_Responder(event_t *ev)
 {
-	static UINT8 consdown = false; // console is treated differently due to rare usage
-
 	// sequential completions a la 4dos
 	static char completioncmd[80 + sizeof("find ")] = "find ";
 	static char *completion = &completioncmd[sizeof("find ")-1];
@@ -943,32 +941,28 @@ boolean CON_Responder(event_t *ev)
 	// let go keyup events, don't eat them
 	if (ev->type != ev_keydown && ev->type != ev_text && ev->type != ev_console)
 	{
-		if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1])
-			consdown = false;
 		return false;
 	}
 
 	key = ev->key;
 
 	// check for console toggle key
-	if (ev->type != ev_console)
+	if (ev->type == ev_keydown)
 	{
 		if (modeattacking || metalrecording || marathonmode)
 			return false;
 
-		if (ev->type == ev_keydown && ((key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) && !shiftdown))
+		if ((key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) && !shiftdown)
 		{
-			if (consdown) // ignore repeat
-				return true;
+			I_SetTextInputMode(con_destlines == 0); // inverse, since this is changed next tic.
 			consoletoggle = true;
-			consdown = true;
 			return true;
 		}
 
 		// check other keys only if console prompt is active
 		if (!consoleready && key < NUMINPUTS) // metzgermeister: boundary check!!
 		{
-			if (ev->type == ev_keydown && !menuactive && bindtable[key])
+			if (!menuactive && bindtable[key])
 			{
 				COM_BufAddText(bindtable[key]);
 				COM_BufAddText("\n");
@@ -980,14 +974,14 @@ boolean CON_Responder(event_t *ev)
 		// escape key toggle off console
 		if (key == KEY_ESCAPE)
 		{
+			I_SetTextInputMode(false);
 			consoletoggle = true;
 			return true;
 		}
 	}
-
-	if (ev->type == ev_text)
+	else if (ev->type == ev_text)
 	{
-		if (!consoletoggle)
+		if (!consoletoggle && consoleready)
 			CON_InputAddChar(key);
 		return true;
 	}
@@ -1036,7 +1030,7 @@ boolean CON_Responder(event_t *ev)
 	}
 	else if (key == KEY_BACKSPACE)
 	{
-		if (ctrldown)
+		if (ctrldown && input_cur != 0)
 		{
 			input_sel = M_JumpWordReverse(inputlines[inputline], input_cur);
 			CON_InputDelSelection();
@@ -1094,7 +1088,9 @@ boolean CON_Responder(event_t *ev)
 
 		if (key == 'x' || key == 'X')
 		{
-			if (input_sel > input_cur)
+			if (input_sel == input_cur) // Don't replace the clipboard without a text selection
+				return true;
+			else if (input_sel > input_cur)
 				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
 			else
 				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
@@ -1104,7 +1100,9 @@ boolean CON_Responder(event_t *ev)
 		}
 		else if (key == 'c' || key == 'C')
 		{
-			if (input_sel > input_cur)
+			if (input_sel == input_cur) // Don't replace the clipboard without a text selection
+				return true;
+			else if (input_sel > input_cur)
 				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
 			else
 				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c
index 858dfaf20234cb6898ffe008bce3c3f76e8b950b..413b366b865c035a08ece29008c30004ea58666e 100644
--- a/src/dedicated/i_system.c
+++ b/src/dedicated/i_system.c
@@ -1585,5 +1585,15 @@ void I_GetCursorPosition(INT32 *x, INT32 *y)
 	(void)y;
 }
 
+void I_SetTextInputMode(boolean active)
+{
+	(void)active;
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return false;
+}
+
 #include "../sdl/dosstr.c"
 
diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c
index ecabe3576d3f15b06513315a945562076587aff5..99bfa9f363ca04c9281b17b0cffeda5cc4314586 100644
--- a/src/dummy/i_system.c
+++ b/src/dummy/i_system.c
@@ -211,5 +211,15 @@ const char *I_GetSysName(void)
 	return NULL;
 }
 
+void I_SetTextInputMode(boolean active)
+{
+	(void)active;
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return false;
+}
+
 #include "../sdl/dosstr.c"
 
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 4e2f3d492974c0027c3b343a075018dc29682d33..16c59d9cf82bb9b92067f3c792a5f29292e7cdfd 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -999,6 +999,7 @@ static void HU_sendChatMessage(void)
 void HU_clearChatChars(void)
 {
 	memset(w_chat, '\0', sizeof(w_chat));
+	I_SetTextInputMode(false);
 	chat_on = false;
 	c_input = 0;
 
@@ -1048,6 +1049,7 @@ boolean HU_Responder(event_t *ev)
 		if ((ev->key == gamecontrol[GC_TALKKEY][0] || ev->key == gamecontrol[GC_TALKKEY][1])
 			&& netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise.
 		{
+			I_SetTextInputMode(true);
 			chat_on = true;
 			chat_on_first_event = false;
 			w_chat[0] = 0;
@@ -1059,6 +1061,7 @@ boolean HU_Responder(event_t *ev)
 		if ((ev->key == gamecontrol[GC_TEAMKEY][0] || ev->key == gamecontrol[GC_TEAMKEY][1])
 			&& netgame && !OLD_MUTE)
 		{
+			I_SetTextInputMode(true);
 			chat_on = true;
 			chat_on_first_event = false;
 			w_chat[0] = 0;
@@ -1133,6 +1136,7 @@ boolean HU_Responder(event_t *ev)
 			if (!CHAT_MUTE)
 				HU_sendChatMessage();
 
+			I_SetTextInputMode(false);
 			chat_on = false;
 			c_input = 0; // reset input cursor
 			chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :)
@@ -1143,6 +1147,7 @@ boolean HU_Responder(event_t *ev)
 			|| c == gamecontrol[GC_TEAMKEY][0] || c == gamecontrol[GC_TEAMKEY][1])
 			&& c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle.
 		{
+			I_SetTextInputMode(false);
 			chat_on = false;
 			c_input = 0; // reset input cursor
 			I_UpdateMouseGrab();
diff --git a/src/i_system.h b/src/i_system.h
index 3f0e05d127fa4ed5ce9aa8fbe89ff109773851f4..f4d169113c50b0ae5e2c1aca53b4d04f128658f4 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -339,4 +339,12 @@ void I_SetMouseGrab(boolean grab);
 */
 const char *I_GetSysName(void);
 
+/** \brief Sets text input mode. When enabled, keyboard inputs will respect dead keys.
+ */
+void I_SetTextInputMode(boolean active);
+
+/** \brief Retrieves current text input mode.
+ */
+boolean I_GetTextInputMode(void);
+
 #endif
diff --git a/src/info.c b/src/info.c
index 9b33a57ab2f863d24f2355b24acdd6ed208e9765..d66c24af81aaafb851e6a83e699d2027add29cb5 100644
--- a/src/info.c
+++ b/src/info.c
@@ -761,12 +761,12 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK, 0},  // S_PLAY_MELEE_LANDING
 
 	// SF_SUPER
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_SUPER_TRANS2, 0}, // S_PLAY_SUPER_TRANS1
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3, 0}, // S_PLAY_SUPER_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4, 0}, // S_PLAY_SUPER_TRANS3
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5, 0}, // S_PLAY_SUPER_TRANS4
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6, 0}, // S_PLAY_SUPER_TRANS5
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL, 0},         // S_PLAY_SUPER_TRANS6
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_ANIMATE,     7, {NULL},          0, 4, S_PLAY_SUPER_TRANS2, 0}, // S_PLAY_SUPER_TRANS1
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3, 0}, // S_PLAY_SUPER_TRANS2
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4, 0}, // S_PLAY_SUPER_TRANS3
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5, 0}, // S_PLAY_SUPER_TRANS4
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6, 0}, // S_PLAY_SUPER_TRANS5
+	{SPR_PLAY, SPR2_TRNS|SPR2F_SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL, 0},         // S_PLAY_SUPER_TRANS6
 
 	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY, 0}, //S_OBJPLACE_DUMMY
 
diff --git a/src/m_menu.c b/src/m_menu.c
index 50011347550c32622238ef02a6d538be62bbb31f..4d8ee17e8a50c582b910a1748d741997515d9457 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -2102,6 +2102,12 @@ menu_t OP_PlaystyleDef = {
 	0, 0, 0, NULL
 };
 
+static void M_UpdateItemOn(void)
+{
+	I_SetTextInputMode((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING ||
+		(currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER);
+}
+
 static void M_VideoOptions(INT32 choice)
 {
 	(void)choice;
@@ -2329,6 +2335,7 @@ void Nextmap_OnChange(void)
 		{
 			currentMenu->lastOn = itemOn;
 			itemOn = nastart;
+			M_UpdateItemOn();
 		}
 	}
 	else if (currentMenu == &SP_TimeAttackDef)
@@ -2378,6 +2385,7 @@ void Nextmap_OnChange(void)
 		{
 			currentMenu->lastOn = itemOn;
 			itemOn = tastart;
+			M_UpdateItemOn();
 		}
 
 		if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0')
@@ -3128,6 +3136,7 @@ static void M_NextOpt(void)
 		else
 			itemOn++;
 	} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
+	M_UpdateItemOn();
 }
 
 static void M_PrevOpt(void)
@@ -3140,6 +3149,7 @@ static void M_PrevOpt(void)
 		else
 			itemOn--;
 	} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
+	M_UpdateItemOn();
 }
 
 // lock out further input in a tic when important buttons are pressed
@@ -3651,12 +3661,14 @@ void M_StartControlPanel(void)
 
 		currentMenu = &MainDef;
 		itemOn = singleplr;
+		M_UpdateItemOn();
 	}
 	else if (modeattacking)
 	{
 		currentMenu = &MAPauseDef;
 		MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 		itemOn = mapause_continue;
+		M_UpdateItemOn();
 	}
 	else if (!(netgame || multiplayer)) // Single Player
 	{
@@ -3703,6 +3715,7 @@ void M_StartControlPanel(void)
 
 		currentMenu = &SPauseDef;
 		itemOn = spause_continue;
+		M_UpdateItemOn();
 	}
 	else // multiplayer
 	{
@@ -3744,6 +3757,7 @@ void M_StartControlPanel(void)
 
 		currentMenu = &MPauseDef;
 		itemOn = mpause_continue;
+		M_UpdateItemOn();
 	}
 
 	CON_ToggleOff(); // move away console
@@ -3837,6 +3851,7 @@ void M_SetupNextMenu(menu_t *menudef)
 			}
 		}
 	}
+	M_UpdateItemOn();
 
 	hidetitlemap = false;
 }
@@ -6109,6 +6124,7 @@ void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtyp
 
 	currentMenu = &MessageDef;
 	itemOn = 0;
+	M_UpdateItemOn();
 }
 
 static void M_DrawMessageMenu(void)
@@ -6183,6 +6199,7 @@ static void M_HandleImageDef(INT32 choice)
 			if (itemOn >= (INT16)(currentMenu->numitems-1))
 				itemOn = 0;
             else itemOn++;
+			M_UpdateItemOn();
 			break;
 
 		case KEY_LEFTARROW:
@@ -6193,6 +6210,7 @@ static void M_HandleImageDef(INT32 choice)
 			if (!itemOn)
 				itemOn = currentMenu->numitems - 1;
 			else itemOn--;
+			M_UpdateItemOn();
 			break;
 
 		case KEY_ESCAPE:
@@ -7389,6 +7407,7 @@ static void M_EmblemHints(INT32 choice)
 	SR_EmblemHintDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&SR_EmblemHintDef);
 	itemOn = 2; // always start on back.
+	M_UpdateItemOn();
 }
 
 static void M_DrawEmblemHints(void)
@@ -10050,6 +10069,7 @@ static void M_TimeAttack(INT32 choice)
 		Nextmap_OnChange();
 
 	itemOn = tastart; // "Start" is selected.
+	M_UpdateItemOn();
 }
 
 // Drawing function for Nights Attack
@@ -10288,6 +10308,7 @@ static void M_NightsAttack(INT32 choice)
 		Nextmap_OnChange();
 
 	itemOn = nastart; // "Start" is selected.
+	M_UpdateItemOn();
 }
 
 // Player has selected the "START" from the nights attack screen
@@ -10607,6 +10628,7 @@ static void M_ModeAttackEndGame(INT32 choice)
 		break;
 	}
 	itemOn = currentMenu->lastOn;
+	M_UpdateItemOn();
 	G_SetGamestate(GS_TIMEATTACK);
 	modeattacking = ATTACKING_NONE;
 	M_ChangeMenuMusic("_title", true);
@@ -10688,6 +10710,7 @@ static void M_Marathon(INT32 choice)
 	titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
 	M_SetupNextMenu(&SP_MarathonDef);
 	itemOn = marathonstart; // "Start" is selected.
+	M_UpdateItemOn();
 	recatkdrawtimer = (50-8) * FRACUNIT;
 	char_scroll = 0;
 }
@@ -11401,6 +11424,7 @@ static void M_ConnectMenu(INT32 choice)
 	else
 		M_SetupNextMenu(&MP_ConnectDef);
 	itemOn = 0;
+	M_UpdateItemOn();
 	M_Refresh(0);
 }
 
@@ -11660,6 +11684,7 @@ static void M_StartServerMenu(INT32 choice)
 	Newgametype_OnChange();
 	M_SetupNextMenu(&MP_ServerDef);
 	itemOn = 1;
+	M_UpdateItemOn();
 }
 
 // ==============
@@ -11842,15 +11867,21 @@ static void M_HandleConnectIP(INT32 choice)
 					case KEY_INS:
 					case 'c':
 					case 'C': // ctrl+c, ctrl+insert, copying
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+						}
 						break;
 
 					case 'x':
 					case 'X': // ctrl+x, cutting
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
-						setupm_ip[0] = 0;
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+							setupm_ip[0] = 0;
+						}
 						break;
 
 					default: // otherwise do nothing
@@ -11874,9 +11905,12 @@ static void M_HandleConnectIP(INT32 choice)
 							break;
 						}
 					case KEY_DEL: // shift+delete, cutting
-						I_ClipboardCopy(setupm_ip, l);
-						S_StartSound(NULL,sfx_menu1); // Tails
-						setupm_ip[0] = 0;
+						if (l != 0) // Don't replace the clipboard without any text
+						{
+							I_ClipboardCopy(setupm_ip, l);
+							S_StartSound(NULL,sfx_menu1); // Tails
+							setupm_ip[0] = 0;
+						}
 						break;
 					default: // otherwise do nothing.
 						break;
@@ -13071,7 +13105,10 @@ static void M_SetupScreenshotMenu(void)
 	{
 		item->status = IT_GRAYEDOUT;
 		if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that
+		{
 			itemOn = op_screenshot_storagelocation;
+			M_UpdateItemOn();
+		}
 	}
 	else
 #endif
diff --git a/src/m_misc.c b/src/m_misc.c
index 55c5485a149a2b2c43e48fab973c5ad898091036..a60bbea98d2e2b47cf3fea0dae652d26b6aa4763 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2208,6 +2208,8 @@ int M_JumpWordReverse(const char *line, int offset)
 {
 	int (*is)(int);
 	int c;
+	if (offset == 0) // Don't let "--offset" later result in a negative value
+		return 0;
 	c = line[--offset];
 	if (isspace(c))
 		is = isspace;
diff --git a/src/p_pspr.h b/src/p_pspr.h
index 5fb6767633398d1e304001123dcda541599b1aba..6510190f118fb639c52a22576dd911023d3b134c 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -39,7 +39,7 @@
 #define FF_FRAMEMASK 0xff
 
 /// \brief Frame flags - SPR2: Super sprite2
-#define FF_SPR2SUPER 0x80
+#define FF_SPR2SUPER SPR2F_SUPER //TODO: 2.3: remove this backwards compat hack
 /// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation
 #define FF_SPR2ENDSTATE 0x100
 /// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation
diff --git a/src/p_spec.c b/src/p_spec.c
index 805817fb033c465b33059c24fbefb52432173444..78cf460632970ac108512f29f1fd2111aea5f462 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3684,7 +3684,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 
 		case 466: // Set level failure state
 			{
-				if (line->args[1])
+				if (line->args[0])
 				{
 					stagefailed = false;
 					CONS_Debug(DBG_GAMELOGIC, "Stage can be completed successfully!\n");
diff --git a/src/r_skins.c b/src/r_skins.c
index d0d2eed6287ed69b27fef7eb7fe3acc4c7c61b3c..cd7d60b53e4c572630e26980309729a121d43cb7 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -43,10 +43,9 @@ UINT16 P_GetStateSprite2(state_t *state)
 	else
 	{
 		// Transform the state frame into an animation ID
-		UINT32 stateframe = state->frame & FF_FRAMEMASK;
-		UINT16 spr2 = stateframe & ~FF_SPR2SUPER;
+		UINT16 spr2 = state->frame & FF_FRAMEMASK;
 
-		if (stateframe & FF_SPR2SUPER)
+		if (state->frame & SPR2F_SUPER)
 			spr2 |= SPR2F_SUPER;
 
 		return spr2;
@@ -70,7 +69,7 @@ boolean P_IsStateSprite2Super(state_t *state)
 		if (state->sprite2 & SPR2F_SUPER)
 			return true;
 	}
-	else if (state->frame & FF_SPR2SUPER)
+	else if (state->frame & SPR2F_SUPER)
 		return true;
 
 	return false;
diff --git a/src/r_textures.c b/src/r_textures.c
index 59cc114139c5abb24df0f47fa0dddd0e70ec8d72..5d3fe24db2c942647d514a92ad42a759d0b3c9f4 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -821,8 +821,8 @@ Rloadflats (INT32 i, INT32 w)
 			UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
 			if (Picture_PNGDimensions((UINT8 *)flatlump, &texw, &texh, NULL, NULL, lumplength))
 			{
-				width = (INT16)width;
-				height = (INT16)height;
+				width = (INT16)texw;
+				height = (INT16)texh;
 			}
 			else
 			{
@@ -1068,6 +1068,98 @@ void R_LoadTexturesPwad(UINT16 wadnum)
 	R_FinishLoadingTextures(newtextures);
 }
 
+static lumpnum_t W_GetTexPatchLumpNum(const char *name)
+{
+	// Flats as a texture patch crashes horribly, and flats
+	// can share the same name as textures.
+
+	// But even if they worked, we want to prioritize:
+	// Patches -> Textures -> anything else
+
+	enum
+	{
+		USE_PATCHES,
+		USE_TEXTURES,
+		USE__MAX,
+	};
+
+	lumpnum_t lump = LUMPERROR;
+	INT32 lump_type_it;
+	
+
+	for (lump_type_it = 0; lump_type_it < USE__MAX; lump_type_it++)
+	{
+		INT32 i;
+
+		for (i = numwadfiles - 1; i >= 0; i--) // Scan wad files backwards so patched lumps take precedent
+		{
+			lumpnum_t start = LUMPERROR;
+			lumpnum_t end = LUMPERROR;
+
+			switch (wadfiles[i]->type)
+			{
+				case RET_WAD:
+					if (lump_type_it == USE_PATCHES)
+					{
+						if ((start = W_CheckNumForMarkerStartPwad("P_START", (UINT16)i, 0)) == INT16_MAX)
+							continue;
+						else if ((end = W_CheckNumForNamePwad("P_END", (UINT16)i, start)) == INT16_MAX)
+							continue;
+					}
+					else if (lump_type_it == USE_TEXTURES)
+					{
+						if ((start = W_CheckNumForMarkerStartPwad("TX_START", (UINT16)i, 0)) == INT16_MAX)
+							continue;
+						else if ((end = W_CheckNumForNamePwad("TX_END", (UINT16)i, start)) == INT16_MAX)
+							continue;
+					}
+					break;
+				case RET_PK3:
+				case RET_FOLDER:
+					if (lump_type_it == USE_PATCHES)
+					{
+						if ((start = W_CheckNumForFolderStartPK3("Patches/", i, 0)) == INT16_MAX)
+							continue;
+						if ((end = W_CheckNumForFolderEndPK3("Patches/", i, start)) == INT16_MAX)
+							continue;
+					}
+					else if (lump_type_it == USE_TEXTURES)
+					{
+						if ((start = W_CheckNumForFolderStartPK3("Textures/", i, 0)) == INT16_MAX)
+							continue;
+						if ((end = W_CheckNumForFolderEndPK3("Textures/", i, start)) == INT16_MAX)
+							continue;
+					}
+					break;
+				default:
+					continue;
+			}
+
+			// Now find lump with specified name in that range.
+			lump = W_CheckNumForNamePwad(name, (UINT16)i, start);
+			if (lump < end)
+			{
+				lump += (i<<16); // found it, in our constraints
+				break;
+			}
+			lump = LUMPERROR;
+		}
+
+		if (lump != LUMPERROR)
+		{
+			break;
+		}
+	}
+
+	if (lump == LUMPERROR)
+	{
+		// Use whatever else you can find.
+		return W_GetNumForName(name);
+	}
+
+	return lump;
+}
+
 static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
 {
 	char *texturesToken;
@@ -1240,13 +1332,13 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
 	if (actuallyLoadPatch == true)
 	{
 		// Check lump exists
-		patchLumpNum = W_GetNumForName(patchName);
+		patchLumpNum = W_GetTexPatchLumpNum(patchName);
 		// If so, allocate memory for texpatch_t and fill 'er up
 		resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL);
 		resultPatch->originx = patchXPos;
 		resultPatch->originy = patchYPos;
-		resultPatch->lump = patchLumpNum & 65535;
-		resultPatch->wad = patchLumpNum>>16;
+		resultPatch->lump = LUMPNUM(patchLumpNum);
+		resultPatch->wad = WADFILENUM(patchLumpNum);
 		resultPatch->flip = flip;
 		resultPatch->alpha = alpha;
 		resultPatch->style = style;
diff --git a/src/s_sound.c b/src/s_sound.c
index 5155b90e8abe03901670bd8e5f38b29a7cdd508c..32353a59c2d590dd8ea1f74b47399de0886684d0 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -2256,9 +2256,9 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
 		return;
 
 	strncpy(newmusic, mmusic, sizeof(newmusic)-1);
+	newmusic[6] = 0;
 	if (LUA_HookMusicChange(music_name, &hook_param))
 		return;
-	newmusic[6] = 0;
 
 	// No Music (empty string)
 	if (newmusic[0] == 0)
diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c
index f5fe9fb041b9f02057955afe072815e709b19dc3..b2177e563120fc76cf726353e5cad841e45b1762 100644
--- a/src/sdl/i_main.c
+++ b/src/sdl/i_main.c
@@ -186,6 +186,9 @@ int main(int argc, char **argv)
 #endif
 #endif
 
+	// disable text input right off the bat, since we don't need it at the start.
+	I_SetTextInputMode(false);
+
 #ifdef LOGMESSAGES
 	if (!M_CheckParm("-nolog"))
 		InitLogging();
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 2d051888dc1f26de5357b8689eced942ab38da59..115b900f5b575ce376a816dc9093c38202724e86 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -3275,4 +3275,18 @@ const char *I_GetSysName(void)
 	return SDL_GetPlatform();
 }
 
+
+void I_SetTextInputMode(boolean active)
+{
+	if (active)
+		SDL_StartTextInput();
+	else
+		SDL_StopTextInput();
+}
+
+boolean I_GetTextInputMode(void)
+{
+	return SDL_IsTextInputActive();
+}
+
 #endif