diff --git a/.gitignore b/.gitignore
index 922fac4aa..3090417dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,5 @@ Win32_LIB_ASM_Release
 *.db
 *.opendb
 /.vs
+/debian
+/assets/debian
diff --git a/.travis.yml b/.travis.yml
index 15a3c844c..6d2e8cddf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,20 @@
+# Travis-CI Config
+#
+# You may use the Deployer to upload packages and builds to external servers.
+# See deployer/travis/deployer_defaults.sh for environment variables to configure.
+
 language: c
 sudo: required
 dist: trusty
 
 matrix:
     include:
+################################
+# Test Buildbots
+# Deployer does not operate on these. See Deployer Buildbots, below.
+# These bots are disabled when a deployment is triggered by 'deployer' branch name AND DPL_TERMINATE_TESTS=1.
+# These bots remain enabled when a deployment is triggered by release tag.
+################################
         - os: linux
           addons:
             apt:
@@ -16,6 +27,7 @@ matrix:
               - gcc-4.4
           compiler: gcc-4.4
           env: GCC44=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.4 (Ubuntu/Linaro 4.4.7-8ubuntu1) 4.4.7
         - os: linux
           addons:
@@ -29,6 +41,7 @@ matrix:
               - gcc-4.6
           compiler: gcc-4.6
           env: GCC46=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.6 (Ubuntu/Linaro 4.6.4-6ubuntu2) 4.6.4
         - os: linux
           addons:
@@ -42,10 +55,12 @@ matrix:
               - gcc-4.7
           compiler: gcc-4.7
           env: GCC47=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.7
         - os: linux
           compiler: gcc
           env: GCC48=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
         - os: linux
           addons:
@@ -61,6 +76,7 @@ matrix:
               - gcc-4.8
           compiler: gcc-4.8
           env: GCC48=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
         - os: linux
           addons:
@@ -76,6 +92,7 @@ matrix:
               - gcc-7
           compiler: gcc-7
           env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough" GCC72=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-7 (Ubuntu 7.2.0-1ubuntu1~14.04) 7.2.0 20170802
         - os: linux
           addons:
@@ -90,10 +107,12 @@ matrix:
               - p7zip-full
               - gcc-8
           compiler: gcc-8
-          env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough -Wno-error=format-overflow" GCC81=1
+          env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wno-implicit-fallthrough -Wno-error=format-overflow -Wno-error=format-truncation" GCC81=1
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #gcc-8 (Ubuntu 7.2.0-1ubuntu1~14.04) 8.1.0
         - os: linux
           compiler: clang
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #clang version 3.5.0 (tags/RELEASE_350/final)
         - os: linux
           addons:
@@ -108,6 +127,7 @@ matrix:
               - p7zip-full
               - clang-3.5
           compiler: clang-3.5
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #Ubuntu clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
         - os: linux
           addons:
@@ -123,6 +143,7 @@ matrix:
               - p7zip-full
               - clang-3.6
           compiler: clang-3.6
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #Ubuntu clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2)
         - os: linux
           addons:
@@ -138,6 +159,7 @@ matrix:
               - p7zip-full
               - clang-3.7
           compiler: clang-3.7
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #Ubuntu clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1)
         - os: linux
           addons:
@@ -153,6 +175,7 @@ matrix:
               - p7zip-full
               - clang-3.8
           compiler: clang-3.8
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #clang version 3.8.1-svn271127-1~exp1 (branches/release_38)
         - os: linux
           addons:
@@ -168,6 +191,7 @@ matrix:
               - p7zip-full
               - clang-3.9
           compiler: clang-3.9
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #clang version 3.9.X
 #        - os: linux
 #          addons:
@@ -183,6 +207,7 @@ matrix:
 #              - p7zip-full
 #              - clang-4.0
 #          compiler: clang-4.0
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #clang version 4.0.X
 #        - os: linux
 #          addons:
@@ -198,34 +223,325 @@ matrix:
 #              - p7zip-full
 #              - clang-5.0
 #          compiler: clang-5.0
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #clang version 5.0.X
 #        - os: osx
 #          osx_image: beta-xcode6.1
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
 #        - os: osx
 #          osx_image: beta-xcode6.2
 #          compiler: gcc
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
 ##        - os: osx
 ##          osx_image: beta-xcode6.3
+##          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 ##          #I think xcode.6.3 VM is broken, it does not boot
 #        - os: osx
 #          osx_image: xcode6.4
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
 #        - os: osx
 #          osx_image: xcode7
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 7.0.0 (clang-700.0.72)
 #        - os: osx
 #          osx_image: xcode7.1
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 7.0.0 (clang-700.1.76)
 #        - os: osx
 #          osx_image: xcode7.2
+#          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
 #          #Apple LLVM version 7.0.2 (clang-700.1.81)
 #        - os: osx
 #          osx_image: xcode7.3
+#          #Apple LLVM version 7.3.0 (clang-703.0.31)
+#        - os: osx
+#          osx_image: xcode7.3
 #          #Apple LLVM version 7.3.0 (clang-703.0.31)
         - os: osx
+          if: env(DPL_ENABLED) != "1" OR env(DPL_TERMINATE_TESTS) != "1" OR NOT branch =~ /^.*deployer.*$/
           #Default: macOS 10.13 and Xcode 9.4.1
+
+
+################################
+# Deployer Buildbots - OSX
+################################
+        - os: osx
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_MAIN) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=osx
+          - _DPL_FTP_TARGET=1
+          - _DPL_PACKAGE_BINARY=1
+          #Apple LLVM version 7.3.0 (clang-703.0.31)
+
+
+################################
+# Deployer Buildbots - Linux assets
+# Set DPL_TERMINATE_ASSETS to disable all of these
+# List Ubuntu LTS next, newest to oldest
+# Then list non-LTS, newest to oldest
+################################
+        - os: linux
+          addons:
+            apt:
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-4.8
+          compiler: gcc-4.8
+          dist: xenial
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_ASSETS) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=bionic-asset
+          - _DPL_DPUT_TARGET=1
+          - _DPL_PACKAGE_SOURCE=1
+          - _DPL_PACKAGE_MAIN=0
+          - _DPL_PACKAGE_ASSET=1
+          - PACKAGE_DISTRO=bionic
+          #- PACKAGE_SUBVERSION=~18.04bionic
+          #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+
+        ################################
+        # The below asset bots produce packages that occupy too much space.
+        # It would be nice if the asset files were not included in the source package itself,
+        # so these can deploy to each Ubuntu target without manual intervention.
+        #
+        # Currently, to get around Launchpad's space limitation,
+        # copy the packages from *one* bot and the space usage is not increased.
+        ################################
+        # - os: linux
+        #   addons:
+        #     apt:
+        #       packages:
+        #       - libsdl2-mixer-dev
+        #       - libpng-dev
+        #       - libgl1-mesa-dev
+        #       - libgme-dev
+        #       - p7zip-full
+        #       - gcc-4.8
+        #   compiler: gcc-4.8
+        #   dist: trusty
+        #   if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+        #       AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+        #       AND env(DPL_TERMINATE_ASSETS) != "1"
+        #   env:
+        #   - _DPL_JOB_ENABLED=1
+        #   - _DPL_JOB_NAME=trusty-asset
+        #   - _DPL_DPUT_TARGET=1
+        #   - _DPL_PACKAGE_SOURCE=1
+        #   - _DPL_PACKAGE_MAIN=0
+        #   - _DPL_PACKAGE_ASSET=1
+        #   - PACKAGE_DISTRO=trusty
+        #   #- PACKAGE_SUBVERSION=~14.04trusty
+        #   #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        # - os: linux
+        #   addons:
+        #     apt:
+        #       packages:
+        #       - libsdl2-mixer-dev
+        #       - libpng-dev
+        #       - libgl1-mesa-dev
+        #       - libgme-dev
+        #       - p7zip-full
+        #       - gcc-4.8
+        #   compiler: gcc-4.8
+        #   dist: xenial
+        #   if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+        #       AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+        #       AND env(DPL_TERMINATE_ASSETS) != "1"
+        #   env:
+        #   - _DPL_JOB_ENABLED=1
+        #   - _DPL_JOB_NAME=disco-asset
+        #   - _DPL_DPUT_TARGET=1
+        #   - _DPL_PACKAGE_SOURCE=1
+        #   - _DPL_PACKAGE_MAIN=0
+        #   - _DPL_PACKAGE_ASSET=1
+        #   - PACKAGE_DISTRO=disco
+        #   #- PACKAGE_SUBVERSION=~19.04disco
+        #   #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        # - os: linux
+        #   addons:
+        #     apt:
+        #       packages:
+        #       - libsdl2-mixer-dev
+        #       - libpng-dev
+        #       - libgl1-mesa-dev
+        #       - libgme-dev
+        #       - p7zip-full
+        #       - gcc-4.8
+        #   compiler: gcc-4.8
+        #   dist: xenial
+        #   if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+        #       AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+        #       AND env(DPL_TERMINATE_ASSETS) != "1"
+        #   env:
+        #   - _DPL_JOB_ENABLED=1
+        #   - _DPL_JOB_NAME=cosmic-asset
+        #   - _DPL_DPUT_TARGET=1
+        #   - _DPL_PACKAGE_SOURCE=1
+        #   - _DPL_PACKAGE_MAIN=0
+        #   - _DPL_PACKAGE_ASSET=1
+        #   - PACKAGE_DISTRO=cosmic
+        #   #- PACKAGE_SUBVERSION=~18.10cosmic
+        #   #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        # - os: linux
+        #   addons:
+        #     apt:
+        #       packages:
+        #       - libsdl2-mixer-dev
+        #       - libpng-dev
+        #       - libgl1-mesa-dev
+        #       - libgme-dev
+        #       - p7zip-full
+        #       - gcc-4.8
+        #   compiler: gcc-4.8
+        #   dist: xenial
+        #   if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+        #       AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+        #       AND env(DPL_TERMINATE_ASSETS) != "1"
+        #   env:
+        #   - _DPL_JOB_ENABLED=1
+        #   - _DPL_JOB_NAME=xenial-asset
+        #   - _DPL_DPUT_TARGET=1
+        #   - _DPL_PACKAGE_SOURCE=1
+        #   - _DPL_PACKAGE_MAIN=0
+        #   - _DPL_PACKAGE_ASSET=1
+        #   - PACKAGE_DISTRO=xenial
+        #   #- PACKAGE_SUBVERSION=~16.04xenial
+        #   #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+
+
+################################
+# Deployer Buildbots - Linux binaries
+# List Ubuntu LTS, newest to oldest
+# Then list non-LTS, newest to oldest
+################################
+        - os: linux
+          addons:
+            apt:
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-4.8
+          compiler: gcc-4.8
+          dist: xenial
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_MAIN) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=bionic
+          - _DPL_DPUT_TARGET=1
+          - _DPL_PACKAGE_SOURCE=1
+          - PACKAGE_DISTRO=bionic
+          - PACKAGE_SUBVERSION=~18.04bionic
+          #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        - os: linux
+          addons:
+            apt:
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-4.8
+          compiler: gcc-4.8
+          dist: trusty
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_MAIN) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=trusty
+          - _DPL_DPUT_TARGET=1
+          - _DPL_PACKAGE_SOURCE=1
+          - PACKAGE_DISTRO=trusty
+          - PACKAGE_SUBVERSION=~14.04trusty
+          #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        - os: linux
+          addons:
+            apt:
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-4.8
+          compiler: gcc-4.8
+          dist: xenial
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_MAIN) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=disco
+          - _DPL_DPUT_TARGET=1
+          - _DPL_PACKAGE_SOURCE=1
+          - PACKAGE_DISTRO=disco
+          - PACKAGE_SUBVERSION=~19.04disco
+          #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        - os: linux
+          addons:
+            apt:
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-4.8
+          compiler: gcc-4.8
+          dist: xenial
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_MAIN) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=cosmic
+          - _DPL_DPUT_TARGET=1
+          - _DPL_PACKAGE_SOURCE=1
+          - PACKAGE_DISTRO=cosmic
+          - PACKAGE_SUBVERSION=~18.10cosmic
+          #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
+        - os: linux
+          addons:
+            apt:
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - gcc-4.8
+          compiler: gcc-4.8
+          dist: xenial
+          if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
+              AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
+              AND env(DPL_TERMINATE_MAIN) != "1"
+          env:
+          - _DPL_JOB_ENABLED=1
+          - _DPL_JOB_NAME=xenial
+          - _DPL_DPUT_TARGET=1
+          - _DPL_PACKAGE_SOURCE=1
+          - PACKAGE_DISTRO=xenial
+          - PACKAGE_SUBVERSION=~16.04xenial
+          #gcc-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5
     allow_failures:
       - compiler: clang-3.5
       - compiler: clang-3.6
@@ -235,12 +551,14 @@ matrix:
       - compiler: clang-4.0
       - compiler: clang-5.0
 
+
 cache:
   apt: true
   ccache: true
   directories:
   - $HOME/srb2_cache
 
+
 addons:
   apt:
     packages:
@@ -248,6 +566,7 @@ addons:
     - libpng-dev
     - libgl1-mesa-dev
     - libgme-dev
+    - zlib1g-dev
     - p7zip-full
   homebrew:
     taps:
@@ -260,18 +579,115 @@ addons:
     update: true
 
 
-before_script:
-  - wget --verbose --server-response -c http://rosenthalcastle.org/srb2/SRB2-v2115-assets-2.7z -O $HOME/srb2_cache/SRB2-v2115-assets-2.7z
-  - 7z x $HOME/srb2_cache/SRB2-v2115-assets-2.7z -oassets
-  - mkdir build
-  - cd build
-  - export CFLAGS="-Wall -W -Werror $WFLAGS"
-  - export CCACHE_COMPRESS=true
-  - cmake .. -DCMAKE_BUILD_TYPE=Release
 
 before_install:
-  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -O -L https://www.libsdl.org/release/SDL2-2.0.6.dmg; hdiutil attach SDL2-2.0.6.dmg; sudo cp -a /Volumes/SDL2/SDL2.framework /Library/Frameworks/; fi
-  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -O -L https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.dmg; hdiutil attach SDL2_mixer-2.0.1.dmg; sudo cp -a /Volumes/SDL2_mixer/SDL2_mixer.framework /Library/Frameworks/; fi
+  # Initialize Deployer defaults
+  - . ./deployer/travis/deployer_defaults.sh
+
+  # Initialize Deployer; check if Deployer is enabled
+  # This needs to be run in the current shell so that $__DPL_ACTIVE is set for this session
+  - . ./deployer/travis/deployer.sh
+
+  # Also check if we should now terminate -- see `deployer.sh` for conditions.
+  # This should never happen on non-release buildbots when Deployer is not triggered.
+  - if [[ "$__DPL_TRY_TERMINATE_EARLY" == "1" ]]; then
+      if [[ "$__DPL_ACTIVE" != "1" ]]; then
+        echo "Exiting early because this job is not deploying.";
+        exit;
+      fi;
+    fi
+
+  # If we're triggered by release tag, force ASSET_FILES_OPTIONAL_GET=1
+  - if [[ "$__DPL_TAG_ELIGIBLE" = "1" ]]; then
+      ASSET_FILES_OPTIONAL_GET=1;
+    fi;
+
+
+install:
+  # Install OS X library dependencies via Homebrew
+  # Do this differently for release buildbots:
+  #     * `brew install --build-bottle` builds libraries for x86_64's lowest common denominator CPU, core2
+  #     * `sdl2_mixer` requires options from the formula tap https://github.com/mazmazz/homebrew-srb2
+  #     * `brew postinstall` runs post-install scripts after building a bottle
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+      if [[ "$__DPL_ACTIVE" == "1" ]]; then
+        brew install --build-bottle sdl2 game-music-emu;
+        brew install --build-bottle mazmazz/srb2/sdl2_mixer --with-flac --with-mpg123;
+        brew postinstall sdl2 game-music-emu mazmazz/srb2/sdl2_mixer;
+      fi;
+    fi
   - mkdir -p $HOME/srb2_cache
 
-script: make -k
+
+before_script:
+  # OLDPWD is root repo folder
+  - OLDPWD=$PWD
+  - __ASSET_DIRECTORY="$OLDPWD/assets/installer"
+  - mkdir -p "$__ASSET_DIRECTORY"
+  - cd "$HOME/srb2_cache"
+
+  # Get stat command so we know what the cached archive date is.
+  # stat is different for OSX
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+      STATCMD="stat -f %m";
+    else
+      STATCMD="stat -c %y";
+    fi
+
+  # Get asset files (required for MD5)
+  # See `deployer_defaults.sh` for asset download path
+  - if [[ "$ASSET_ARCHIVE_PATH" != "" ]]; then
+      if [ -f "$(basename $ASSET_ARCHIVE_PATH)" ]; then
+        echo "$(basename $ASSET_ARCHIVE_PATH) cache date -- $($STATCMD $(basename $ASSET_ARCHIVE_PATH))";
+      fi;
+      wget --verbose --server-response -N "$ASSET_ARCHIVE_PATH";
+      7z x "$(basename $ASSET_ARCHIVE_PATH)" -o"$__ASSET_DIRECTORY" -aos;
+    fi;
+
+  # Get optional files too
+  - if [[ "$__DPL_ACTIVE" == "1" ]] && [[ "$ASSET_FILES_OPTIONAL_GET" == "1" ]] && [[ "$ASSET_ARCHIVE_OPTIONAL_PATH" != "" ]]; then
+      if [ -f "$(basename $ASSET_ARCHIVE_OPTIONAL_PATH)" ]; then
+        echo "$(basename $ASSET_ARCHIVE_OPTIONAL_PATH) cache date -- $($STATCMD $(basename $ASSET_ARCHIVE_OPTIONAL_PATH))";
+      fi;
+      wget --verbose --server-response -N "$ASSET_ARCHIVE_OPTIONAL_PATH";
+      7z x "$(basename $ASSET_ARCHIVE_OPTIONAL_PATH)" -o"$__ASSET_DIRECTORY" -aos;
+    fi;
+
+  # Go back to root repo folder
+  - cd "$OLDPWD"
+
+  # Prepare CMake asset lists
+  - SRB2_ASSET_HASHED=$(echo ${ASSET_FILES_HASHED// /\;})
+  - SRB2_ASSET_DOCS=$(echo ${ASSET_FILES_DOCS// /\;})
+  - SRB2_ASSET_DIRECTORY="$__ASSET_DIRECTORY"
+
+  # Prepare CMake
+  - mkdir build
+  - cd build
+  - mkdir package
+  - export CFLAGS="-Wall -W -Werror $WFLAGS"
+  - export CCACHE_COMPRESS=true
+  # If OS X, set -march=core2 to build compatible binaries with old Macs
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+      export CFLAGS="${CFLAGS} -march=core2";
+    fi;
+  - cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$PWD/bin -DCPACK_PACKAGE_DIRECTORY=$PWD/package
+      -DSRB2_ASSET_HASHED="${SRB2_ASSET_HASHED}" -DSRB2_ASSET_DOCS="${SRB2_ASSET_DOCS}"
+      -DSRB2_ASSET_DIRECTORY="${SRB2_ASSET_DIRECTORY}"
+      -DCPACK_PACKAGE_DESCRIPTION_SUMMARY="${PROGRAM_NAME}"
+      -DCPACK_PACKAGE_VENDOR="${PROGRAM_VENDOR}"
+      -DSRB2_SDL2_EXE_NAME="${PROGRAM_FILENAME}"
+
+script:
+  # Build our Makefile from Cmake!
+  - if [[ "$__DPL_ACTIVE" == "1" ]]; then
+      . ../deployer/travis/deployer_build.sh;
+    else
+      make -k;
+    fi;
+
+after_success:
+  # Run the upload scripts
+  # These do nothing if Deployer is not triggered
+  - . ../deployer/travis/deployer_ftp.sh
+  - . ../deployer/travis/deployer_dput.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0a5507b92..b70221859 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,8 @@
 cmake_minimum_required(VERSION 3.0)
+# DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string.
+# Version change is fine.
 project(SRB2
-	VERSION 2.1.23
+	VERSION 2.1.24
 	LANGUAGES C)
 
 if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
@@ -92,8 +94,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 
 # Set EXE names so the assets CMakeLists can refer to its target
-set(SRB2_SDL2_EXE_NAME srb2)
-set(SRB2_WIN_EXE_NAME srb2dd)
+set(SRB2_SDL2_EXE_NAME srb2 CACHE STRING "Executable binary output name")
+set(SRB2_WIN_EXE_NAME srb2dd CACHE STRING "Executable binary output name for DirectDraw build")
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
 
@@ -122,8 +124,8 @@ if(${CMAKE_SYSTEM} MATCHES "Darwin")
 	set(CPACK_GENERATOR "DragNDrop")
 endif()
 
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Sonic Robo Blast 2")
-set(CPACK_PACKAGE_VENDOR "Sonic Team Jr.")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Sonic Robo Blast 2" CACHE STRING "Program name for display purposes")
+set(CPACK_PACKAGE_VENDOR "Sonic Team Jr." CACHE STRING "Vendor name for display purposes")
 #set(CPACK_PACKAGE_DESCRIPTION_FILE )
 set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
 set(CPACK_PACKAGE_VERSION_MAJOR ${SRB2_VERSION_MAJOR})
diff --git a/appveyor.yml b/appveyor.yml
index f0f843fbb..98da61dbf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 2.1.23.{branch}-{build}
+version: 2.1.24.{branch}-{build}
 os: MinGW
 
 environment:
diff --git a/assets/.gitignore b/assets/.gitignore
index 9ed61ca1a..d6e46a75b 100644
--- a/assets/.gitignore
+++ b/assets/.gitignore
@@ -1,5 +1,10 @@
-*
-*.*
+*.srb
+*.pk3
+*.dta
+*.wad
+*.txt
 !README.txt
 !LICENSE.txt
-!LICENSE-3RD-PARTY.txt
\ No newline at end of file
+!LICENSE-3RD-PARTY.txt
+!CMakeLists.txt
+!debian-template/*
diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt
index 6edb3df13..68ff0fdf9 100644
--- a/assets/CMakeLists.txt
+++ b/assets/CMakeLists.txt
@@ -1,40 +1,58 @@
 ## Assets Target Configuration ##
 
-# MD5 generation
-set(SRB2_ASSET_ALL
-	${CMAKE_CURRENT_SOURCE_DIR}/srb2.srb
-	${CMAKE_CURRENT_SOURCE_DIR}/player.dta
-	${CMAKE_CURRENT_SOURCE_DIR}/rings.dta
-	${CMAKE_CURRENT_SOURCE_DIR}/zones.dta
-	${CMAKE_CURRENT_SOURCE_DIR}/patch.dta
-	${CMAKE_CURRENT_SOURCE_DIR}/music.dta
-	${CMAKE_CURRENT_SOURCE_DIR}/README.txt
-	${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt
-	${CMAKE_CURRENT_SOURCE_DIR}/LICENSE-3RD-PARTY.txt
-)
+# For prepending the current source path, later
+FUNCTION(PREPEND var prefix)
+   SET(listVar "")
+   FOREACH(f ${ARGN})
+      LIST(APPEND listVar "${prefix}/${f}")
+   ENDFOREACH(f)
+   SET(${var} "${listVar}" PARENT_SCOPE)
+ENDFUNCTION(PREPEND)
+
+set(SRB2_ASSET_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/installer"
+	CACHE STRING "Path to directory that contains all asset files for the installer.")
 
 set(SRB2_ASSET_HASHED
-	srb2.srb
-	player.dta
-	rings.dta
-	zones.dta
-	patch.dta
+"srb2.srb;\
+player.dta;\
+rings.dta;\
+zones.dta;\
+patch.dta"
+	CACHE STRING "Asset filenames to apply MD5 checks. No spaces between entries!"
 )
 
+set(SRB2_ASSET_DOCS
+"README.txt;\
+LICENSE.txt;\
+LICENSE-3RD-PARTY.txt"
+	CACHE STRING "Documentation filenames. In OS X, these are packaged separately from other assets. No spaces between entries!"
+)
+
+PREPEND(SRB2_ASSET_DOCS ${SRB2_ASSET_DIRECTORY} ${SRB2_ASSET_DOCS})
+
 foreach(SRB2_ASSET ${SRB2_ASSET_HASHED})
-	file(MD5 ${CMAKE_CURRENT_SOURCE_DIR}/${SRB2_ASSET} "SRB2_ASSET_${SRB2_ASSET}_HASH")
+	file(MD5 ${SRB2_ASSET_DIRECTORY}/${SRB2_ASSET} "SRB2_ASSET_${SRB2_ASSET}_HASH")
 	set(SRB2_ASSET_${SRB2_ASSET}_HASH ${SRB2_ASSET_${SRB2_ASSET}_HASH} PARENT_SCOPE)
 endforeach()
 
 # Installation
 
-if(CLANG)
+if(${CMAKE_SYSTEM} MATCHES Darwin)
 	get_target_property(outname SRB2SDL2 OUTPUT_NAME)
-	install(FILES ${SRB2_ASSET_ALL}
+	install(DIRECTORY "${SRB2_ASSET_DIRECTORY}/"
 		DESTINATION "${outname}.app/Contents/Resources"
 	)
+	install(FILES ${SRB2_ASSET_DOCS}
+		DESTINATION .
+		OPTIONAL
+	)
 else()
-	install(FILES ${SRB2_ASSET_ALL}
+	install(DIRECTORY "${SRB2_ASSET_DIRECTORY}/"
 		DESTINATION .
 	)
+	# Docs are assumed to be located in SRB2_ASSET_DIRECTORY, so don't install again
+	#install(FILES ${SRB2_ASSET_DOCS}
+	#	DESTINATION .
+	#	OPTIONAL
+	#)
 endif()
diff --git a/assets/debian/README.Debian b/assets/debian-template/README.Debian
similarity index 59%
rename from assets/debian/README.Debian
rename to assets/debian-template/README.Debian
index 68c952a4e..f3fe90030 100644
--- a/assets/debian/README.Debian
+++ b/assets/debian-template/README.Debian
@@ -12,9 +12,39 @@ with apt-key add. Thanks!
  -- Callum Dickinson <gcfreak_ag20@hotmail.com>  Fri, 26 Nov 2010 18:25:31 +1300
 
 
+---------------
+
+
+Templating
+
+Note that you MUST run [repo-root]/debian_template.sh before running debuild
+on these scripts! debian_template.sh fills these template files with working values.
+
+You should also set PACKAGE_NAME_EMAIL="John Doe <jdoe@example.com>" to match
+the identity of the key you will use to sign the package.
+
+
+Building for Launchpad PPA
+
+Run this step first:
+
+    1. source [repo-root]/debian_template.sh
+       * Initializes defaults for the package variables and fills in templates.
+
+Use these steps to prepare building a source package for Launchpad:
+
+    1. cd [repo-root]/assets/
+    2. debuild -T clean-all (optional; if you already have asset files, this clears them)
+
+Build the source package:
+
+    1. debuild -T build (this downloads the asset files from srb2.org if necessary)
+    2. debuild -S (builds the source package for Launchpad, including the asset files)
+
+
 Signing for Launchpad PPA
 
-First, follow the above instructions to generate a GnuPG key with your identity. You will need
+First, follow Callum's instructions to generate a GnuPG key with your identity. You will need
 to publish the fingerprint of that key to Ubuntu's key server.
 
     https://help.ubuntu.com/community/GnuPrivacyGuardHowto#Uploading_the_key_to_Ubuntu_keyserver
@@ -26,22 +56,18 @@ upload signed source packages and publish them onto your PPA.
 IF YOU UPLOAD A PACKAGE and Launchpad does NOT send you a confirmation or rejection email, that
 means your key is not set up correctly with your Launchpad account.
 
+Finally, if your packages have not already been signed, follow these steps:
 
-Building for Launchpad PPA
+    1. cd ..
+       * Packages are located in the parent folder of where debuild was called
+    2. debsign "srb2-data_[version]_source.changes"
+       * You may need to specify -k [key-fingerprint]
 
-Use these steps to prepare building a source package for Launchpad:
 
-    1. Highly recommend copying the assets/ folder to outside your repo folder, or else the asset
-       files may be included in the main source package, when you build that.
-    2. cd [wherever-your-assets-folder-is]/assets/
-    3. debuild -T clean (optional, if you already have asset files)
+Uploading for Launchpad PPA
 
-Building the source package is a two-step process:
-
-    1. debuild -T build (this downloads the asset files from srb2.org if necessary)
-    2. debuild -S (builds the source package for Launchpad, including the asset files)
-
-Then follow the instructions at <https://help.launchpad.net/Packaging/PPA/Uploading> to upload
+Follow the instructions at <https://help.launchpad.net/Packaging/PPA/Uploading> to upload
 to your PPA and have Launchpad build your binary deb packages.
 
+
  -- Marco Zafra <marco.a.zafra@gmail.com>  Mon, 26 Nov 2018 21:13:00 -0500
diff --git a/assets/debian/README.source b/assets/debian-template/README.source
similarity index 100%
rename from assets/debian/README.source
rename to assets/debian-template/README.source
diff --git a/assets/debian-template/changelog b/assets/debian-template/changelog
new file mode 100644
index 000000000..64562e2a3
--- /dev/null
+++ b/assets/debian-template/changelog
@@ -0,0 +1,5 @@
+${PACKAGE_NAME}-data (${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION}) ${PACKAGE_DISTRO}; urgency=${PACKAGE_URGENCY}
+
+  * ${PROGRAM_NAME} v${PROGRAM_VERSION} asset data
+
+ -- ${PACKAGE_NAME_EMAIL}  ${__PACKAGE_DATETIME}
diff --git a/assets/debian/compat b/assets/debian-template/compat
similarity index 100%
rename from assets/debian/compat
rename to assets/debian-template/compat
diff --git a/assets/debian/control b/assets/debian-template/control
similarity index 84%
rename from assets/debian/control
rename to assets/debian-template/control
index 22d9643ee..ae5c0ce67 100644
--- a/assets/debian/control
+++ b/assets/debian-template/control
@@ -1,15 +1,15 @@
 # SRB2-data Debian package control file.
 
-Source: srb2-data
+Source: ${PACKAGE_NAME}-data
 Section: games
 Priority: extra
-Maintainer: Sonic Team Junior <stjr@srb2.org>
+Maintainer: ${PACKAGE_GROUP_NAME_EMAIL}
 Build-Depends: debhelper (>= 7.0.50~),
  wget
 Standards-Version: 3.8.4
-Homepage: http://www.srb2.org
+Homepage: ${PACKAGE_WEBSITE}
 
-Package: srb2-data
+Package: ${PACKAGE_NAME}-data
 Architecture: all
 Description: A cross-platform 3D Sonic fangame
  Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog
diff --git a/debian/copyright b/assets/debian-template/copyright
similarity index 57%
rename from debian/copyright
rename to assets/debian-template/copyright
index 97d606b0f..cc47c453b 100644
--- a/debian/copyright
+++ b/assets/debian-template/copyright
@@ -1,18 +1,18 @@
 This work was packaged for Debian by:
 
-    Marco Zafra <marco.a.zafra@gmail.com>  Mon, 26 Nov 2018 14:31:00 -0500
+    ${PACKAGE_NAME_EMAIL}  ${__PACKAGE_DATETIME}
 
 It was downloaded from:
 
-    <http://srb2.org>
+    ${PACKAGE_WEBSITE}
 
 Upstream Author(s):
 
-    Sonic Team Junior <stjr@srb2.org>
+    ${PACKAGE_GROUP_NAME_EMAIL}
 
 Copyright:
 
-    Copyright (C) 1998-2018 Sonic Team Junior
+    Copyright (C) 1998-2018 by Sonic Team Junior
 
 License:
 
@@ -21,7 +21,7 @@ License:
 The Debian packaging is:
 
     Copyright (C) 2010 Callum Dickinson <gcfreak_ag20@hotmail.com>
-    Copyright (C) 2010-2018 Sonic Team Junior <stjr@srb2.org>
+    Copyright (C) 2010-2018 by Sonic Team Junior <stjr@srb2.org>
 
 and is licensed under the GPL version 2,
 see "/usr/share/common-licenses/GPL-2".
diff --git a/assets/debian/rules b/assets/debian-template/rules
old mode 100755
new mode 100644
similarity index 70%
rename from assets/debian/rules
rename to assets/debian-template/rules
index a34a3393f..c2d19922d
--- a/assets/debian/rules
+++ b/assets/debian-template/rules
@@ -23,6 +23,16 @@
 #
 #############################################################################
 
+#############################################################################
+#
+# !!!!!!!!!! DEPLOYER NOTE !!!!!!!!!!
+#
+# Variables to be templated are curly-braced ${PACKAGE_INSTALL_PATH}
+# Variables used by the rules script are parenthese'd $(DATADIR)
+# See [repo-root]/debian_template.sh
+#
+#############################################################################
+
 # Uncomment this to turn on verbose mode.
 #export DH_VERBOSE=1
 
@@ -37,30 +47,32 @@ RM	:= rm -rf
 DIR	:= $(shell pwd)
 
 PACKAGE := $(shell cat $(DIR)/debian/control | grep 'Package:' | sed -e 's/Package: //g')
-DATAFILES := srb2.srb zones.dta player.dta rings.dta music.dta patch.dta README.txt LICENSE.txt LICENSE-3RD-PARTY.txt
+ARCHIVEPATH := ${ASSET_ARCHIVE_PATH}
+ARCHIVEOPTIONALPATH := ${ASSET_ARCHIVE_OPTIONAL_PATH}
+GETOPTIONALFILES := ${ASSET_FILES_OPTIONAL_GET}
 
-DATADIR	:= usr/games/SRB2
+DATADIR	:= $(shell echo "${PACKAGE_INSTALL_PATH}" | sed -e 's/^\///')
 RESOURCEDIR := .
+STAGINGDIR := $(RESOURCEDIR)/installer
 WGET	:= wget -P $(RESOURCEDIR) -c -nc
 
 build:
 	$(MKDIR) $(DIR)/debian/tmp/$(DATADIR)
 	> $(DIR)/debian/source/include-binaries
-	# This will need to be updated every time SRB2 official version is
 	# Copy data files to their install locations, and add data files to include-binaries
-	for file in $(DATAFILES); do \
-		if [ ! -f $(RESOURCEDIR)/$$file ]; then \
-			$(WGET) http://alam.srb2.org/SRB2/2.1.21-Final/Resources/$$file; \
+	if [ ! -d $(STAGINGDIR) ]; then \
+		mkdir -p "$(STAGINGDIR)"; \
+		$(WGET) $(ARCHIVEPATH); \
+		7z x "$(RESOURCEDIR)/$(shell basename $(ARCHIVEPATH))" -aos; \
+		if [ "$(GETOPTIONALFILES)" = "1" ]; then \
+			$(WGET) $(ARCHIVEOPTIONALPATH); \
+			7z x "$(RESOURCEDIR)/$(shell basename $(ARCHIVEOPTIONALPATH))" -aos; \
 		fi; \
-		if [ -f $(RESOURCEDIR)/$$file ]; then \
-			$(INSTALL) $(RESOURCEDIR)/$$file $(DIR)/debian/tmp/$(DATADIR)/$$file; \
-			echo $(RESOURCEDIR)/$$file >> $(DIR)/debian/source/include-binaries; \
-		fi; \
-		if [ ! -f $(DIR)/debian/tmp/$(DATADIR)/$$file ]; then \
-			echo $(DIR)/debian/tmp/$(DATADIR)/$$file not found and could not be downloaded!; \
-			return 1; \
-		fi; \
-	done
+	fi
+	# Install asset directory and add asset file to include-binaries
+	cp -vr "$(STAGINGDIR)/." "$(DIR)/debian/tmp/$(DATADIR)"
+	find "$(STAGINGDIR)" >> $(DIR)/debian/source/include-binaries
+
 
 binary-indep:
 	# Generate install folder file
diff --git a/assets/debian/source/format b/assets/debian-template/source/format
similarity index 100%
rename from assets/debian/source/format
rename to assets/debian-template/source/format
diff --git a/assets/debian/source/options b/assets/debian-template/source/options
similarity index 100%
rename from assets/debian/source/options
rename to assets/debian-template/source/options
diff --git a/assets/debian/changelog b/assets/debian/changelog
deleted file mode 100644
index f3a92e1cd..000000000
--- a/assets/debian/changelog
+++ /dev/null
@@ -1,19 +0,0 @@
-srb2-data (2.1.21~7) trusty; urgency=high
-
-  * Updated for SRB2 v2.1.21
-
- -- Marco Zafra <marco.a.zafra@gmail.com>  Mon, 26 Nov 2018 14:31:00 -0500
-
-
-srb2-data (2.1.14~1) unstable; urgency=low
-
-  * Updated for SRB2 v2.1.14
-
- -- Alam Arias <alam+debian@srb2.org>  Sat, 6 Jan 2016 11:00:00 -0500
-
-
-srb2-data (2.0.6-2) maverick; urgency=high
-
-  * Initial proper release..
-
- -- Callum Dickinson <gcfreak_ag20@hotmail.com>  Sat,  29 Jan 2011 01:18:42 +1300
diff --git a/debian/README.Debian b/debian-template/README.Debian
similarity index 62%
rename from debian/README.Debian
rename to debian-template/README.Debian
index 4b724816e..3aa52787e 100644
--- a/debian/README.Debian
+++ b/debian-template/README.Debian
@@ -10,10 +10,38 @@ and give them to your users to install with apt-key add. Thanks!
 
  -- Callum Dickinson <gcfreak_ag20@hotmail.com>  Fri, 26 Nov 2010 18:25:31 +1300
 
+---------------
+
+
+Templating
+
+Note that you MUST run [repo-root]/debian_template.sh before running debuild
+on these scripts! debian_template.sh fills these template files with working values.
+
+You should also set PACKAGE_NAME_EMAIL="John Doe <jdoe@example.com>" to match
+the identity of the key you will use to sign the package.
+
+
+Building for Launchpad PPA
+
+Use these steps to prepare building a source package for Launchpad:
+
+    1. cd [repo-root]
+    2. git reset --hard; git clean -fd; git clean -fx;
+       * Resets your repo folder to a committed state and removes untracked files
+       * If you built srb2-data in the assets/ folder, MAKE SURE THAT FOLDER DOES NOT HAVE ASSETS,
+         OR THEY MAY BE INCLUDED IN THE MAIN SOURCE PACKAGE!
+
+Build the source package:
+
+    1. source [repo-root]/debian_template.sh
+       * Initializes defaults for the package variables and fills in templates.
+    2. debuild -S (builds the source package for Launchpad)
+
 
 Signing for Launchpad PPA
 
-First, follow the above instructions to generate a GnuPG key with your identity. You will need
+First, follow Callum's instructions to generate a GnuPG key with your identity. You will need
 to publish the fingerprint of that key to Ubuntu's key server.
 
     https://help.ubuntu.com/community/GnuPrivacyGuardHowto#Uploading_the_key_to_Ubuntu_keyserver
@@ -25,22 +53,18 @@ upload signed source packages and publish them onto your PPA.
 IF YOU UPLOAD A PACKAGE and Launchpad does NOT send you a confirmation or rejection email, that
 means your key is not set up correctly with your Launchpad account.
 
+Finally, if your packages have not already been signed, follow these steps:
 
-Building for Launchpad PPA
+    1. cd ..
+       * Packages are located in the parent folder of where debuild was called
+    2. debsign "srb2_[version]_source.changes"
+       * You may need to specify -k [key-fingerprint]
 
-Use these steps to prepare building a source package for Launchpad:
 
-    1. cd [srb2repo]
-    2. git reset --hard; git clean -fd; git clean -fx;
-       * Resets your repo folder to a committed state and removes untracked files
-       * If you built srb2-data in the assets/ folder, MAKE SURE THAT FOLDER DOES NOT HAVE ASSETS,
-         OR THEY MAY BE INCLUDED IN THE MAIN SOURCE PACKAGE!
+Uploading for Launchpad PPA
 
-Building the source package takes just one step:
-
-    1. debuild -S (builds the source package for Launchpad)
-
-Then follow the instructions at <https://help.launchpad.net/Packaging/PPA/Uploading> to upload
+Follow the instructions at <https://help.launchpad.net/Packaging/PPA/Uploading> to upload
 to your PPA and have Launchpad build your binary deb packages.
 
+
  -- Marco Zafra <marco.a.zafra@gmail.com>  Mon, 26 Nov 2018 21:13:00 -0500
diff --git a/debian/README.source b/debian-template/README.source
similarity index 100%
rename from debian/README.source
rename to debian-template/README.source
diff --git a/debian-template/changelog b/debian-template/changelog
new file mode 100644
index 000000000..fb08908cd
--- /dev/null
+++ b/debian-template/changelog
@@ -0,0 +1,5 @@
+${PACKAGE_NAME} (${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION}) ${PACKAGE_DISTRO}; urgency=${PACKAGE_URGENCY}
+
+  * ${PROGRAM_NAME} v${PROGRAM_VERSION} program build
+
+ -- ${PACKAGE_NAME_EMAIL}  ${__PACKAGE_DATETIME}
diff --git a/debian/compat b/debian-template/compat
similarity index 100%
rename from debian/compat
rename to debian-template/compat
diff --git a/debian/control b/debian-template/control
similarity index 65%
rename from debian/control
rename to debian-template/control
index 0f2d8062b..e1348d704 100644
--- a/debian/control
+++ b/debian-template/control
@@ -1,24 +1,30 @@
 # SRB2 Debian package control file.
 
-Source: srb2
+Source: ${PACKAGE_NAME}
 Section: games
 Priority: extra
-Maintainer: Sonic Team Junior <stjr@srb2.org>
+Maintainer: ${PACKAGE_GROUP_NAME_EMAIL}
 Build-Depends: debhelper (>= 7.0.50~),
  libsdl2-dev,
  libsdl2-mixer-dev,
- libpng12-dev (>= 1.2.7) | libpng-dev,
+ libpng-dev | libpng16-dev | libpng12-dev (>= 1.2.7),
  zlib1g-dev,
  libgme-dev,
  libglu1-dev | libglu-dev,
  libosmesa6-dev | libgl-dev,
  nasm [i386]
 Standards-Version: 3.8.4
-Homepage: http://www.srb2.org
+Homepage: ${PACKAGE_WEBSITE}
 
-Package: srb2
+Package: ${PACKAGE_NAME}
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (>= 2.1.15), srb2-data (<= 2.1.23)
+Depends: ${SHLIBS_DEPENDS}, ${MISC_DEPENDS},
+ ${PACKAGE_NAME}-data (>> ${PACKAGE_ASSET_MINVERSION}), ${PACKAGE_NAME}-data (<< ${PACKAGE_ASSET_MAXVERSION}),
+ libsdl2-2.0-0,
+ libsdl2-mixer-2.0-0,
+ zlib1g,
+ libgme0,
+ libpng | libpng16-16 | libpng12-0
 Description: A cross-platform 3D Sonic fangame
  Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog
  fangame built using a modified version of the Doom Legacy
@@ -28,10 +34,10 @@ Description: A cross-platform 3D Sonic fangame
  and quite a lot of the fun that the original Sonic games provided.
 
 
-Package: srb2-dbg
+Package: ${PACKAGE_NAME}-dbg
 Architecture: any
-# FIXME: should be Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (= 2.1.14), srb2 but dh_shlibdeps is being an asshat
-Depends: libc6, ${misc:Depends}, srb2-data (>= 2.1.15), srb2-data (<= 2.1.23), srb2
+# FIXME: should be Depends: ${SHLIBS_DEPENDS}, ${MISC_DEPENDS}, srb2-data (= 2.1.14), srb2 but dh_shlibdeps is being an asshat
+Depends: libc6, ${MISC_DEPENDS}, ${PACKAGE_NAME}-data (>> ${PACKAGE_ASSET_MINVERSION}), ${PACKAGE_NAME}-data (<< ${PACKAGE_ASSET_MAXVERSION}), ${PACKAGE_NAME}
 Description: A cross-platform 3D Sonic fangame
  Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog
  fangame built using a modified version of the Doom Legacy
diff --git a/assets/debian/copyright b/debian-template/copyright
similarity index 57%
rename from assets/debian/copyright
rename to debian-template/copyright
index 97d606b0f..cc47c453b 100644
--- a/assets/debian/copyright
+++ b/debian-template/copyright
@@ -1,18 +1,18 @@
 This work was packaged for Debian by:
 
-    Marco Zafra <marco.a.zafra@gmail.com>  Mon, 26 Nov 2018 14:31:00 -0500
+    ${PACKAGE_NAME_EMAIL}  ${__PACKAGE_DATETIME}
 
 It was downloaded from:
 
-    <http://srb2.org>
+    ${PACKAGE_WEBSITE}
 
 Upstream Author(s):
 
-    Sonic Team Junior <stjr@srb2.org>
+    ${PACKAGE_GROUP_NAME_EMAIL}
 
 Copyright:
 
-    Copyright (C) 1998-2018 Sonic Team Junior
+    Copyright (C) 1998-2018 by Sonic Team Junior
 
 License:
 
@@ -21,7 +21,7 @@ License:
 The Debian packaging is:
 
     Copyright (C) 2010 Callum Dickinson <gcfreak_ag20@hotmail.com>
-    Copyright (C) 2010-2018 Sonic Team Junior <stjr@srb2.org>
+    Copyright (C) 2010-2018 by Sonic Team Junior <stjr@srb2.org>
 
 and is licensed under the GPL version 2,
 see "/usr/share/common-licenses/GPL-2".
diff --git a/debian/docs b/debian-template/docs
similarity index 100%
rename from debian/docs
rename to debian-template/docs
diff --git a/debian/rules b/debian-template/rules
old mode 100755
new mode 100644
similarity index 87%
rename from debian/rules
rename to debian-template/rules
index ff80d50bf..0a77624cb
--- a/debian/rules
+++ b/debian-template/rules
@@ -23,6 +23,16 @@
 #
 #############################################################################
 
+#############################################################################
+#
+# !!!!!!!!!! DEPLOYER NOTE !!!!!!!!!!
+#
+# Variables to be templated are curly-braced ${PACKAGE_INSTALL_PATH}
+# Variables used by the rules script are parenthese'd $(PKGDIR)
+# See [repo-root]/debian_template.sh
+#
+#############################################################################
+
 # Uncomment this to turn on verbose mode.
 #export DH_VERBOSE=1
 
@@ -50,16 +60,16 @@ DIR	:= $(shell pwd)
 
 # FIXME: hate hate hate head/tail hack :(
 CONTROLF = $(DIR)/debian/control
-PACKAGE  = srb2
-DBGPKG   = $(PACKAGE)-dbg
-TITLE	= Sonic Robo Blast 2
+PACKAGE  = ${PACKAGE_NAME}
+DBGPKG   = ${PACKAGE}-dbg
+TITLE	= ${PROGRAM_NAME}
 SECTION = Games/Action
-EXENAME = srb2
+EXENAME = ${PROGRAM_FILENAME}
 DBGNAME	= debug/$(EXENAME)
 
-PKGDIR	= usr/games/SRB2
+PKGDIR	= $(shell echo "${PACKAGE_INSTALL_PATH}" | sed -e 's/^\///')
 DBGDIR	= usr/lib/debug/$(PKGDIR)
-LINKDIR = usr/games
+LINKDIR = $(shell echo "${PACKAGE_LINK_PATH}" | sed -e 's/^\///')
 PIXMAPS_DIR = usr/share/pixmaps
 DESKTOP_DIR = usr/share/applications
 PREFIX	= $(shell test "$(CROSS_COMPILE_BUILD)" != "$(CROSS_COMPILE_HOST)" && echo "PREFIX=$(CROSS_COMPILE_HOST)")
@@ -102,8 +112,8 @@ binary-arch:
 	$(INSTALL) $(BINDIR)/$(EXENAME) $(DIR)/debian/tmp/$(PKGDIR)/$(PACKAGE)
 	$(INSTALL) $(BINDIR)/$(DBGNAME) $(DIR)/debian/tmp/$(DBGDIR)/$(PACKAGE)
 	# Install desktop file and banner image
-	$(INSTALL) $(DIR)/srb2.png $(DIR)/debian/tmp/usr/share/pixmaps
-	$(INSTALL) $(DIR)/debian/srb2.desktop $(DIR)/debian/tmp/usr/share/applications
+	$(INSTALL) $(DIR)/srb2.png $(DIR)/debian/tmp/usr/share/pixmaps/${PROGRAM_FILENAME}.png
+	$(INSTALL) $(DIR)/debian/srb2.desktop $(DIR)/debian/tmp/usr/share/applications/${PROGRAM_FILENAME}.desktop
 	# add compiled binaries to include-binaries
 	echo $(BINDIR)/$(EXENAME) >> $(DIR)/debian/source/include-binaries
 	echo $(BINDIR)/$(EXENAME) >> $(DIR)/debian/source/include-binaries
diff --git a/debian/source/format b/debian-template/source/format
similarity index 100%
rename from debian/source/format
rename to debian-template/source/format
diff --git a/debian/source/options b/debian-template/source/options
similarity index 81%
rename from debian/source/options
rename to debian-template/source/options
index 841c65a6f..1ef771ddf 100644
--- a/debian/source/options
+++ b/debian-template/source/options
@@ -2,7 +2,7 @@ tar-ignore = "assets/*.srb"
 tar-ignore = "assets/*.pk3"
 tar-ignore = "assets/*.dta"
 tar-ignore = "assets/*.wad"
-tar-ignore = "assets/debian/srb2-data/*"
+tar-ignore = "assets/debian/${PACKAGE_NAME}-data/*"
 tar-ignore = "assets/debian/tmp/*"
 tar-ignore = "*.obj"
 tar-ignore = "*.dep"
diff --git a/debian-template/srb2.desktop b/debian-template/srb2.desktop
new file mode 100644
index 000000000..07c7906e0
--- /dev/null
+++ b/debian-template/srb2.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=${PROGRAM_NAME}
+Comment=${PROGRAM_DESCRIPTION}
+Encoding=UTF-8
+Exec=${PACKAGE_INSTALL_PATH}/${PROGRAM_FILENAME}
+Icon=/usr/share/pixmaps/${PROGRAM_FILENAME}.png
+Terminal=false
+Type=Application
+StartupNotify=false
+Categories=Application;Game;
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index b06a78e2b..000000000
--- a/debian/changelog
+++ /dev/null
@@ -1,12 +0,0 @@
-srb2 (2.1.23~9) trusty; urgency=high
-
-  * SRB2 v2.1.23 release
-
- -- Marco Zafra <marco.a.zafra@gmail.com>  Mon, 27 Nov 2018 16:45:00 -0500
-
-
-srb2 (2.0.6-5) maverick; urgency=high
-
-  * Initial proper release..
-
- -- Callum Dickinson <gcfreak_ag20@hotmail.com>  Sat, 29 Jan 2011 01:18:42 +1300
diff --git a/debian/srb2.desktop b/debian/srb2.desktop
deleted file mode 100644
index 3a1cac9f6..000000000
--- a/debian/srb2.desktop
+++ /dev/null
@@ -1,10 +0,0 @@
-[Desktop Entry]
-Name=Sonic Robo Blast 2
-Comment=A free 3D Sonic the Hedgehog fangame closely inspired by the original Sonic games on the Sega Genesis.
-Encoding=UTF-8
-Exec=/usr/games/SRB2/srb2
-Icon=/usr/share/pixmaps/srb2.png
-Terminal=false
-Type=Application
-StartupNotify=false
-Categories=Application;Game;
diff --git a/debian_template.sh b/debian_template.sh
new file mode 100644
index 000000000..c1af3c19f
--- /dev/null
+++ b/debian_template.sh
@@ -0,0 +1,166 @@
+#!/bin/bash
+
+# Deployer for Travis-CI
+# Debian package templating
+#
+# Call this script BEFORE running debuild!
+# source ./debian_template.sh [clean] [main/asset]
+#
+# Before running this script,
+# you should also set PACKAGE_NAME_EMAIL="John Doe <jdoe@example.com>" to match
+# the identity of the key you will use to sign the package.
+#
+
+# Get script's actual path
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+
+# Recursive function for directory crawling
+# $1 = Directory root to crawl
+# $2 = Code to eval on file
+# $3 = Code to eval on directory
+# Exposes $dirtails, $dirlevel, and $dirtailname
+dirlevel=0 # initialize
+dirtails=()
+
+# Utility function to make dira/dirb/dirc string
+makedirtailname () {
+	dirtailname=""
+	for tail in $dirtails; do
+		if [[ "$dirtailname" == "" ]]; then
+			dirtailname="/$tail";
+		else
+			dirtailname="$dirtailname/$tail";
+		fi;
+	done;
+}
+
+evaldirectory () {
+	if [ -d "$1" ]; then
+		# Set contextual variables
+		# dirtails is an array of directory basenames after the crawl root
+		if (( $dirlevel > 0 )); then
+			dirtails+=( "$(basename $1)" );
+		else
+			dirtails=();
+		fi;
+		dirlevel=$((dirlevel+1));
+
+		# Generate directory path after the crawl root
+		makedirtailname;
+
+		# Eval our directory with the latest contextual info
+		# Don't eval on root
+		if (( $dirlevel > 1 )) && [[ "$3" != "" ]]; then
+			eval "$3";
+		fi;
+
+		# Iterate entries
+		for name in $1/*; do
+			if [ -d "$name" ]; then
+				# Name is a directory, but don't eval yet
+				# Recurse so our vars are updated
+				evaldirectory "$name" "$2" "$3";
+
+				# Decrement our directory level and remove a dirtail
+				unset 'dirtails[ ${#dirtails[@]}-1 ]';
+				dirlevel=$((dirlevel-1));
+				makedirtailname;
+			else
+				# Name is a file
+				if [ -f "$name" ] && [[ "$2" != "" ]]; then
+					eval "$2";
+				fi;
+			fi;
+		done;
+
+		# Reset our variables; we're done iterating
+		if (( $dirlevel == 1 )); then
+			dirlevel=0;
+		fi;
+	fi;
+}
+
+#
+# Initialize package parameter defaults
+#
+if [[ "$__DEBIAN_PARAMETERS_INITIALIZED" != "1" ]]; then
+	. ${DIR}/deployer/travis/deployer_defaults.sh;
+fi;
+
+# Clean up after ourselves; we only expect to run this script once
+# during buildboting
+__DEBIAN_PARAMETERS_INITIALIZED=0
+
+# for envsubst
+export __PACKAGE_DATETIME="$(date '+%a, %d %b %Y %H:%M:%S %z')"
+export __PACKAGE_DATETIME_DIGIT="$(date -u '+%Y%m%d%H%M%S')"
+
+if [[ "$PACKAGE_REVISION" == "" ]]; then
+	PACKAGE_REVISION="-$__PACKAGE_DATETIME_DIGIT";
+	__PACKAGE_REVISION_BY_DATE=1;
+	export PACKAGE_REVISION=${PACKAGE_REVISION}; # for envsubst
+fi;
+
+#
+# Clean the old debian/ directories
+#
+if [[ "$1" == "clean" ]]; then
+	toclean=$2;
+else
+	toclean=$1;
+fi;
+
+if [[ "$toclean" == "" ]] || [[ "$toclean" == "main" ]]; then
+	echo "Cleaning main package scripts";
+	if [[ ! -f ${DIR}/debian ]]; then
+		rm -rf ${DIR}/debian;
+	fi;
+fi;
+if [[ "$toclean" == "" ]] || [[ "$toclean" == "asset" ]]; then
+	echo "Cleaning asset package scripts";
+	if [[ ! -f ${DIR}/assets/debian ]]; then
+		rm -rf ${DIR}/assets/debian;
+	fi;
+fi;
+
+#
+# Make new templates
+#
+if [[ "$1" != "clean" ]]; then
+	totemplate=$1;
+
+	# HACK: ${shlibs:Depends} in the templates make the templating fail
+	# So just define replacemment variables
+	export SHLIBS_DEPENDS=${SHLIBS_DEPENDS};
+	export MISC_DEPENDS=${MISC_DEPENDS};
+	export DEBFILEVAR='$$file'; # used in assets/debian/rules
+
+	# Package parameters are exported for envsubst in deployer_defaults.sh
+
+	if [[ "$totemplate" == "" ]] || [[ "$totemplate" == "main" ]]; then
+		echo "Generating main package scripts";
+		fromroot=${DIR}/debian-template;
+		toroot=${DIR}/debian;
+		mkdir ${toroot};
+
+		evaldirectory ${fromroot} \
+			"cat \$name | envsubst > ${toroot}\${dirtailname}/\$( basename \$name )" \
+			"mkdir \"${toroot}\${dirtailname}\"";
+	fi;
+
+	if [[ "$totemplate" == "" ]] || [[ "$totemplate" == "asset" ]]; then
+		echo "Generating asset package scripts";
+		fromroot=${DIR}/assets/debian-template;
+		toroot=${DIR}/assets/debian;
+		mkdir ${toroot};
+
+		# Root dir to crawl; file eval; directory eval
+		evaldirectory ${fromroot} \
+			"cat \$name | envsubst > ${toroot}\${dirtailname}/\$( basename \$name )" \
+			"mkdir \"${toroot}\${dirtailname}\"";
+	fi;
+fi;
+
+if [[ "$__DPL_ACTIVE" != "1" ]] && [[ "$__PACKAGE_REVISION_BY_DATE" == "1" ]]; then
+	unset PACKAGE_REVISION; # so we can reset the date on subsequent runs
+fi;
diff --git a/deployer/travis/deployer.sh b/deployer/travis/deployer.sh
new file mode 100644
index 000000000..c88155d21
--- /dev/null
+++ b/deployer/travis/deployer.sh
@@ -0,0 +1,157 @@
+#!/bin/bash
+
+# Deployer for Travis-CI
+# Initialization
+#
+# Performs validity checks to ensure that Deployer is allowed to run
+# e.g., is an FTP hostname specified? Are we whitelisted by OSNAMES and BRANCHES?
+#
+# Set these environment variables in your Travis-CI settings, where they are stored securely.
+# See other shell scripts for more options.
+#
+# DPL_ENABLED = 1                       (leave blank to disable)
+# DPL_TAG_ENABLED = 1                   (run Deployer on all tags)
+# DPL_JOB_ENABLE_ALL = 1                (run Deployer on all jobs; leave blank to act on specific jobs, see below)
+# DPL_JOBNAMES = name1,name2            (whitelist of job names to allow uploading; leave blank to upload from all jobs)
+# DPL_OSNAMES = osx                     (whitelist of OS names to allow uploading; leave blank to upload from all OSes)
+# DPL_BRANCHES = master,branch1,branch2 (whitelist of branches to upload; leave blank to upload all branches)
+#
+# To enable Deployer on specific jobs, set _DPL_JOB_ENABLED=1 for that job. Example:
+# - matrix:
+#   - os: osx
+#     env:
+#     - _DPL_JOB_ENABLED=1
+#
+# DO NOT set __DPL_ACTIVE, because that would bypass these validity checks.
+
+# Validate Deployer state
+if [[ "$DPL_ENABLED" == "1" ]] && [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
+    # Test for base eligibility:
+    # Are we in a deployer branch? Or
+    # Are we in a release tag AND DPL_TAG_ENABLED=1?
+    if [[ $TRAVIS_BRANCH == *"deployer"* ]]; then
+        __DPL_BASE_ELIGIBLE=1;
+        __DPL_TERMINATE_EARLY_ELIGIBLE=1;
+    fi;
+
+    if [[ "$TRAVIS_TAG" != "" ]] && [[ "$DPL_TAG_ENABLED" == "1" ]]; then
+        __DPL_BASE_ELIGIBLE=1;
+        __DPL_TAG_ELIGIBLE=1;
+        __DPL_TERMINATE_EARLY_ELIGIBLE=1;
+    fi;
+
+    # Logging message for trigger word
+    if [[ "$__DPL_TAG_ELIGIBLE" != "1" ]] && [[ "$DPL_TRIGGER" != "" ]]; then
+        echo "Testing for trigger $DPL_TRIGGER, commit message: $TRAVIS_COMMIT_MESSAGE";
+        echo "[${DPL_TRIGGER}]";
+        echo "[${DPL_TRIGGER}-${_DPL_JOB_NAME}]";
+        echo "[${DPL_TRIGGER}-${TRAVIS_OS_NAME}]";
+    fi;
+
+    #
+    # Search for the trigger word
+    # Force enable if release tags are eligible
+    #
+    if [[ "$__DPL_TAG_ELIGIBLE" == "1" ]] || [[ "$DPL_TRIGGER" == "" ]] \
+    || [[ $TRAVIS_COMMIT_MESSAGE == *"[$DPL_TRIGGER]"* ]] \
+    || [[ $TRAVIS_COMMIT_MESSAGE == *"[${DPL_TRIGGER}-${_DPL_JOB_NAME}]"* ]] \
+    || [[ $TRAVIS_COMMIT_MESSAGE == *"[${DPL_TRIGGER}-${TRAVIS_OS_NAME}]"* ]]; then
+        #
+        # Whitelist by branch name
+        # Force enable if release tags are eligible
+        #
+        if [[ "$__DPL_TAG_ELIGIBLE" == "1" ]] || [[ "$DPL_BRANCHES" == "" ]] || [[ $DPL_BRANCHES == *"$TRAVIS_BRANCH"* ]]; then
+            # Set this so we only early-terminate builds when we are specifically deploying
+            # Trigger string and branch are encompassing conditions; the rest are job-specific
+            # This check only matters for deployer branches and when DPL_TERMINATE_TESTS=1,
+            # because we're filtering non-deployer jobs.
+            #
+            # __DPL_TRY_TERMINATE_EARLY is invalidated in .travis.yml if __DPL_ACTIVE=1
+            if [[ "$__DPL_TERMINATE_EARLY_ELIGIBLE" == "1" ]] && [[ "$DPL_TERMINATE_TESTS" == "1" ]]; then
+                __DPL_TRY_TERMINATE_EARLY=1;
+            fi;
+
+            #
+            # Is the job enabled for deployment?
+            #
+            if [[ "$DPL_JOB_ENABLE_ALL" == "1" ]] || [[ "$_DPL_JOB_ENABLED" == "1" ]]; then
+                #
+                # Whitelist by job names
+                #
+                if [[ "$DPL_JOBNAMES" == "" ]] || [[ "$_DPL_JOB_NAME" == "" ]] || [[ $DPL_JOBNAMES == *"$_DPL_JOB_NAME"* ]]; then
+                    #
+                    # Whitelist by OS names
+                    #
+                    if [[ "$DPL_OSNAMES" == "" ]] || [[ $DPL_OSNAMES == *"$TRAVIS_OS_NAME"* ]]; then
+                        # Base Deployer is eligible for becoming active
+
+                        # Are we building for Linux?
+                        if [[ "$_DPL_PACKAGE_BINARY" == "1" ]] || [[ "$_DPL_PACKAGE_SOURCE" == "1" ]]; then
+                            if [[ "$_DPL_PACKAGE_MAIN" == "1" ]] || [[ "$_DPL_PACKAGE_ASSET" == "1" ]]; then
+                                if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+                                    __DPL_DEBIAN_ACTIVE=1;
+                                fi;
+                            fi;
+                        fi;
+
+                        # Now check for deployment targets
+                        if [[ "$_DPL_FTP_TARGET" == "1" ]] && [[ "$DPL_FTP_HOSTNAME" != "" ]]; then
+                            if [[ "$TRAVIS_OS_HOST" == "linux" ]] && [[ "$DPL_FTP_PROTOCOL" == "ftp" ]]; then
+                                echo "Non-secure FTP will not work on Linux Travis-CI jobs!";
+                                echo "Try SFTP or another target. Details:";
+                                echo "https://blog.travis-ci.com/2018-07-23-the-tale-of-ftp-at-travis-ci";
+                            else
+                                if [[ "$__DPL_DEBIAN_ACTIVE" == "1" ]] || [[ "$_DPL_PACKAGE_BINARY" == "1" ]] || [[ "$_DPL_BINARY" == "1" ]]; then
+                                    echo "Deployer FTP target is enabled";
+                                    __DPL_FTP_ACTIVE=1;
+                                else
+                                    echo "Deployer FTP target cannot be enabled: You must specify _DPL_PACKAGE_BINARY=1,";
+                                    echo "and/or _DPL_BINARY=1 in your job's environment variables.";
+                                fi;
+                            fi;
+                        fi;
+
+                        if [[ "$_DPL_DPUT_TARGET" == "1" ]] && [[ "$__DPL_DEBIAN_ACTIVE" == "1" ]] \
+                        && [[ "$DPL_DPUT_INCOMING" != "" ]]; then
+                            if [[ "$DPL_DPUT_METHOD" == "ftp" ]]; then
+                                echo "DPUT will not work with non-secure FTP on Linux Travis-CI jobs!";
+                                echo "Try SFTP or another method for DPUT. Details:";
+                                echo "https://blog.travis-ci.com/2018-07-23-the-tale-of-ftp-at-travis-ci";
+                            else
+                                echo "Deployer DPUT target is enabled";
+                                __DPL_DPUT_ACTIVE=1;
+                            fi;
+                        fi;
+
+                        # If any deployment targets are active, then so is the Deployer at large
+                        if [[ "$__DPL_FTP_ACTIVE" == "1" ]] || [[ "$__DPL_DPUT_ACTIVE" == "1" ]]; then
+                            __DPL_ACTIVE=1;
+                        fi;
+                    fi;
+                fi;
+            fi;
+        fi;
+    else
+        if [[ "$DPL_TRIGGER" != "" ]]; then
+            echo "Testing for global trigger [$DPL_TRIGGER, commit message: $TRAVIS_COMMIT_MESSAGE";
+        fi;
+        if [[ "$DPL_TRIGGER" != "" ]] && [[ $TRAVIS_COMMIT_MESSAGE == *"[$DPL_TRIGGER"* ]]; then
+            if [[ "$__DPL_TAG_ELIGIBLE" == "1" ]] || [[ "$DPL_BRANCHES" == "" ]] || [[ $DPL_BRANCHES == *"$TRAVIS_BRANCH"* ]]; then
+                # This check only matters for deployer branches and when DPL_TERMINATE_TESTS=1,
+                # because we're filtering non-deployer jobs.
+                if [[ "$__DPL_TERMINATE_EARLY_ELIGIBLE" == "1" ]] && [[ "$DPL_TERMINATE_TESTS" == "1" ]]; then
+                    # Assume that some job received the trigger, so mark this for early termination
+                    __DPL_TRY_TERMINATE_EARLY=1;
+                fi;
+            fi;
+        fi;
+    fi;
+fi;
+
+if [[ "$__DPL_TRY_TERMINATE_EARLY" == "1" ]] && [[ "$__DPL_ACTIVE" != "1" ]]; then
+    echo "Deployer is active in another job";
+fi;
+
+if [[ "$__DPL_TRY_TERMINATE_EARLY" != "1" ]] && [[ "$__DPL_ACTIVE" != "1" ]]; then
+    echo "Deployer is not active";
+fi;
diff --git a/deployer/travis/deployer_build.sh b/deployer/travis/deployer_build.sh
new file mode 100644
index 000000000..3817f025d
--- /dev/null
+++ b/deployer/travis/deployer_build.sh
@@ -0,0 +1,190 @@
+#!/bin/bash
+
+# Deployer for Travis-CI
+# Build Script
+#
+# Builds the required targets depending on which sub-modules are enabled
+
+if [[ "$__DPL_FTP_ACTIVE" == "1" ]] || [[ "$__DPL_DPUT_ACTIVE" == "1" ]]; then
+	if [[ "$__DPL_DEBIAN_ACTIVE" == "1" ]]; then
+		echo "Building Debian package(s)"
+
+		sudo apt-get install devscripts debhelper fakeroot secure-delete expect;
+
+		# Build source packages first, since they zip up the entire source folder,
+		# binaries and all
+		if [[ "$_DPL_PACKAGE_MAIN" == "1" ]]; then
+			. ../debian_template.sh main;
+			OLDPWD=$PWD; # [repo]/build
+			cd ..; # repo root
+
+			if [[ "$_DPL_PACKAGE_SOURCE" == "1" ]]; then
+				echo "Building main source Debian package";
+				expect <(cat <<EOD
+spawn debuild -S -us -uc;
+expect "continue anyway? (y/n)"
+send "y\r"
+interact
+EOD
+);
+			fi;
+
+			if [[ "$_DPL_PACKAGE_BINARY" == "1" ]]; then
+				echo "Building main binary Debian package";
+				expect <(cat <<EOD
+spawn debuild -us -uc;
+expect "continue anyway? (y/n)"
+send "y\r"
+interact
+EOD
+);
+			fi;
+
+			cd $OLDPWD;
+		fi;
+
+		# Also an asset package
+		if [[ "$_DPL_PACKAGE_ASSET" == "1" ]]; then
+			. ../debian_template.sh asset;
+			OLDPWD=$PWD; # [repo]/build
+			cd ../assets;
+
+			# make sure the asset files exist, download them if they don't
+			#echo "Checking asset files for asset Debian package";
+			#debuild -T build;
+
+			if [[ "$_DPL_PACKAGE_SOURCE" == "1" ]]; then
+				echo "Building asset source Debian package";
+				expect <(cat <<EOD
+spawn debuild -S -us -uc;
+expect "continue anyway? (y/n)"
+send "y\r"
+interact
+EOD
+);
+			fi;
+
+			if [[ "$_DPL_PACKAGE_BINARY" == "1" ]]; then
+				echo "Building asset binary Debian package";
+				expect <(cat <<EOD
+spawn debuild -us -uc;
+expect "continue anyway? (y/n)"
+send "y\r"
+interact
+EOD
+);
+			fi;
+
+			cd $OLDPWD;
+		fi;
+
+		# Now sign our packages
+		if [[ "$DPL_PGP_KEY_PRIVATE" != "" ]] && [[ "$DPL_PGP_KEY_PASSPHRASE" != "" ]]; then
+			# Get the key to sign
+			# Do this AFTER debuild so that we can specify the passphrase in command line
+			echo "$DPL_PGP_KEY_PRIVATE" | base64 --decode > key.asc;
+			echo "$DPL_PGP_KEY_PASSPHRASE" > phrase.txt;
+			gpg --import key.asc;
+
+			if [[ "$_DPL_PACKAGE_MAIN" == "1" ]]; then
+				echo "Signing main package(s)";
+
+				PACKAGEFILENAME=${PACKAGE_NAME}_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				PACKAGEDBGFILENAME=${PACKAGE_NAME}-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGENIGHTLYFILENAME=${PACKAGE_NAME}-nightly_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGENIGHTLYDBGFILENAME=${PACKAGE_NAME}-nightly-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGEPATCHFILENAME=${PACKAGE_NAME}-patch_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGEPATCHDBGFILENAME=${PACKAGE_NAME}-patch-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGEPATCHNIGHTLYFILENAME=${PACKAGE_NAME}-patch-nightly_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGEPATCHNIGHTLYDBGFILENAME=${PACKAGE_NAME}-patch-nightly-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+
+				PACKAGEFILENAMES=(
+					$PACKAGEFILENAME
+					$PACKAGEDBGFILENAME
+					#$PACKAGENIGHTLYFILENAME
+					#$PACKAGENIGHTLYDBGFILENAME
+					#$PACKAGEPATCHFILENAME
+					#$PACKAGEPATCHDBGFILENAME
+					#$PACKAGEPATCHNIGHTLYFILENAME
+					#$PACKAGEPATCHNIGHTLYDBGFILENAME
+				);
+
+				# Main packages are in parent of root repo folder
+				OLDPWD=$PWD; # [repo]/build
+				cd ../..; # parent of repo root
+
+				for n in ${PACKAGEFILENAMES}; do
+					for f in ./$n*.changes; do
+						debsign --no-re-sign -p"gpg --passphrase-file $OLDPWD/phrase.txt --batch" "$f";
+					done;
+				done;
+
+				cd $OLDPWD;
+			fi;
+
+			if [[ "$_DPL_PACKAGE_ASSET" == "1" ]]; then
+				echo "Signing asset package(s)";
+
+				PACKAGEFILENAME=${PACKAGE_NAME}-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGENIGHTLYFILENAME=${PACKAGE_NAME}-nightly-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGEPATCHFILENAME=${PACKAGE_NAME}-patch-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+				#PACKAGEPATCHNIGHTLYFILENAME=${PACKAGE_NAME}-patch-nightly-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+
+				PACKAGEFILENAMES=(
+					$PACKAGEFILENAME
+					#$PACKAGENIGHTLYFILENAME
+					#$PACKAGEPATCHFILENAME
+					#$PACKAGEPATCHNIGHTLYFILENAME
+				)
+
+				# Asset packages are in root repo folder
+				OLDPWD=$PWD; # [repo]/build
+				cd ..; # repo root
+
+				for n in ${PACKAGEFILENAMES}; do
+					for f in ./$n*.changes; do
+						debsign --no-re-sign -p"gpg --passphrase-file $OLDPWD/phrase.txt --batch" "$f";
+					done;
+				done;
+
+				cd $OLDPWD;
+			fi;
+
+			# Delete the keys :eyes:
+			srm key.asc;
+			srm phrase.txt;
+		fi;
+	fi;
+
+	# all other OSes
+	if [[ "$TRAVIS_OS_NAME" != "linux" ]]; then
+		#
+		# Check for binary building
+		#
+		if [[ "$_DPL_BINARY" == "1" ]]; then
+			echo "Building a Binary";
+			make -k;
+		fi;
+
+		#
+		# Check for package building
+		#
+		if [[ "$_DPL_PACKAGE_BINARY" == "1" ]]; then
+			echo "Building a Package";
+
+			# Make an OSX package; superuser is required for library bundling
+			#
+			# HACK: OSX packaging can't write libraries to .app package unless we're superuser
+			# because the original library files don't have WRITE permission
+			# Bug may be sidestepped by using CHMOD_BUNDLE_ITEMS=TRUE
+			# But I don't know where this is set. Not `cmake -D...` because this var is ignored.
+			# https://cmake.org/Bug/view.php?id=9284
+			if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+				sudo make -k package;
+			else
+				# Some day, when Windows is supported, we'll just make a standard package
+				make -k package;
+			fi;
+		fi;
+	fi;
+fi;
diff --git a/deployer/travis/deployer_defaults.sh b/deployer/travis/deployer_defaults.sh
new file mode 100644
index 000000000..bccb7409a
--- /dev/null
+++ b/deployer/travis/deployer_defaults.sh
@@ -0,0 +1,105 @@
+#!/bin/bash
+
+# Deployer for Travis-CI
+# Default Variables
+#
+# Here are all of the user-set variables used by Deployer.
+# See the "Cross-platform deployment" page on SRB2 Wiki for documentation.
+
+# Core Parameters
+: ${DPL_ENABLED}                # Enable Deployer behavior; must be set for any deployment activity
+: ${DPL_TAG_ENABLED}            # Trigger Deployer for all tag releases
+: ${DPL_JOB_ENABLE_ALL}         # Enable all jobs for deployment
+: ${DPL_TERMINATE_TESTS}        # Terminate all build test jobs (used in .travis.yml)
+: ${DPL_TRIGGER}                # Use a [word] in the commit message to trigger Deployer
+: ${DPL_JOBNAMES}               # Trigger Deployer by job name
+: ${DPL_OSNAMES}                # Trigger Deployer by OS name (osx,linux)
+: ${DPL_BRANCHES}               # Trigger Deployer by git branch name
+
+# Job Parameters
+: ${_DPL_JOB_ENABLED}           # Enable Deployer for this specific job. DPL_ENABLED must be set too.
+: ${_DPL_JOB_NAME}              # Identifier for the job, used for logging and trigger word matching
+: ${_DPL_FTP_TARGET}            # Deploy to FTP
+: ${_DPL_DPUT_TARGET}           # Deploy to DPUT
+: ${_DPL_PACKAGE_SOURCE}        # Build packages into a Source distribution. Linux only.
+: ${_DPL_PACKAGE_BINARY}        # Build packages into a Binary distribution.
+: ${_DPL_PACKAGE_MAIN:=1}       # Build main installation package. Linux only; OS X assumes this.
+: ${_DPL_PACKAGE_ASSET}         # Build asset installation package. Linux only.
+
+# Asset File Parameters
+: ${ASSET_ARCHIVE_PATH:=https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-assets.7z}
+: ${ASSET_ARCHIVE_OPTIONAL_PATH:=https://github.com/mazmazz/SRB2/releases/download/SRB2_assets/SRB2-v2122-optional-assets.7z}
+: ${ASSET_FILES_HASHED:=srb2.srb zones.dta player.dta rings.dta patch.dta}
+: ${ASSET_FILES_DOCS:=README.txt LICENSE.txt LICENSE-3RD-PARTY.txt}
+: ${ASSET_FILES_OPTIONAL_GET:=0}
+
+# FTP Parameters
+: ${DPL_FTP_PROTOCOL}
+: ${DPL_FTP_USER}
+: ${DPL_FTP_PASS}
+: ${DPL_FTP_HOSTNAME}
+: ${DPL_FTP_PORT}
+: ${DPL_FTP_PATH}
+
+# DPUT Parameters
+: ${DPL_DPUT_DOMAIN:=ppa.launchpad.net}
+: ${DPL_DPUT_METHOD:=sftp}
+: ${DPL_DPUT_INCOMING}
+: ${DPL_DPUT_LOGIN:=anonymous}
+: ${DPL_SSH_KEY_PRIVATE}        # Base64-encoded private key file. Used to sign repository uploads
+: ${DPL_SSH_KEY_PASSPHRASE}     # Decodes the private key file.
+
+# Package Parameters
+: ${PACKAGE_NAME:=srb2}
+: ${PACKAGE_VERSION:=2.1.23}
+: ${PACKAGE_SUBVERSION}         # Highly recommended to set this to reflect the distro series target (e.g., ~18.04bionic)
+: ${PACKAGE_REVISION}           # Defaults to UTC timestamp
+: ${PACKAGE_INSTALL_PATH:=/usr/games/SRB2}
+: ${PACKAGE_LINK_PATH:=/usr/games}
+: ${PACKAGE_DISTRO:=trusty}
+: ${PACKAGE_URGENCY:=high}
+: ${PACKAGE_NAME_EMAIL:=Sonic Team Junior <stjr@srb2.org>}
+: ${PACKAGE_GROUP_NAME_EMAIL:=Sonic Team Junior <stjr@srb2.org>}
+: ${PACKAGE_WEBSITE:=<http://www.srb2.org>}
+
+: ${PACKAGE_ASSET_MINVERSION:=2.1.21}  # Number this the version BEFORE the actual required version, because we do a > check
+: ${PACKAGE_ASSET_MAXVERSION:=2.1.24}  # Number this the version AFTER the actual required version, because we do a < check
+
+: ${PROGRAM_NAME:=Sonic Robo Blast 2}
+: ${PROGRAM_VENDOR:=Sonic Team Junior}
+: ${PROGRAM_VERSION:=2.1.23}
+: ${PROGRAM_DESCRIPTION:=A free 3D Sonic the Hedgehog fangame closely inspired by the original Sonic games on the Sega Genesis.}
+: ${PROGRAM_FILENAME:=srb2}
+
+: ${DPL_PGP_KEY_PRIVATE}        # Base64-encoded private key file. Used to sign Debian packages
+: ${DPL_PGP_KEY_PASSPHRASE}     # Decodes the private key file.
+
+# Export Asset and Package Parameters for envsubst templating
+
+export ASSET_ARCHIVE_PATH="${ASSET_ARCHIVE_PATH}"
+export ASSET_ARCHIVE_OPTIONAL_PATH="${ASSET_ARCHIVE_OPTIONAL_PATH}"
+export ASSET_FILES_HASHED="${ASSET_FILES_HASHED}"
+export ASSET_FILES_DOCS="${ASSET_FILES_DOCS}"
+export ASSET_FILES_OPTIONAL_GET="${ASSET_FILES_OPTIONAL_GET}"
+
+export PACKAGE_NAME="${PACKAGE_NAME}"
+export PACKAGE_VERSION="${PACKAGE_VERSION}"
+export PACKAGE_SUBVERSION="${PACKAGE_SUBVERSION}" # in case we have this
+export PACKAGE_REVISION="${PACKAGE_REVISION}"
+export PACKAGE_ASSET_MINVERSION="${PACKAGE_ASSET_MINVERSION}"
+export PACKAGE_ASSET_MAXVERSION="${PACKAGE_ASSET_MAXVERSION}"
+export PACKAGE_INSTALL_PATH="${PACKAGE_INSTALL_PATH}"
+export PACKAGE_LINK_PATH="${PACKAGE_LINK_PATH}"
+export PACKAGE_DISTRO="${PACKAGE_DISTRO}"
+export PACKAGE_URGENCY="${PACKAGE_URGENCY}"
+export PACKAGE_NAME_EMAIL="${PACKAGE_NAME_EMAIL}"
+export PACKAGE_GROUP_NAME_EMAIL="${PACKAGE_GROUP_NAME_EMAIL}"
+export PACKAGE_WEBSITE="${PACKAGE_WEBSITE}"
+
+export PROGRAM_NAME="${PROGRAM_NAME}"
+export PROGRAM_VERSION="${PROGRAM_VERSION}"
+export PROGRAM_DESCRIPTION="${PROGRAM_DESCRIPTION}"
+export PROGRAM_FILENAME="${PROGRAM_FILENAME}"
+
+# This file is called in debian_template.sh, so mark our completion so we don't run it again
+__DEBIAN_PARAMETERS_INITIALIZED=1
diff --git a/deployer/travis/deployer_dput.sh b/deployer/travis/deployer_dput.sh
new file mode 100644
index 000000000..863a928cd
--- /dev/null
+++ b/deployer/travis/deployer_dput.sh
@@ -0,0 +1,133 @@
+#!/bin/bash
+
+# Deployer for Travis-CI
+# DPUT uploader (e.g., Launchpad PPA)
+#
+
+if [[ "$__DPL_DPUT_ACTIVE" == "1" ]]; then
+    # Install APT dependencies
+    # paramiko required for ssh
+    sudo apt-get install python-paramiko expect dput; # python-pip
+    #pip install paramiko;
+
+    # Output the DPUT config
+    # Dput only works if you're using secure FTP, so that's what we default to.
+    cat > "./dput.cf" << EOM
+[deployer]
+fqdn = ${DPL_DPUT_DOMAIN}
+method = ${DPL_DPUT_METHOD}
+incoming = ${DPL_DPUT_INCOMING}
+login = ${DPL_DPUT_LOGIN}
+allow_unsigned_uploads = 0
+EOM
+
+    # Output SSH config
+    # Don't let SSH prompt us for untrusted hosts
+    cat >> "./ssh_config" << EOM
+
+Host *
+    StrictHostKeyChecking no
+    UserKnownHostsFile=/dev/null
+    PubKeyAuthentication yes
+    IdentityFile ${PWD}/key.private
+    IdentitiesOnly yes
+EOM
+    sudo sh -c "cat < ${PWD}/ssh_config >> /etc/ssh/ssh_config";
+
+    # Get the private key
+    echo "$DPL_SSH_KEY_PRIVATE" | base64 --decode > key.private;
+    chmod 700 ./key.private;
+
+    if [[ "$_DPL_PACKAGE_MAIN" == "1" ]]; then
+        PACKAGEFILENAME=${PACKAGE_NAME}_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+        PACKAGEDBGFILENAME=${PACKAGE_NAME}-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+		#PACKAGENIGHTLYFILENAME=${PACKAGE_NAME}-nightly_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+		#PACKAGENIGHTLYDBGFILENAME=${PACKAGE_NAME}-nightly-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+        #PACKAGEPATCHFILENAME=${PACKAGE_NAME}-patch_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+		#PACKAGEPATCHDBGFILENAME=${PACKAGE_NAME}-patch-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+        #PACKAGEPATCHNIGHTLYFILENAME=${PACKAGE_NAME}-patch-nightly_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+		#PACKAGEPATCHNIGHTLYDBGFILENAME=${PACKAGE_NAME}-patch-nightly-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+
+        PACKAGEFILENAMES=(
+            $PACKAGEFILENAME
+            $PACKAGEDBGFILENAME
+            #$PACKAGENIGHTLYFILENAME
+            #$PACKAGENIGHTLYDBGFILENAME
+            #$PACKAGEPATCHFILENAME
+            #$PACKAGEPATCHDBGFILENAME
+            #$PACKAGEPATCHNIGHTLYFILENAME
+            #$PACKAGEPATCHNIGHTLYDBGFILENAME
+        );
+
+        # Main packages are in parent of root repo folder
+        OLDPWD=$PWD; # [repo]/build
+        cd ../..;
+
+        # Enter passphrase if required
+        for n in ${PACKAGEFILENAMES}; do
+            for f in $n*.changes; do
+                # Binary builds also generate source builds, so exclude the source
+                # builds if desired
+                if [[ "$_DPL_PACKAGE_SOURCE" != "1" ]]; then
+                    if [[ "$f" == *"_source"* ]] || [[ "$f" == *".tar.xz"* ]]; then
+                        continue;
+                    fi;
+                fi;
+
+                expect <(cat <<EOD
+spawn dput -c "${OLDPWD}/dput.cf" deployer "$f";
+expect "Enter passphrase for key"
+send "${DPL_SSH_KEY_PASSPHRASE}\r"
+interact
+EOD
+);
+            done;
+        done;
+
+        # Go back to [repo]/build folder
+        cd $OLDPWD;
+    fi;
+
+    if [[ "$_DPL_PACKAGE_ASSET" == "1" ]]; then
+        PACKAGEFILENAME=${PACKAGE_NAME}-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+        #PACKAGENIGHTLYFILENAME=${PACKAGE_NAME}-nightly-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+        #PACKAGEPATCHFILENAME=${PACKAGE_NAME}-patch-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+        #PACKAGEPATCHNIGHTLYFILENAME=${PACKAGE_NAME}-patch-nightly-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+
+        PACKAGEFILENAMES=(
+            $PACKAGEFILENAME
+            #$PACKAGENIGHTLYFILENAME
+            #$PACKAGEPATCHFILENAME
+            #$PACKAGEPATCHNIGHTLYFILENAME
+        )
+
+        # Asset packages are in root repo folder
+        OLDPWD=$PWD; # [repo]/build
+        cd ..;
+
+        # Enter passphrase if required
+        for n in ${PACKAGEFILENAMES}; do
+            for f in $n*.changes; do
+                # Binary builds also generate source builds, so exclude the source
+                # builds if desired
+                if [[ "$_DPL_PACKAGE_SOURCE" != "1" ]]; then
+                    if [[ "$f" == *"_source"* ]] || [[ "$f" == *".tar.xz"* ]]; then
+                        continue;
+                    fi;
+                fi;
+                expect <(cat <<EOD
+spawn dput -c "${OLDPWD}/dput.cf" deployer "$f";
+expect "Enter passphrase for key"
+send "${DPL_SSH_KEY_PASSPHRASE}\r"
+interact
+EOD
+);
+            done;
+        done;
+
+        # Go back to [repo]/build folder
+        cd $OLDPWD;
+    fi;
+
+    srm ./key.private;
+fi;
diff --git a/deployer/travis/deployer_ftp.sh b/deployer/travis/deployer_ftp.sh
new file mode 100644
index 000000000..1f6bd08b5
--- /dev/null
+++ b/deployer/travis/deployer_ftp.sh
@@ -0,0 +1,137 @@
+#!/bin/bash
+
+# Deployer for Travis-CI
+# FTP Uploader
+#
+# Package files are uploaded to, e.g., ftp://username:password@example.com:21/path/to/upload/STJr/SRB2/master/460873812-151.1
+# With file `commit.txt` and folder(s) `bin` and `package`
+#
+# Set these environment variables in your Travis-CI settings, where they are stored securely.
+# See other shell scripts for more options.
+#
+# DPL_FTP_PROTOCOL = ftp                    (ftp or sftp or ftps or however your FTP URI begins)
+# DPL_FTP_USER = username
+# DPL_FTP_PASS = password
+# DPL_FTP_HOSTNAME = example.com
+# DPL_FTP_PORT = 21
+# DPL_FTP_PATH = path/to/upload             (do not add trailing slash)
+
+if [[ "$__DPL_FTP_ACTIVE" == "1" ]]; then
+	if [[ "$TRAVIS_JOB_NAME" != "" ]]; then
+		JOBNAME=$TRAVIS_JOB_NAME;
+	else
+		if [[ "$_DPL_JOB_NAME" != "" ]]; then
+			JOBNAME=$_DPL_JOB_NAME;
+		else
+			JOBNAME=$TRAVIS_OS_NAME;
+		fi;
+	fi;
+
+	# Generate commit.txt file
+	echo "Travis-CI Build $TRAVIS_OS_NAME - $TRAVIS_REPO_SLUG/$TRAVIS_BRANCH - $TRAVIS_JOB_NUMBER - $JOBNAME" > "commit.txt";
+	echo "Job ID $TRAVIS_JOB_ID" >> "commit.txt";
+	echo "" >> "commit.txt";
+	echo "Commit $TRAVIS_COMMIT" >> "commit.txt";
+	echo "$TRAVIS_COMMIT_MESSAGE" >> "commit.txt";
+	echo "" >> "commit.txt";
+
+	# Initialize FTP parameters
+	if [[ "$DPL_FTP_PORT" == "" ]]; then
+		DPL_FTP_PORT=21;
+	fi;
+	if [[ "$DPL_FTP_PROTOCOL" == "" ]]; then
+		DPL_FTP_PROTOCOL=ftp;
+	fi;
+	__DPL_FTP_LOCATION=$DPL_FTP_PROTOCOL://$DPL_FTP_HOSTNAME:$DPL_FTP_PORT/$DPL_FTP_PATH/$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH/$TRAVIS_JOB_ID-$TRAVIS_JOB_NUMBER-$JOBNAME;
+
+	# Upload to FTP!
+	echo "Uploading to FTP...";
+	curl --ftp-create-dirs -T "commit.txt" -u $DPL_FTP_USER:$DPL_FTP_PASS "$__DPL_FTP_LOCATION/commit.txt";
+
+	if [[ "$__DPL_DEBIAN_ACTIVE" == "1" ]]; then
+		if [[ "$_DPL_PACKAGE_MAIN" == "1" ]]; then
+			PACKAGEFILENAME=${PACKAGE_NAME}_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			PACKAGEDBGFILENAME=${PACKAGE_NAME}-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGENIGHTLYFILENAME=${PACKAGE_NAME}-nightly_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGENIGHTLYDBGFILENAME=${PACKAGE_NAME}-nightly-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGEPATCHFILENAME=${PACKAGE_NAME}-patch_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGEPATCHDBGFILENAME=${PACKAGE_NAME}-patch-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGEPATCHNIGHTLYFILENAME=${PACKAGE_NAME}-patch-nightly_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGEPATCHNIGHTLYDBGFILENAME=${PACKAGE_NAME}-patch-nightly-dbg_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+
+			PACKAGEFILENAMES=(
+				$PACKAGEFILENAME
+				$PACKAGEDBGFILENAME
+				#$PACKAGENIGHTLYFILENAME
+				#$PACKAGENIGHTLYDBGFILENAME
+				#$PACKAGEPATCHFILENAME
+				#$PACKAGEPATCHDBGFILENAME
+				#$PACKAGEPATCHNIGHTLYFILENAME
+				#$PACKAGEPATCHNIGHTLYDBGFILENAME
+			);
+
+			# Main packages are in parent of root repo folder
+			OLDPWD=$PWD; # [repo]/build
+			cd ../..;
+
+			for n in ${PACKAGEFILENAMES}; do
+				for f in ./$n*; do
+					# Binary builds also generate source builds, so exclude the source
+					# builds if desired
+					if [[ "$_DPL_PACKAGE_SOURCE" != "1" ]]; then
+						if [[ "$f" == *"_source"* ]] || [[ "$f" == *".tar.xz"* ]]; then
+							continue;
+						fi;
+					fi;
+					curl --ftp-create-dirs -T "$f" -u $DPL_FTP_USER:$DPL_FTP_PASS  "$__DPL_FTP_LOCATION/package/main/$f";
+				done;
+			done;
+
+			# Go back to [repo]/build folder
+			cd $OLDPWD;
+		fi;
+
+		if [[ "$_DPL_PACKAGE_ASSET" == "1" ]]; then
+			PACKAGEFILENAME=${PACKAGE_NAME}-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGENIGHTLYFILENAME=${PACKAGE_NAME}-nightly-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGEPATCHFILENAME=${PACKAGE_NAME}-patch-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+			#PACKAGEPATCHNIGHTLYFILENAME=${PACKAGE_NAME}-patch-nightly-data_${PACKAGE_VERSION}${PACKAGE_SUBVERSION}${PACKAGE_REVISION};
+
+			PACKAGEFILENAMES=(
+				$PACKAGEFILENAME
+				#$PACKAGENIGHTLYFILENAME
+				#$PACKAGEPATCHFILENAME
+				#$PACKAGEPATCHNIGHTLYFILENAME
+			)
+
+			# Asset packages are in root repo folder
+			OLDPWD=$PWD; # [repo]/build
+			cd ..;
+
+			for n in ${PACKAGEFILENAMES}; do
+				for f in ./$n*; do
+					# Binary builds also generate source builds, so exclude the source
+					# builds if desired
+					if [[ "$_DPL_PACKAGE_SOURCE" != "1" ]]; then
+						if [[ "$f" == *"_source"* ]] || [[ "$f" == *".tar.xz"* ]]; then
+							continue;
+						fi;
+					fi;
+					curl --ftp-create-dirs -T "$f" -u $DPL_FTP_USER:$DPL_FTP_PASS  "$__DPL_FTP_LOCATION/package/asset/$f";
+				done;
+			done;
+
+			# Go back to [repo]/build folder
+			cd $OLDPWD;
+		fi;
+	else
+		if [[ "$_DPL_BINARY" == "1" ]]; then
+			find bin -type f -exec curl -u $DPL_FTP_USER:$DPL_FTP_PASS --ftp-create-dirs -T {} $__DPL_FTP_LOCATION/{} \;;
+		fi;
+
+		if [[ "$_DPL_PACKAGE_BINARY" == "1" ]]; then
+			sudo rm -r package/_CPack_Packages
+			find package -type f -exec curl -u $DPL_FTP_USER:$DPL_FTP_PASS --ftp-create-dirs -T {} $__DPL_FTP_LOCATION/{} \;;
+		fi;
+	fi;
+fi
diff --git a/libs/libgme.props b/libs/libgme.props
new file mode 100644
index 000000000..209f6b9a8
--- /dev/null
+++ b/libs/libgme.props
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Platform)' == 'Win32' OR '$(Platform)' == 'x64'">
+    <IncludePath>$(SolutionDir)libs\gme\include;$(IncludePath)</IncludePath>
+    <LibraryPath Condition="'$(Platform)' == 'Win32'">$(SolutionDir)libs\gme\win32;$(LibraryPath)</LibraryPath>
+    <LibraryPath Condition="'$(Platform)' == 'x64'">$(SolutionDir)libs\gme\win64;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)' == 'Win32' OR '$(Platform)' == 'x64'">
+    <Link>
+      <AdditionalDependencies>libgme.dll.a;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup />
+</Project>
\ No newline at end of file
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index c43cfe82a..dd9fa8423 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -1266,21 +1266,24 @@ UINT8 *HWR_GetScreenshot(void)
 	return buf;
 }
 
-boolean HWR_Screenshot(const char *lbmname)
+boolean HWR_Screenshot(const char *pathname)
 {
 	boolean ret;
 	UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
 
 	if (!buf)
+	{
+		CONS_Debug(DBG_RENDER, "HWR_Screenshot: Failed to allocate memory\n");
 		return false;
+	}
 
 	// returns 24bit 888 RGB
 	HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
 
 #ifdef USE_PNG
-	ret = M_SavePNG(lbmname, buf, vid.width, vid.height, false);
+	ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL);
 #else
-	ret = saveTGA(lbmname, buf, vid.width, vid.height);
+	ret = saveTGA(pathname, buf, vid.width, vid.height);
 #endif
 	free(buf);
 	return ret;
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index ced8f837d..fdfc1d257 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -39,8 +39,6 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
 void HWR_DrawViewBorder(INT32 clearlines);
 void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum);
-UINT8 *HWR_GetScreenshot(void);
-boolean HWR_Screenshot(const char *lbmname);
 void HWR_InitTextureMapping(void);
 void HWR_SetViewSize(void);
 void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option);
@@ -54,6 +52,9 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color);
 void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 options);	// Lat: separate flags from color since color needs to be an uint to work right.
 void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum);
 
+UINT8 *HWR_GetScreenshot(void);
+boolean HWR_Screenshot(const char *pathname);
+
 void HWR_AddCommands(void);
 void HWR_CorrectSWTricks(void);
 void transform(float *cx, float *cy, float *cz);
diff --git a/src/info.h b/src/info.h
index fbe8ed8d7..5482af60b 100644
--- a/src/info.h
+++ b/src/info.h
@@ -253,7 +253,7 @@ void A_LookForBetter();
 void A_Boss5BombExplode();
 
 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
-#define NUMMOBJFREESLOTS 256
+#define NUMMOBJFREESLOTS 512
 #define NUMSPRITEFREESLOTS NUMMOBJFREESLOTS
 #define NUMSTATEFREESLOTS (NUMMOBJFREESLOTS*8)
 
diff --git a/src/m_misc.c b/src/m_misc.c
index c967548c6..621d705f9 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -30,6 +30,7 @@
 #include "g_game.h"
 #include "m_misc.h"
 #include "hu_stuff.h"
+#include "st_stuff.h"
 #include "v_video.h"
 #include "z_zone.h"
 #include "g_input.h"
@@ -609,6 +610,23 @@ void M_SaveConfig(const char *filename)
 	fclose(f);
 }
 
+// ==========================================================================
+//                              SCREENSHOTS
+// ==========================================================================
+static UINT8 screenshot_palette[768];
+static void M_CreateScreenShotPalette(void)
+{
+	size_t i, j;
+	for (i = 0, j = 0; i < 768; i += 3, j++)
+	{
+		RGBA_t locpal = ((cv_screenshot_colorprofile.value)
+		? pLocalPalette[(max(st_palette,0)*256)+j]
+		: pMasterPalette[(max(st_palette,0)*256)+j]);
+		screenshot_palette[i] = locpal.s.red;
+		screenshot_palette[i+1] = locpal.s.green;
+		screenshot_palette[i+2] = locpal.s.blue;
+	}
+}
 
 #if NUMSCREENS > 2
 static const char *Newsnapshotfile(const char *pathname, const char *ext)
@@ -677,25 +695,20 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext)
 	CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
 }
 
-static void M_PNGhdr(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_uint_32 width, PNG_CONST png_uint_32 height, const boolean palette)
+static void M_PNGhdr(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_uint_32 width, PNG_CONST png_uint_32 height, PNG_CONST png_byte *palette)
 {
 	const png_byte png_interlace = PNG_INTERLACE_NONE; //PNG_INTERLACE_ADAM7
 	if (palette)
 	{
 		png_colorp png_PLTE = png_malloc(png_ptr, sizeof(png_color)*256); //palette
+		const png_byte *pal = palette;
 		png_uint_16 i;
-
-		RGBA_t *pal = ((cv_screenshot_colorprofile.value)
-		? pLocalPalette
-		: pMasterPalette);
-
 		for (i = 0; i < 256; i++)
 		{
-			png_PLTE[i].red   = pal[i].s.red;
-			png_PLTE[i].green = pal[i].s.green;
-			png_PLTE[i].blue  = pal[i].s.blue;
+			png_PLTE[i].red   = *pal; pal++;
+			png_PLTE[i].green = *pal; pal++;
+			png_PLTE[i].blue  = *pal; pal++;
 		}
-
 		png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE,
 		 png_interlace, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 		png_write_info_before_PLTE(png_ptr, png_info_ptr);
@@ -968,7 +981,7 @@ static void M_PNGfix_acTL(png_structp png_ptr, png_infop png_info_ptr,
 #endif
 }
 
-static boolean M_SetupaPNG(png_const_charp filename, boolean palette)
+static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal)
 {
 	apng_FILE = fopen(filename,"wb+"); // + mode for reading
 	if (!apng_FILE)
@@ -1020,7 +1033,7 @@ static boolean M_SetupaPNG(png_const_charp filename, boolean palette)
 	png_set_compression_strategy(apng_ptr, cv_zlib_strategya.value);
 	png_set_compression_window_bits(apng_ptr, cv_zlib_window_bitsa.value);
 
-	M_PNGhdr(apng_ptr, apng_info_ptr, vid.width, vid.height, palette);
+	M_PNGhdr(apng_ptr, apng_info_ptr, vid.width, vid.height, pal);
 
 	M_PNGText(apng_ptr, apng_info_ptr, true);
 
@@ -1044,6 +1057,7 @@ static boolean M_SetupaPNG(png_const_charp filename, boolean palette)
 static inline moviemode_t M_StartMovieAPNG(const char *pathname)
 {
 #ifdef USE_APNG
+	UINT8 *palette;
 	const char *freename = NULL;
 	boolean ret = false;
 
@@ -1059,10 +1073,8 @@ static inline moviemode_t M_StartMovieAPNG(const char *pathname)
 		return MM_OFF;
 	}
 
-	if (rendermode == render_soft)
-		ret = M_SetupaPNG(va(pandf,pathname,freename), true);
-	else
-		ret = M_SetupaPNG(va(pandf,pathname,freename), false);
+	if (rendermode == render_soft) M_CreateScreenShotPalette();
+	ret = M_SetupaPNG(va(pandf,pathname,freename), (palette = screenshot_palette));
 
 	if (!ret)
 	{
@@ -1265,13 +1277,14 @@ void M_StopMovie(void)
   * \param data     The image data.
   * \param width    Width of the picture.
   * \param height   Height of the picture.
-  * \param palette  Palette of image data
+  * \param palette  Palette of image data.
   *  \note if palette is NULL, BGR888 format
   */
-boolean M_SavePNG(const char *filename, void *data, int width, int height, const boolean palette)
+boolean M_SavePNG(const char *filename, void *data, int width, int height, const UINT8 *palette)
 {
 	png_structp png_ptr;
 	png_infop png_info_ptr;
+	PNG_CONST png_byte *PLTE = (const png_byte *)palette;
 #ifdef PNG_SETJMP_SUPPORTED
 #ifdef USE_FAR_KEYWORD
 	jmp_buf jmpbuf;
@@ -1286,8 +1299,7 @@ boolean M_SavePNG(const char *filename, void *data, int width, int height, const
 		return false;
 	}
 
-	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
-	 PNG_error, PNG_warn);
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn);
 	if (!png_ptr)
 	{
 		CONS_Debug(DBG_RENDER, "M_SavePNG: Error on initialize libpng\n");
@@ -1334,7 +1346,7 @@ boolean M_SavePNG(const char *filename, void *data, int width, int height, const
 	png_set_compression_strategy(png_ptr, cv_zlib_strategy.value);
 	png_set_compression_window_bits(png_ptr, cv_zlib_window_bits.value);
 
-	M_PNGhdr(png_ptr, png_info_ptr, width, height, palette);
+	M_PNGhdr(png_ptr, png_info_ptr, width, height, PLTE);
 
 	M_PNGText(png_ptr, png_info_ptr, false);
 
@@ -1381,7 +1393,7 @@ typedef struct
   * \param palette  Palette of image data
   */
 #if NUMSCREENS > 2
-static boolean WritePCXfile(const char *filename, const UINT8 *data, int width, int height)
+static boolean WritePCXfile(const char *filename, const UINT8 *data, int width, int height, const UINT8 *pal)
 {
 	int i;
 	size_t length;
@@ -1425,15 +1437,11 @@ static boolean WritePCXfile(const char *filename, const UINT8 *data, int width,
 
 	// write color table
 	{
-		RGBA_t *pal = ((cv_screenshot_colorprofile.value)
-		? pLocalPalette
-		: pMasterPalette);
-
 		for (i = 0; i < 256; i++)
 		{
-			*pack++ = pal[i].s.red;
-			*pack++ = pal[i].s.green;
-			*pack++ = pal[i].s.blue;
+			*pack++ = *pal; pal++;
+			*pack++ = *pal; pal++;
+			*pack++ = *pal; pal++;
 		}
 	}
 
@@ -1453,9 +1461,8 @@ void M_ScreenShot(void)
 }
 
 /** Takes a screenshot.
-  * The screenshot is saved as "srb2xxxx.pcx" (or "srb2xxxx.tga" in hardware
-  * rendermode) where xxxx is the lowest four-digit number for which a file
-  * does not already exist.
+  * The screenshot is saved as "srb2xxxx.png" where xxxx is the lowest
+  * four-digit number for which a file does not already exist.
   *
   * \sa HWR_ScreenShot
   */
@@ -1469,6 +1476,10 @@ void M_DoScreenShot(void)
 	// Don't take multiple screenshots, obviously
 	takescreenshot = false;
 
+	// how does one take a screenshot without a render system?
+	if (rendermode == render_none)
+		return;
+
 	if (cv_screenshot_option.value == 0)
 		pathname = usehome ? srb2home : srb2path;
 	else if (cv_screenshot_option.value == 1)
@@ -1479,16 +1490,13 @@ void M_DoScreenShot(void)
 		pathname = cv_screenshot_folder.string;
 
 #ifdef USE_PNG
-	if (rendermode != render_none)
-		freename = Newsnapshotfile(pathname,"png");
+	freename = Newsnapshotfile(pathname,"png");
 #else
 	if (rendermode == render_soft)
 		freename = Newsnapshotfile(pathname,"pcx");
-	else if (rendermode != render_none)
+	else if (rendermode == render_opengl)
 		freename = Newsnapshotfile(pathname,"tga");
 #endif
-	else
-		I_Error("Can't take a screenshot without a render system");
 
 	if (rendermode == render_soft)
 	{
@@ -1502,16 +1510,16 @@ void M_DoScreenShot(void)
 
 	// save the pcx file
 #ifdef HWRENDER
-	if (rendermode != render_soft)
+	if (rendermode == render_opengl)
 		ret = HWR_Screenshot(va(pandf,pathname,freename));
 	else
 #endif
-	if (rendermode != render_none)
 	{
+		M_CreateScreenShotPalette();
 #ifdef USE_PNG
-		ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, true);
+		ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
 #else
-		ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height);
+		ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
 #endif
 	}
 
@@ -1519,14 +1527,14 @@ failure:
 	if (ret)
 	{
 		if (moviemode != MM_SCREENSHOT)
-			CONS_Printf(M_GetText("screen shot %s saved in %s\n"), freename, pathname);
+			CONS_Printf(M_GetText("Screen shot %s saved in %s\n"), freename, pathname);
 	}
 	else
 	{
 		if (freename)
-			CONS_Printf(M_GetText("Couldn't create screen shot %s in %s\n"), freename, pathname);
+			CONS_Alert(CONS_ERROR, M_GetText("Couldn't create screen shot %s in %s\n"), freename, pathname);
 		else
-			CONS_Printf(M_GetText("Couldn't create screen shot (all 10000 slots used!) in %s\n"), pathname);
+			CONS_Alert(CONS_ERROR, M_GetText("Couldn't create screen shot in %s (all 10000 slots used!)\n"), pathname);
 
 		if (moviemode == MM_SCREENSHOT)
 			M_StopMovie();
diff --git a/src/m_misc.h b/src/m_misc.h
index 28d9cd5a5..6ac92dbcc 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -58,7 +58,7 @@ void FIL_ForceExtension(char *path, const char *extension);
 boolean FIL_CheckExtension(const char *in);
 
 #ifdef HAVE_PNG
-boolean M_SavePNG(const char *filename, void *data, int width, int height, const boolean palette);
+boolean M_SavePNG(const char *filename, void *data, int width, int height, const UINT8 *palette);
 #endif
 
 extern boolean takescreenshot;
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index 7f8f052ba..de2157055 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -153,7 +153,7 @@ if(${SDL2_FOUND})
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
 		)
-		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "Sonic Robo Blast 2")
+		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
 	else()
 		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_LIBRARIES}
@@ -337,10 +337,19 @@ if(${SDL2_FOUND})
 
 
 	# Mac bundle fixup
+	# HACK: THIS IS IMPORTANT! See the escaped \${CMAKE_INSTALL_PREFIX}? This
+	# makes it so that var is evaluated LATER during cpack, not right now!
+	# This fixes the quirk where the bundled libraries don't land in the final package
+	# https://cmake.org/pipermail/cmake/2011-March/043532.html
+	#
+	# HOWEVER: ${CPACK_PACKAGE_DESCRIPTION_SUMMARY} is NOT escaped, because that var
+	# is only available to us at this step. Read the link: ${CMAKE_INSTALL_PREFIX} at
+	# this current step points to the CMAKE build folder, NOT the folder that CPACK uses.
+	# Therefore, it makes sense to escape that var, but not the other.
 	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		install(CODE "
 			include(BundleUtilities)
-			fixup_bundle(\"${CMAKE_INSTALL_PREFIX}/Sonic Robo Blast 2.app\"
+			fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${CPACK_PACKAGE_DESCRIPTION_SUMMARY}.app\"
 				\"\"
 				/Library/Frameworks
 			)"
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index e43772179..ee5df4dcb 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -93,6 +93,7 @@
     <Import Project="..\..\libs\libpng.props" />
     <Import Project="..\..\libs\SDL2.props" />
     <Import Project="..\..\libs\SDL_mixer.props" />
+    <Import Project="..\..\libs\libgme.props" />
     <Import Project="Srb2SDL.props" />
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
diff --git a/src/sdl/Srb2SDL.props b/src/sdl/Srb2SDL.props
index 260f81eed..75839a5b2 100644
--- a/src/sdl/Srb2SDL.props
+++ b/src/sdl/Srb2SDL.props
@@ -5,7 +5,10 @@
   <PropertyGroup />
   <ItemDefinitionGroup>
     <ClCompile>
-      <PreprocessorDefinitions>USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;SDLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <!-- x86/x64 defines: has specific libraries that ARM does not -->
+      <PreprocessorDefinitions Condition="'$(Platform)' == 'Win32' OR '$(Platform)' == 'x64'">HAVE_ZLIB;HAVE_LIBGME;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;SDLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <!-- ARM defines -->
+      <PreprocessorDefinitions Condition="'$(Platform)' != 'Win32' AND '$(Platform)' != 'x64'">USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;SDLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
   </ItemDefinitionGroup>
   <ItemGroup />
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index a8ecbf7f8..878db3d8d 100644
--- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1219,7 +1219,7 @@
 		C01FCF4B08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.23;
+				CURRENT_PROJECT_VERSION = 2.1.24;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					NORMALSRB2,
@@ -1231,7 +1231,7 @@
 		C01FCF4C08A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.23;
+				CURRENT_PROJECT_VERSION = 2.1.24;
 				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
 				GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/sounds.h b/src/sounds.h
index fd1142aba..90c7d9ac6 100644
--- a/src/sounds.h
+++ b/src/sounds.h
@@ -42,7 +42,7 @@ typedef enum
 } skinsound_t;
 
 // free sfx for S_AddSoundFx()
-#define NUMSFXFREESLOTS 800 // Matches SOC Editor.
+#define NUMSFXFREESLOTS 1600 // Matches SOC Editor.
 #define NUMSKINSFXSLOTS (MAXSKINS*NUMSKINSOUNDS)
 
 //
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 9ad04b5ce..4509ed849 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -190,7 +190,7 @@ void ST_Ticker(void)
 }
 
 // 0 is default, any others are special palettes.
-static INT32 st_palette = 0;
+INT32 st_palette = 0;
 
 void ST_doPaletteStuff(void)
 {
diff --git a/src/st_stuff.h b/src/st_stuff.h
index e1d8a8a92..aca4e60d2 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -58,6 +58,7 @@ boolean ST_SameTeam(player_t *a, player_t *b);
 //--------------------
 
 extern boolean st_overlay; // sb overlay on or off when fullscreen
+extern INT32 st_palette; // 0 is default, any others are special palettes.
 
 extern lumpnum_t st_borderpatchnum;
 // patches, also used in intermission
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 774ce5cbe..acab2507a 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -91,6 +91,7 @@
     <Import Project="..\..\libs\FMOD.props" />
     <Import Project="..\..\libs\zlib.props" />
     <Import Project="..\..\libs\libpng.props" />
+    <Import Project="..\..\libs\libgme.props" />
     <Import Project="SRB2Win.props" />
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
diff --git a/src/win32/Srb2win.props b/src/win32/Srb2win.props
index 44a30d50d..fa152f0c9 100644
--- a/src/win32/Srb2win.props
+++ b/src/win32/Srb2win.props
@@ -5,7 +5,10 @@
   <PropertyGroup />
   <ItemDefinitionGroup>
     <ClCompile>
-      <PreprocessorDefinitions>_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <!-- x86/x64 defines: has specific libraries that ARM does not -->
+      <PreprocessorDefinitions Condition="'$(Platform)' == 'Win32' OR '$(Platform)' == 'x64'">HAVE_ZLIB;HAVE_LIBGME;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <!-- ARM defines -->
+      <PreprocessorDefinitions Condition="'$(Platform)' != 'Win32' AND '$(Platform)' != 'x64'">_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link />
     <Link>