diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8ecee2b19d8d372a0b2c4e22d88eab3907eb6597..67a3b66b7f759be472dd6c13b93712d2aeef0388 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -43,7 +43,7 @@ jobs:
             - v1-SRB2-APT
       - run:
           name: Install SDK
-          command: apt-get -qq -y --no-install-recommends install git build-essential nasm libpng-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 gettext ccache wget gcc-multilib upx openssh-client
+          command: apt-get -qq -y --no-install-recommends install git build-essential nasm libpng-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 libcurl4-openssl-dev:i386 libopenmpt-dev:i386 gettext ccache wget gcc-multilib upx openssh-client
 
       - save_cache:
           key: v1-SRB2-APT
@@ -71,4 +71,4 @@ jobs:
       - save_cache:
           key: v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
           paths:
-            - /root/.ccache
\ No newline at end of file
+            - /root/.ccache
diff --git a/.travis.yml b/.travis.yml
index 9d91b77dfc937a48da16ead5cf80298711e92da5..789426be7f3792c46cb04a4115d8169d2aaff31a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,6 +26,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.4
           compiler: gcc-4.4
@@ -43,6 +44,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.6
           compiler: gcc-4.6
@@ -60,6 +62,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.7
           compiler: gcc-4.7
@@ -83,6 +86,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -101,6 +105,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-7
           compiler: gcc-7
@@ -119,6 +124,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-8
           compiler: gcc-8
@@ -141,6 +147,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - clang-3.5
           compiler: clang-3.5
@@ -159,6 +166,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - clang-3.6
           compiler: clang-3.6
@@ -177,6 +185,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - clang-3.7
           compiler: clang-3.7
@@ -195,6 +204,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - clang-3.8
           compiler: clang-3.8
@@ -213,6 +223,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - clang-3.9
           compiler: clang-3.9
@@ -323,6 +334,7 @@ matrix:
               - libpng-dev
               - libgl1-mesa-dev
               - libgme-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -468,6 +480,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -495,6 +508,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -522,6 +536,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -549,6 +564,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -576,6 +592,7 @@ matrix:
               - libgl1-mesa-dev
               - libgme-dev
               - libopenmpt-dev
+              - libcurl4-openssl-dev
               - p7zip-full
               - gcc-4.8
           compiler: gcc-4.8
@@ -619,6 +636,7 @@ addons:
     - libgme-dev
     - zlib1g-dev
     - libopenmpt-dev
+    - libcurl4-openssl-dev
     - p7zip-full
   homebrew:
     taps:
@@ -629,6 +647,7 @@ addons:
     - p7zip
     - libopenmpt
     - cmake
+    - curl
     update: true
 
 
diff --git a/Doxyfile b/Doxyfile
index d11fa2bbc6d0e2d61697759c6be6023e944af95b..eb8c6ae9eb53f8b20fe8d7f0902c16cf39d166b2 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -109,13 +109,10 @@ FILE_PATTERNS          = *.c \
                          *.mm \
                          *.dox
 RECURSIVE              = YES
-EXCLUDE                = ./src/djgppdos/internal.h \
-                         ./src/djgppdos/setup.c \
-                         ./src/sdl/IMG_xpm.c \
+EXCLUDE                = ./src/sdl/IMG_xpm.c \
                          ./src/sdl/SRB2DC/scramble.c
 EXCLUDE_SYMLINKS       = NO
 EXCLUDE_PATTERNS       = */src/hardware/*/* \
-                         */src/djgppdos/bcd.? \
                          */src/sdl/SDL_main/* \
                          */src/*/*_private.h \
                          */src/sdl/*/*help.? \
diff --git a/appveyor.yml b/appveyor.yml
index 820c77e8b0c5a05b7ff6bdaa441e7048a23c86fa..2acc2f71235be24cd7190e511ee5106f16bcc295 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 2.2.6.{branch}-{build}
+version: 2.2.8.{branch}-{build}
 os: MinGW
 
 environment:
diff --git a/bin/Dos/Debug/.gitignore b/bin/Dos/Debug/.gitignore
deleted file mode 100644
index 42c6dc2c662642792a8860e166dfd81126695e8f..0000000000000000000000000000000000000000
--- a/bin/Dos/Debug/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# DON'T REMOVE
-# This keeps the folder from disappearing
diff --git a/bin/Dos/Release/.gitignore b/bin/Dos/Release/.gitignore
deleted file mode 100644
index 42c6dc2c662642792a8860e166dfd81126695e8f..0000000000000000000000000000000000000000
--- a/bin/Dos/Release/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# DON'T REMOVE
-# This keeps the folder from disappearing
diff --git a/debian-template/control b/debian-template/control
index 74d11ae9023215f91120d549078042bd5bdfade0..88334f132ecaff78d534183bf23a3d862720dd61 100644
--- a/debian-template/control
+++ b/debian-template/control
@@ -11,6 +11,7 @@ Build-Depends: debhelper (>= 7.0.50~),
  zlib1g-dev,
  libgme-dev,
  libopenmpt-dev,
+ libcurl4-openssl-dev,
  libglu1-dev | libglu-dev,
  libosmesa6-dev | libgl-dev,
  nasm [i386]
diff --git a/libs/curl/include/curl/curl.h b/libs/curl/include/curl/curl.h
index ee9754da8cc75ff0e9b48bfeefac46b3f111ad11..b7cb30a581b031e1fd575e874a1395fc3c0cc1e5 100644
--- a/libs/curl/include/curl/curl.h
+++ b/libs/curl/include/curl/curl.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_CURL_H
-#define __CURL_CURL_H
+#ifndef CURLINC_CURL_H
+#define CURLINC_CURL_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -24,23 +24,26 @@
 
 /*
  * If you have libcurl problems, all docs and details are found here:
- *   http://curl.haxx.se/libcurl/
+ *   https://curl.haxx.se/libcurl/
  *
  * curl-library mailing list subscription and unsubscription web interface:
- *   http://cool.haxx.se/mailman/listinfo/curl-library/
+ *   https://cool.haxx.se/mailman/listinfo/curl-library/
  */
 
+#ifdef CURL_NO_OLDIES
+#define CURL_STRICTER
+#endif
+
 #include "curlver.h"         /* libcurl version defines   */
-#include "curlbuild.h"       /* libcurl build definitions */
-#include "curlrules.h"       /* libcurl rules enforcement */
+#include "system.h"          /* determine things run-time */
 
 /*
- * Define WIN32 when build target is Win32 API
+ * Define CURL_WIN32 when build target is Win32 API
  */
 
-#if (defined(_WIN32) || defined(__WIN32__)) && \
-     !defined(WIN32) && !defined(__SYMBIAN32__)
-#define WIN32
+#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) &&        \
+  !defined(__SYMBIAN32__)
+#define CURL_WIN32
 #endif
 
 #include <stdio.h>
@@ -55,74 +58,79 @@
 #include <sys/types.h>
 #include <time.h>
 
-#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \
-  !defined(__CYGWIN__) || defined(__MINGW32__)
-#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H))
+#if defined(CURL_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
+      defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
 /* The check above prevents the winsock2 inclusion if winsock.h already was
    included, since they can't co-exist without problems */
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #endif
-#else
+#endif
 
 /* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
-   libc5-based Linux systems. Only include it on system that are known to
+   libc5-based Linux systems. Only include it on systems that are known to
    require it! */
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
-    defined(ANDROID) || \
+    defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+    defined(__CYGWIN__) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
 #include <sys/select.h>
 #endif
 
-#ifndef _WIN32_WCE
+#if !defined(CURL_WIN32) && !defined(_WIN32_WCE)
 #include <sys/socket.h>
 #endif
-#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+
+#if !defined(CURL_WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
 #include <sys/time.h>
 #endif
-#include <sys/types.h>
-#endif
 
 #ifdef __BEOS__
 #include <support/SupportDefs.h>
 #endif
 
+/* Compatibility for non-Clang compilers */
+#ifndef __has_declspec_attribute
+#  define __has_declspec_attribute(x) 0
+#endif
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-typedef void CURL;
-
-/*
- * Decorate exportable functions for Win32 and Symbian OS DLL linking.
- * This avoids using a .def file for building libcurl.dll.
- */
-#if (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) && \
-     !defined(CURL_STATICLIB)
-#if defined(BUILDING_LIBCURL)
-#define CURL_EXTERN  __declspec(dllexport)
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_easy CURL;
+typedef struct Curl_share CURLSH;
 #else
-#define CURL_EXTERN  __declspec(dllimport)
+typedef void CURL;
+typedef void CURLSH;
 #endif
-#else
 
-#ifdef CURL_HIDDEN_SYMBOLS
 /*
- * This definition is used to make external definitions visible in the
- * shared library when symbols are hidden by default.  It makes no
- * difference when compiling applications whether this is set or not,
- * only when compiling the library.
+ * libcurl external API function linkage decorations.
  */
-#define CURL_EXTERN CURL_EXTERN_SYMBOL
+
+#ifdef CURL_STATICLIB
+#  define CURL_EXTERN
+#elif defined(CURL_WIN32) || defined(__SYMBIAN32__) || \
+     (__has_declspec_attribute(dllexport) && \
+      __has_declspec_attribute(dllimport))
+#  if defined(BUILDING_LIBCURL)
+#    define CURL_EXTERN  __declspec(dllexport)
+#  else
+#    define CURL_EXTERN  __declspec(dllimport)
+#  endif
+#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS)
+#  define CURL_EXTERN CURL_EXTERN_SYMBOL
 #else
-#define CURL_EXTERN
-#endif
+#  define CURL_EXTERN
 #endif
 
 #ifndef curl_socket_typedef
 /* socket typedef */
-#ifdef WIN32
+#if defined(CURL_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
 typedef SOCKET curl_socket_t;
 #define CURL_SOCKET_BAD INVALID_SOCKET
 #else
@@ -132,46 +140,103 @@ typedef int curl_socket_t;
 #define curl_socket_typedef
 #endif /* curl_socket_typedef */
 
+/* enum for the different supported SSL backends */
+typedef enum {
+  CURLSSLBACKEND_NONE = 0,
+  CURLSSLBACKEND_OPENSSL = 1,
+  CURLSSLBACKEND_GNUTLS = 2,
+  CURLSSLBACKEND_NSS = 3,
+  CURLSSLBACKEND_OBSOLETE4 = 4,  /* Was QSOSSL. */
+  CURLSSLBACKEND_GSKIT = 5,
+  CURLSSLBACKEND_POLARSSL = 6,
+  CURLSSLBACKEND_WOLFSSL = 7,
+  CURLSSLBACKEND_SCHANNEL = 8,
+  CURLSSLBACKEND_SECURETRANSPORT = 9,
+  CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */
+  CURLSSLBACKEND_MBEDTLS = 11,
+  CURLSSLBACKEND_MESALINK = 12,
+  CURLSSLBACKEND_BEARSSL = 13
+} curl_sslbackend;
+
+/* aliases for library clones and renames */
+#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL
+
+/* deprecated names: */
+#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
+#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT
+
 struct curl_httppost {
   struct curl_httppost *next;       /* next entry in the list */
   char *name;                       /* pointer to allocated name */
   long namelength;                  /* length of name length */
   char *contents;                   /* pointer to allocated data contents */
-  long contentslength;              /* length of contents field */
+  long contentslength;              /* length of contents field, see also
+                                       CURL_HTTPPOST_LARGE */
   char *buffer;                     /* pointer to allocated buffer contents */
   long bufferlength;                /* length of buffer field */
   char *contenttype;                /* Content-Type */
-  struct curl_slist* contentheader; /* list of extra headers for this form */
+  struct curl_slist *contentheader; /* list of extra headers for this form */
   struct curl_httppost *more;       /* if one field name has more than one
                                        file, this link should link to following
                                        files */
   long flags;                       /* as defined below */
-#define HTTPPOST_FILENAME (1<<0)    /* specified content is a file name */
-#define HTTPPOST_READFILE (1<<1)    /* specified content is a file name */
-#define HTTPPOST_PTRNAME (1<<2)     /* name is only stored pointer
-                                       do not free in formfree */
-#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
-                                       do not free in formfree */
-#define HTTPPOST_BUFFER (1<<4)      /* upload file from buffer */
-#define HTTPPOST_PTRBUFFER (1<<5)   /* upload file from pointer contents */
-#define HTTPPOST_CALLBACK (1<<6)    /* upload file contents by using the
-                                       regular read callback to get the data
-                                       and pass the given pointer as custom
-                                       pointer */
+
+/* specified content is a file name */
+#define CURL_HTTPPOST_FILENAME (1<<0)
+/* specified content is a file name */
+#define CURL_HTTPPOST_READFILE (1<<1)
+/* name is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRNAME (1<<2)
+/* contents is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
+/* upload file from buffer */
+#define CURL_HTTPPOST_BUFFER (1<<4)
+/* upload file from pointer contents */
+#define CURL_HTTPPOST_PTRBUFFER (1<<5)
+/* upload file contents by using the regular read callback to get the data and
+   pass the given pointer as custom pointer */
+#define CURL_HTTPPOST_CALLBACK (1<<6)
+/* use size in 'contentlen', added in 7.46.0 */
+#define CURL_HTTPPOST_LARGE (1<<7)
 
   char *showfilename;               /* The file name to show. If not set, the
                                        actual file name will be used (if this
                                        is a file part) */
   void *userp;                      /* custom pointer used for
                                        HTTPPOST_CALLBACK posts */
+  curl_off_t contentlen;            /* alternative length of contents
+                                       field. Used if CURL_HTTPPOST_LARGE is
+                                       set. Added in 7.46.0 */
 };
 
+
+/* This is a return code for the progress callback that, when returned, will
+   signal libcurl to continue executing the default progress function */
+#define CURL_PROGRESSFUNC_CONTINUE 0x10000001
+
+/* This is the CURLOPT_PROGRESSFUNCTION callback prototype. It is now
+   considered deprecated but was the only choice up until 7.31.0 */
 typedef int (*curl_progress_callback)(void *clientp,
                                       double dltotal,
                                       double dlnow,
                                       double ultotal,
                                       double ulnow);
 
+/* This is the CURLOPT_XFERINFOFUNCTION callback prototype. It was introduced
+   in 7.32.0, avoids the use of floating point numbers and provides more
+   detailed information. */
+typedef int (*curl_xferinfo_callback)(void *clientp,
+                                      curl_off_t dltotal,
+                                      curl_off_t dlnow,
+                                      curl_off_t ultotal,
+                                      curl_off_t ulnow);
+
+#ifndef CURL_MAX_READ_SIZE
+  /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */
+#define CURL_MAX_READ_SIZE 524288
+#endif
+
 #ifndef CURL_MAX_WRITE_SIZE
   /* Tests have proven that 20K is a very bad buffer size for uploads on
      Windows, while 16K for some odd reason performed a lot better.
@@ -189,16 +254,18 @@ typedef int (*curl_progress_callback)(void *clientp,
 #define CURL_MAX_HTTP_HEADER (100*1024)
 #endif
 
-
 /* This is a magic return code for the write callback that, when returned,
    will signal libcurl to pause receiving on the current transfer. */
 #define CURL_WRITEFUNC_PAUSE 0x10000001
+
 typedef size_t (*curl_write_callback)(char *buffer,
                                       size_t size,
                                       size_t nitems,
                                       void *outstream);
 
-
+/* This callback will be called when a new resolver request is made */
+typedef int (*curl_resolver_start_callback)(void *resolver_state,
+                                            void *reserved, void *userdata);
 
 /* enumeration of file types */
 typedef enum {
@@ -223,14 +290,11 @@ typedef enum {
 #define CURLFINFOFLAG_KNOWN_SIZE        (1<<6)
 #define CURLFINFOFLAG_KNOWN_HLINKCOUNT  (1<<7)
 
-/* Content of this structure depends on information which is known and is
-   achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man
-   page for callbacks returning this structure -- some fields are mandatory,
-   some others are optional. The FLAG field has special meaning. */
+/* Information about a single file, used when doing FTP wildcard matching */
 struct curl_fileinfo {
   char *filename;
   curlfiletype filetype;
-  time_t time;
+  time_t time; /* always zero! */
   unsigned int perm;
   int uid;
   int gid;
@@ -249,7 +313,7 @@ struct curl_fileinfo {
   unsigned int flags;
 
   /* used internally */
-  char * b_data;
+  char *b_data;
   size_t b_size;
   size_t b_used;
 };
@@ -305,14 +369,25 @@ typedef int (*curl_seek_callback)(void *instream,
    signal libcurl to pause sending data on the current transfer. */
 #define CURL_READFUNC_PAUSE 0x10000001
 
+/* Return code for when the trailing headers' callback has terminated
+   without any errors*/
+#define CURL_TRAILERFUNC_OK 0
+/* Return code for when was an error in the trailing header's list and we
+  want to abort the request */
+#define CURL_TRAILERFUNC_ABORT 1
+
 typedef size_t (*curl_read_callback)(char *buffer,
                                       size_t size,
                                       size_t nitems,
                                       void *instream);
 
-typedef enum  {
-  CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
-  CURLSOCKTYPE_LAST   /* never use */
+typedef int (*curl_trailer_callback)(struct curl_slist **list,
+                                      void *userdata);
+
+typedef enum {
+  CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
+  CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
+  CURLSOCKTYPE_LAST    /* never use */
 } curlsocktype;
 
 /* The return code from the sockopt_callback can signal information back
@@ -341,6 +416,9 @@ typedef curl_socket_t
                             curlsocktype purpose,
                             struct curl_sockaddr *address);
 
+typedef int
+(*curl_closesocket_callback)(void *clientp, curl_socket_t item);
+
 typedef enum {
   CURLIOE_OK,            /* I/O operation successful */
   CURLIOE_UNKNOWNCMD,    /* command was unknown to callback */
@@ -348,7 +426,7 @@ typedef enum {
   CURLIOE_LAST           /* never use */
 } curlioerr;
 
-typedef enum  {
+typedef enum {
   CURLIOCMD_NOP,         /* no operation */
   CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
   CURLIOCMD_LAST         /* never use */
@@ -358,6 +436,7 @@ typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
                                          int cmd,
                                          void *clientp);
 
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
 /*
  * The following typedef's are signatures of malloc, free, realloc, strdup and
  * calloc respectively.  Function pointers of these types can be passed to the
@@ -370,6 +449,9 @@ typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
 typedef char *(*curl_strdup_callback)(const char *str);
 typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
 
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
+
 /* the kind of data that is passed to information_callback*/
 typedef enum {
   CURLINFO_TEXT = 0,
@@ -406,17 +488,22 @@ typedef enum {
   CURLE_COULDNT_RESOLVE_PROXY,   /* 5 */
   CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
   CURLE_COULDNT_CONNECT,         /* 7 */
-  CURLE_FTP_WEIRD_SERVER_REPLY,  /* 8 */
+  CURLE_WEIRD_SERVER_REPLY,      /* 8 */
   CURLE_REMOTE_ACCESS_DENIED,    /* 9 a service was denied by the server
                                     due to lack of access - when login fails
                                     this is not returned. */
-  CURLE_OBSOLETE10,              /* 10 - NOT USED */
+  CURLE_FTP_ACCEPT_FAILED,       /* 10 - [was obsoleted in April 2006 for
+                                    7.15.4, reused in Dec 2011 for 7.24.0]*/
   CURLE_FTP_WEIRD_PASS_REPLY,    /* 11 */
-  CURLE_OBSOLETE12,              /* 12 - NOT USED */
+  CURLE_FTP_ACCEPT_TIMEOUT,      /* 12 - timeout occurred accepting server
+                                    [was obsoleted in August 2007 for 7.17.0,
+                                    reused in Dec 2011 for 7.24.0]*/
   CURLE_FTP_WEIRD_PASV_REPLY,    /* 13 */
   CURLE_FTP_WEIRD_227_FORMAT,    /* 14 */
   CURLE_FTP_CANT_GET_HOST,       /* 15 */
-  CURLE_OBSOLETE16,              /* 16 - NOT USED */
+  CURLE_HTTP2,                   /* 16 - A problem in the http2 framing layer.
+                                    [was obsoleted in August 2007 for 7.17.0,
+                                    reused in July 2014 for 7.38.0] */
   CURLE_FTP_COULDNT_SET_TYPE,    /* 17 */
   CURLE_PARTIAL_FILE,            /* 18 */
   CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
@@ -445,18 +532,17 @@ typedef enum {
   CURLE_LDAP_CANNOT_BIND,        /* 38 */
   CURLE_LDAP_SEARCH_FAILED,      /* 39 */
   CURLE_OBSOLETE40,              /* 40 - NOT USED */
-  CURLE_FUNCTION_NOT_FOUND,      /* 41 */
+  CURLE_FUNCTION_NOT_FOUND,      /* 41 - NOT USED starting with 7.53.0 */
   CURLE_ABORTED_BY_CALLBACK,     /* 42 */
   CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
   CURLE_OBSOLETE44,              /* 44 - NOT USED */
   CURLE_INTERFACE_FAILED,        /* 45 - CURLOPT_INTERFACE failed */
   CURLE_OBSOLETE46,              /* 46 - NOT USED */
-  CURLE_TOO_MANY_REDIRECTS ,     /* 47 - catch endless re-direct loops */
+  CURLE_TOO_MANY_REDIRECTS,      /* 47 - catch endless re-direct loops */
   CURLE_UNKNOWN_OPTION,          /* 48 - User specified an unknown option */
-  CURLE_TELNET_OPTION_SYNTAX ,   /* 49 - Malformed telnet option */
+  CURLE_TELNET_OPTION_SYNTAX,    /* 49 - Malformed telnet option */
   CURLE_OBSOLETE50,              /* 50 - NOT USED */
-  CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
-                                     wasn't verified fine */
+  CURLE_OBSOLETE51,              /* 51 - NOT USED */
   CURLE_GOT_NOTHING,             /* 52 - when this is a specific error */
   CURLE_SSL_ENGINE_NOTFOUND,     /* 53 - SSL crypto engine not found */
   CURLE_SSL_ENGINE_SETFAILED,    /* 54 - can not set SSL crypto engine as
@@ -466,7 +552,8 @@ typedef enum {
   CURLE_OBSOLETE57,              /* 57 - NOT IN USE */
   CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
   CURLE_SSL_CIPHER,              /* 59 - couldn't use specified cipher */
-  CURLE_SSL_CACERT,              /* 60 - problem with the CA cert (path?) */
+  CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
+                                     wasn't verified fine */
   CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
   CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
   CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
@@ -507,18 +594,41 @@ typedef enum {
                                     7.19.0) */
   CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
   CURLE_RTSP_CSEQ_ERROR,         /* 85 - mismatch of RTSP CSeq numbers */
-  CURLE_RTSP_SESSION_ERROR,      /* 86 - mismatch of RTSP Session Identifiers */
+  CURLE_RTSP_SESSION_ERROR,      /* 86 - mismatch of RTSP Session Ids */
   CURLE_FTP_BAD_FILE_LIST,       /* 87 - unable to parse FTP file list */
   CURLE_CHUNK_FAILED,            /* 88 - chunk callback reported error */
-
+  CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
+                                    session will be queued */
+  CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not
+                                     match */
+  CURLE_SSL_INVALIDCERTSTATUS,   /* 91 - invalid certificate status */
+  CURLE_HTTP2_STREAM,            /* 92 - stream error in HTTP/2 framing layer
+                                    */
+  CURLE_RECURSIVE_API_CALL,      /* 93 - an api function was called from
+                                    inside a callback */
+  CURLE_AUTH_ERROR,              /* 94 - an authentication function returned an
+                                    error */
+  CURLE_HTTP3,                   /* 95 - An HTTP/3 layer problem */
+  CURLE_QUIC_CONNECT_ERROR,      /* 96 - QUIC connection error */
   CURL_LAST /* never use! */
 } CURLcode;
 
 #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
                           the obsolete stuff removed! */
 
+/* Previously obsolete error code re-used in 7.38.0 */
+#define CURLE_OBSOLETE16 CURLE_HTTP2
+
+/* Previously obsolete error codes re-used in 7.24.0 */
+#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
+#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
+
 /*  compatibility with older names */
 #define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
+#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY
+
+/* The following were added in 7.62.0 */
+#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION
 
 /* The following were added in 7.21.5, April 2011 */
 #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
@@ -567,14 +677,26 @@ typedef enum {
    make programs break */
 #define CURLE_ALREADY_COMPLETE 99999
 
+/* Provide defines for really old option names */
+#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */
+#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */
+#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA
+
+/* Since long deprecated options with no code in the lib that does anything
+   with them. */
+#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
+#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
+
 #endif /*!CURL_NO_OLDIES*/
 
 /* This prototype applies to all conversion callbacks */
 typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
 
 typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
-                                          void *ssl_ctx, /* actually an
-                                                            OpenSSL SSL_CTX */
+                                          void *ssl_ctx, /* actually an OpenSSL
+                                                            or WolfSSL SSL_CTX,
+                                                            or an mbedTLS
+                                                          mbedtls_ssl_config */
                                           void *userptr);
 
 typedef enum {
@@ -582,6 +704,7 @@ typedef enum {
                            CONNECT HTTP/1.1 */
   CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
                                HTTP/1.0  */
+  CURLPROXY_HTTPS = 2, /* added in 7.52.0 */
   CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
                            in 7.10 */
   CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
@@ -591,17 +714,39 @@ typedef enum {
                                    in 7.18.0 */
 } curl_proxytype;  /* this enum was added in 7.10 */
 
-#define CURLAUTH_NONE         0       /* nothing */
-#define CURLAUTH_BASIC        (1<<0)  /* Basic (default) */
-#define CURLAUTH_DIGEST       (1<<1)  /* Digest */
-#define CURLAUTH_GSSNEGOTIATE (1<<2)  /* GSS-Negotiate */
-#define CURLAUTH_NTLM         (1<<3)  /* NTLM */
-#define CURLAUTH_DIGEST_IE    (1<<4)  /* Digest with IE flavour */
-#define CURLAUTH_ONLY         (1<<31) /* used together with a single other
-                                         type to force no auth or just that
-                                         single type */
-#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE)  /* all fine types set */
-#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
+/*
+ * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
+ *
+ * CURLAUTH_NONE         - No HTTP authentication
+ * CURLAUTH_BASIC        - HTTP Basic authentication (default)
+ * CURLAUTH_DIGEST       - HTTP Digest authentication
+ * CURLAUTH_NEGOTIATE    - HTTP Negotiate (SPNEGO) authentication
+ * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated)
+ * CURLAUTH_NTLM         - HTTP NTLM authentication
+ * CURLAUTH_DIGEST_IE    - HTTP Digest authentication with IE flavour
+ * CURLAUTH_NTLM_WB      - HTTP NTLM authentication delegated to winbind helper
+ * CURLAUTH_BEARER       - HTTP Bearer token authentication
+ * CURLAUTH_ONLY         - Use together with a single other type to force no
+ *                         authentication or just that single type
+ * CURLAUTH_ANY          - All fine types set
+ * CURLAUTH_ANYSAFE      - All fine types except Basic
+ */
+
+#define CURLAUTH_NONE         ((unsigned long)0)
+#define CURLAUTH_BASIC        (((unsigned long)1)<<0)
+#define CURLAUTH_DIGEST       (((unsigned long)1)<<1)
+#define CURLAUTH_NEGOTIATE    (((unsigned long)1)<<2)
+/* Deprecated since the advent of CURLAUTH_NEGOTIATE */
+#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
+/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */
+#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE
+#define CURLAUTH_NTLM         (((unsigned long)1)<<3)
+#define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
+#define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
+#define CURLAUTH_BEARER       (((unsigned long)1)<<6)
+#define CURLAUTH_ONLY         (((unsigned long)1)<<31)
+#define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
+#define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
 
 #define CURLSSH_AUTH_ANY       ~0     /* all types supported by the server */
 #define CURLSSH_AUTH_NONE      0      /* none allowed, silly but complete */
@@ -609,20 +754,30 @@ typedef enum {
 #define CURLSSH_AUTH_PASSWORD  (1<<1) /* password */
 #define CURLSSH_AUTH_HOST      (1<<2) /* host key files */
 #define CURLSSH_AUTH_KEYBOARD  (1<<3) /* keyboard interactive */
+#define CURLSSH_AUTH_AGENT     (1<<4) /* agent (ssh-agent, pageant...) */
+#define CURLSSH_AUTH_GSSAPI    (1<<5) /* gssapi (kerberos, ...) */
 #define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
 
+#define CURLGSSAPI_DELEGATION_NONE        0      /* no delegation (default) */
+#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */
+#define CURLGSSAPI_DELEGATION_FLAG        (1<<1) /* delegate always */
+
 #define CURL_ERROR_SIZE 256
 
+enum curl_khtype {
+  CURLKHTYPE_UNKNOWN,
+  CURLKHTYPE_RSA1,
+  CURLKHTYPE_RSA,
+  CURLKHTYPE_DSS,
+  CURLKHTYPE_ECDSA,
+  CURLKHTYPE_ED25519
+};
+
 struct curl_khkey {
   const char *key; /* points to a zero-terminated string encoded with base64
                       if len is zero, otherwise to the "raw" data */
   size_t len;
-  enum type {
-    CURLKHTYPE_UNKNOWN,
-    CURLKHTYPE_RSA1,
-    CURLKHTYPE_RSA,
-    CURLKHTYPE_DSS
-  } keytype;
+  enum curl_khtype keytype;
 };
 
 /* this is the set of return values expected from the curl_sshkeycallback
@@ -661,6 +816,31 @@ typedef enum {
   CURLUSESSL_LAST     /* not an option, never use */
 } curl_usessl;
 
+/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
+
+/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
+   name of improving interoperability with older servers. Some SSL libraries
+   have introduced work-arounds for this flaw but those work-arounds sometimes
+   make the SSL communication fail. To regain functionality with those broken
+   servers, a user can this way allow the vulnerability back. */
+#define CURLSSLOPT_ALLOW_BEAST (1<<0)
+
+/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
+   SSL backends where such behavior is present. */
+#define CURLSSLOPT_NO_REVOKE (1<<1)
+
+/* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain
+   if possible. The OpenSSL backend has this ability. */
+#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2)
+
+/* The default connection attempt delay in milliseconds for happy eyeballs.
+   CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
+   this value, keep them in sync. */
+#define CURL_HET_DEFAULT 200L
+
+/* The default connection upkeep interval in milliseconds. */
+#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L
+
 #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
                           the obsolete stuff removed! */
 
@@ -711,6 +891,18 @@ typedef enum {
   CURLFTPMETHOD_LAST       /* not an option, never use */
 } curl_ftpmethod;
 
+/* bitmask defines for CURLOPT_HEADEROPT */
+#define CURLHEADER_UNIFIED  0
+#define CURLHEADER_SEPARATE (1<<0)
+
+/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */
+#define CURLALTSVC_IMMEDIATELY  (1<<0)
+
+#define CURLALTSVC_READONLYFILE (1<<2)
+#define CURLALTSVC_H1           (1<<3)
+#define CURLALTSVC_H2           (1<<4)
+#define CURLALTSVC_H3           (1<<5)
+
 /* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
 #define CURLPROTO_HTTP   (1<<0)
 #define CURLPROTO_HTTPS  (1<<1)
@@ -738,6 +930,8 @@ typedef enum {
 #define CURLPROTO_RTMPS  (1<<23)
 #define CURLPROTO_RTMPTS (1<<24)
 #define CURLPROTO_GOPHER (1<<25)
+#define CURLPROTO_SMB    (1<<26)
+#define CURLPROTO_SMBS   (1<<27)
 #define CURLPROTO_ALL    (~0) /* enable everything */
 
 /* long may be 32 or 64 bits, but we should never depend on anything else
@@ -747,71 +941,61 @@ typedef enum {
 #define CURLOPTTYPE_FUNCTIONPOINT 20000
 #define CURLOPTTYPE_OFF_T         30000
 
-/* name is uppercase CURLOPT_<name>,
-   type is one of the defined CURLOPTTYPE_<type>
-   number is unique identifier */
-#ifdef CINIT
-#undef CINIT
-#endif
+/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
+   string options from the header file */
 
-#ifdef CURL_ISOCPP
-#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number
-#else
-/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
-#define LONG          CURLOPTTYPE_LONG
-#define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
-#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
-#define OFF_T         CURLOPTTYPE_OFF_T
-#define CINIT(name,type,number) CURLOPT_/**/name = type + number
-#endif
+
+#define CURLOPT(na,t,nu) na = t + nu
+
+/* handy aliases that make no run-time difference */
+#define CURLOPTTYPE_STRINGPOINT  CURLOPTTYPE_OBJECTPOINT
+#define CURLOPTTYPE_SLISTPOINT  CURLOPTTYPE_OBJECTPOINT
 
 /*
- * This macro-mania below setups the CURLOPT_[what] enum, to be used with
- * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
- * word.
+ * All CURLOPT_* values.
  */
 
 typedef enum {
   /* This is the FILE * or void * the regular output should be written to. */
-  CINIT(FILE, OBJECTPOINT, 1),
+  CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_OBJECTPOINT, 1),
 
   /* The full URL to get/put */
-  CINIT(URL,  OBJECTPOINT, 2),
+  CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2),
 
   /* Port number to connect to, if other than default. */
-  CINIT(PORT, LONG, 3),
+  CURLOPT(CURLOPT_PORT, CURLOPTTYPE_LONG, 3),
 
   /* Name of proxy to use. */
-  CINIT(PROXY, OBJECTPOINT, 4),
+  CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4),
 
-  /* "name:password" to use when fetching. */
-  CINIT(USERPWD, OBJECTPOINT, 5),
+  /* "user:password;options" to use when fetching. */
+  CURLOPT(CURLOPT_USERPWD, CURLOPTTYPE_STRINGPOINT, 5),
 
-  /* "name:password" to use with proxy. */
-  CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
+  /* "user:password" to use with proxy. */
+  CURLOPT(CURLOPT_PROXYUSERPWD, CURLOPTTYPE_STRINGPOINT, 6),
 
   /* Range to get, specified as an ASCII string. */
-  CINIT(RANGE, OBJECTPOINT, 7),
+  CURLOPT(CURLOPT_RANGE, CURLOPTTYPE_STRINGPOINT, 7),
 
   /* not used */
 
   /* Specified file stream to upload from (use as input): */
-  CINIT(INFILE, OBJECTPOINT, 9),
+  CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_OBJECTPOINT, 9),
 
   /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
-   * bytes big. If this is not used, error messages go to stderr instead: */
-  CINIT(ERRORBUFFER, OBJECTPOINT, 10),
+   * bytes big. */
+  CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10),
 
   /* Function that will be called to store the output (instead of fwrite). The
    * parameters will use fwrite() syntax, make sure to follow them. */
-  CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
+  CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11),
 
   /* Function that will be called to read the input (instead of fread). The
    * parameters will use fread() syntax, make sure to follow them. */
-  CINIT(READFUNCTION, FUNCTIONPOINT, 12),
+  CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12),
 
   /* Time-out the read operation after this amount of seconds */
-  CINIT(TIMEOUT, LONG, 13),
+  CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13),
 
   /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
    * how large the file being sent really is. That allows better error
@@ -822,20 +1006,20 @@ typedef enum {
    * which takes an off_t type, allowing platforms with larger off_t
    * sizes to handle larger files.  See below for INFILESIZE_LARGE.
    */
-  CINIT(INFILESIZE, LONG, 14),
+  CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14),
 
   /* POST static input fields. */
-  CINIT(POSTFIELDS, OBJECTPOINT, 15),
+  CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15),
 
   /* Set the referrer page (needed by some CGIs) */
-  CINIT(REFERER, OBJECTPOINT, 16),
+  CURLOPT(CURLOPT_REFERER, CURLOPTTYPE_STRINGPOINT, 16),
 
   /* Set the FTP PORT string (interface name, named or numerical IP address)
      Use i.e '-' to use default address. */
-  CINIT(FTPPORT, OBJECTPOINT, 17),
+  CURLOPT(CURLOPT_FTPPORT, CURLOPTTYPE_STRINGPOINT, 17),
 
   /* Set the User-Agent string (examined by some CGIs) */
-  CINIT(USERAGENT, OBJECTPOINT, 18),
+  CURLOPT(CURLOPT_USERAGENT, CURLOPTTYPE_STRINGPOINT, 18),
 
   /* If the download receives less than "low speed limit" bytes/second
    * during "low speed time" seconds, the operations is aborted.
@@ -844,10 +1028,10 @@ typedef enum {
    */
 
   /* Set the "low speed limit" */
-  CINIT(LOW_SPEED_LIMIT, LONG, 19),
+  CURLOPT(CURLOPT_LOW_SPEED_LIMIT, CURLOPTTYPE_LONG, 19),
 
   /* Set the "low speed time" */
-  CINIT(LOW_SPEED_TIME, LONG, 20),
+  CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20),
 
   /* Set the continuation offset.
    *
@@ -855,47 +1039,48 @@ typedef enum {
    * off_t types, allowing for large file offsets on platforms which
    * use larger-than-32-bit off_t's.  Look below for RESUME_FROM_LARGE.
    */
-  CINIT(RESUME_FROM, LONG, 21),
+  CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21),
 
   /* Set cookie in request: */
-  CINIT(COOKIE, OBJECTPOINT, 22),
+  CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22),
 
-  /* This points to a linked list of headers, struct curl_slist kind */
-  CINIT(HTTPHEADER, OBJECTPOINT, 23),
+  /* This points to a linked list of headers, struct curl_slist kind. This
+     list is also used for RTSP (in spite of its name) */
+  CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23),
 
   /* This points to a linked list of post entries, struct curl_httppost */
-  CINIT(HTTPPOST, OBJECTPOINT, 24),
+  CURLOPT(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24),
 
   /* name of the file keeping your private SSL-certificate */
-  CINIT(SSLCERT, OBJECTPOINT, 25),
+  CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25),
 
   /* password for the SSL or SSH private key */
-  CINIT(KEYPASSWD, OBJECTPOINT, 26),
+  CURLOPT(CURLOPT_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 26),
 
   /* send TYPE parameter? */
-  CINIT(CRLF, LONG, 27),
+  CURLOPT(CURLOPT_CRLF, CURLOPTTYPE_LONG, 27),
 
   /* send linked-list of QUOTE commands */
-  CINIT(QUOTE, OBJECTPOINT, 28),
+  CURLOPT(CURLOPT_QUOTE, CURLOPTTYPE_SLISTPOINT, 28),
 
   /* send FILE * or void * to store headers to, if you use a callback it
      is simply passed to the callback unmodified */
-  CINIT(WRITEHEADER, OBJECTPOINT, 29),
+  CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_OBJECTPOINT, 29),
 
   /* point to a file to read the initial cookies from, also enables
      "cookie awareness" */
-  CINIT(COOKIEFILE, OBJECTPOINT, 31),
+  CURLOPT(CURLOPT_COOKIEFILE, CURLOPTTYPE_STRINGPOINT, 31),
 
   /* What version to specifically try to use.
      See CURL_SSLVERSION defines below. */
-  CINIT(SSLVERSION, LONG, 32),
+  CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_LONG, 32),
 
   /* What kind of HTTP time condition to use, see defines */
-  CINIT(TIMECONDITION, LONG, 33),
+  CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_LONG, 33),
 
   /* Time to use with the above condition. Specified in number of seconds
      since 1 Jan 1970 */
-  CINIT(TIMEVALUE, LONG, 34),
+  CURLOPT(CURLOPT_TIMEVALUE, CURLOPTTYPE_LONG, 34),
 
   /* 35 = OBSOLETE */
 
@@ -903,304 +1088,326 @@ typedef enum {
      HTTP: DELETE, TRACE and others
      FTP: to use a different list command
      */
-  CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
+  CURLOPT(CURLOPT_CUSTOMREQUEST, CURLOPTTYPE_STRINGPOINT, 36),
 
-  /* HTTP request, for odd commands like DELETE, TRACE and others */
-  CINIT(STDERR, OBJECTPOINT, 37),
+  /* FILE handle to use instead of stderr */
+  CURLOPT(CURLOPT_STDERR, CURLOPTTYPE_OBJECTPOINT, 37),
 
   /* 38 is not used */
 
   /* send linked-list of post-transfer QUOTE commands */
-  CINIT(POSTQUOTE, OBJECTPOINT, 39),
+  CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39),
+
+   /* OBSOLETE, do not use! */
+  CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40),
+
+  /* talk a lot */
+  CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41),
+
+  /* throw the header out too */
+  CURLOPT(CURLOPT_HEADER, CURLOPTTYPE_LONG, 42),
+
+  /* shut off the progress meter */
+  CURLOPT(CURLOPT_NOPROGRESS, CURLOPTTYPE_LONG, 43),
+
+  /* use HEAD to get http document */
+  CURLOPT(CURLOPT_NOBODY, CURLOPTTYPE_LONG, 44),
+
+  /* no output on http error codes >= 400 */
+  CURLOPT(CURLOPT_FAILONERROR, CURLOPTTYPE_LONG, 45),
+
+  /* this is an upload */
+  CURLOPT(CURLOPT_UPLOAD, CURLOPTTYPE_LONG, 46),
 
-  /* Pass a pointer to string of the output using full variable-replacement
-     as described elsewhere. */
-  CINIT(WRITEINFO, OBJECTPOINT, 40),
+  /* HTTP POST method */
+  CURLOPT(CURLOPT_POST, CURLOPTTYPE_LONG, 47),
 
-  CINIT(VERBOSE, LONG, 41),      /* talk a lot */
-  CINIT(HEADER, LONG, 42),       /* throw the header out too */
-  CINIT(NOPROGRESS, LONG, 43),   /* shut off the progress meter */
-  CINIT(NOBODY, LONG, 44),       /* use HEAD to get http document */
-  CINIT(FAILONERROR, LONG, 45),  /* no output on http error codes >= 300 */
-  CINIT(UPLOAD, LONG, 46),       /* this is an upload */
-  CINIT(POST, LONG, 47),         /* HTTP POST method */
-  CINIT(DIRLISTONLY, LONG, 48),  /* return bare names when listing directories */
+  /* bare names when listing directories */
+  CURLOPT(CURLOPT_DIRLISTONLY, CURLOPTTYPE_LONG, 48),
 
-  CINIT(APPEND, LONG, 50),       /* Append instead of overwrite on upload! */
+  /* Append instead of overwrite on upload! */
+  CURLOPT(CURLOPT_APPEND, CURLOPTTYPE_LONG, 50),
 
   /* Specify whether to read the user+password from the .netrc or the URL.
    * This must be one of the CURL_NETRC_* enums below. */
-  CINIT(NETRC, LONG, 51),
+  CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_LONG, 51),
 
-  CINIT(FOLLOWLOCATION, LONG, 52),  /* use Location: Luke! */
+  /* use Location: Luke! */
+  CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52),
 
-  CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
-  CINIT(PUT, LONG, 54),          /* HTTP PUT */
+   /* transfer data in text/ASCII format */
+  CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53),
+
+  /* HTTP PUT */
+  CURLOPT(CURLOPT_PUT, CURLOPTTYPE_LONG, 54),
 
   /* 55 = OBSOLETE */
 
-  /* Function that will be called instead of the internal progress display
+  /* DEPRECATED
+   * Function that will be called instead of the internal progress display
    * function. This function should be defined as the curl_progress_callback
    * prototype defines. */
-  CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
+  CURLOPT(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56),
 
-  /* Data passed to the progress callback */
-  CINIT(PROGRESSDATA, OBJECTPOINT, 57),
+  /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
+     callbacks */
+  CURLOPT(CURLOPT_PROGRESSDATA, CURLOPTTYPE_OBJECTPOINT, 57),
+#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA
 
   /* We want the referrer field set automatically when following locations */
-  CINIT(AUTOREFERER, LONG, 58),
+  CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58),
 
   /* Port of the proxy, can be set in the proxy string as well with:
      "[host]:[port]" */
-  CINIT(PROXYPORT, LONG, 59),
+  CURLOPT(CURLOPT_PROXYPORT, CURLOPTTYPE_LONG, 59),
 
   /* size of the POST input data, if strlen() is not good to use */
-  CINIT(POSTFIELDSIZE, LONG, 60),
+  CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60),
 
   /* tunnel non-http operations through a HTTP proxy */
-  CINIT(HTTPPROXYTUNNEL, LONG, 61),
+  CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61),
 
   /* Set the interface string to use as outgoing network interface */
-  CINIT(INTERFACE, OBJECTPOINT, 62),
+  CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62),
 
   /* Set the krb4/5 security level, this also enables krb4/5 awareness.  This
    * is a string, 'clear', 'safe', 'confidential' or 'private'.  If the string
    * is set but doesn't match one of these, 'private' will be used.  */
-  CINIT(KRBLEVEL, OBJECTPOINT, 63),
+  CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),
 
   /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
-  CINIT(SSL_VERIFYPEER, LONG, 64),
+  CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64),
 
   /* The CApath or CAfile used to validate the peer certificate
      this option is used only if SSL_VERIFYPEER is true */
-  CINIT(CAINFO, OBJECTPOINT, 65),
+  CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65),
 
   /* 66 = OBSOLETE */
   /* 67 = OBSOLETE */
 
   /* Maximum number of http redirects to follow */
-  CINIT(MAXREDIRS, LONG, 68),
+  CURLOPT(CURLOPT_MAXREDIRS, CURLOPTTYPE_LONG, 68),
 
   /* Pass a long set to 1 to get the date of the requested document (if
      possible)! Pass a zero to shut it off. */
-  CINIT(FILETIME, LONG, 69),
+  CURLOPT(CURLOPT_FILETIME, CURLOPTTYPE_LONG, 69),
 
   /* This points to a linked list of telnet options */
-  CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
+  CURLOPT(CURLOPT_TELNETOPTIONS, CURLOPTTYPE_SLISTPOINT, 70),
 
   /* Max amount of cached alive connections */
-  CINIT(MAXCONNECTS, LONG, 71),
+  CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71),
 
-  /* What policy to use when closing connections when the cache is filled
-     up */
-  CINIT(CLOSEPOLICY, LONG, 72),
+  /* OBSOLETE, do not use! */
+  CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72),
 
   /* 73 = OBSOLETE */
 
   /* Set to explicitly use a new connection for the upcoming transfer.
      Do not use this unless you're absolutely sure of this, as it makes the
      operation slower and is less friendly for the network. */
-  CINIT(FRESH_CONNECT, LONG, 74),
+  CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74),
 
   /* Set to explicitly forbid the upcoming transfer's connection to be re-used
      when done. Do not use this unless you're absolutely sure of this, as it
      makes the operation slower and is less friendly for the network. */
-  CINIT(FORBID_REUSE, LONG, 75),
+  CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75),
 
   /* Set to a file name that contains random data for libcurl to use to
      seed the random engine when doing SSL connects. */
-  CINIT(RANDOM_FILE, OBJECTPOINT, 76),
+  CURLOPT(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76),
 
   /* Set to the Entropy Gathering Daemon socket pathname */
-  CINIT(EGDSOCKET, OBJECTPOINT, 77),
+  CURLOPT(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77),
 
-  /* Time-out connect operations after this amount of seconds, if connects
-     are OK within this time, then fine... This only aborts the connect
-     phase. [Only works on unix-style/SIGALRM operating systems] */
-  CINIT(CONNECTTIMEOUT, LONG, 78),
+  /* Time-out connect operations after this amount of seconds, if connects are
+     OK within this time, then fine... This only aborts the connect phase. */
+  CURLOPT(CURLOPT_CONNECTTIMEOUT, CURLOPTTYPE_LONG, 78),
 
   /* Function that will be called to store headers (instead of fwrite). The
    * parameters will use fwrite() syntax, make sure to follow them. */
-  CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
+  CURLOPT(CURLOPT_HEADERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 79),
 
   /* Set this to force the HTTP request to get back to GET. Only really usable
      if POST, PUT or a custom request have been used first.
    */
-  CINIT(HTTPGET, LONG, 80),
+  CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80),
 
   /* Set if we should verify the Common name from the peer certificate in ssl
    * handshake, set 1 to check existence, 2 to ensure that it matches the
    * provided hostname. */
-  CINIT(SSL_VERIFYHOST, LONG, 81),
+  CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),
 
   /* Specify which file name to write all known cookies in after completed
      operation. Set file name to "-" (dash) to make it go to stdout. */
-  CINIT(COOKIEJAR, OBJECTPOINT, 82),
+  CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),
 
   /* Specify which SSL ciphers to use */
-  CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
+  CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83),
 
   /* Specify which HTTP version to use! This must be set to one of the
      CURL_HTTP_VERSION* enums set below. */
-  CINIT(HTTP_VERSION, LONG, 84),
+  CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_LONG, 84),
 
   /* Specifically switch on or off the FTP engine's use of the EPSV command. By
      default, that one will always be attempted before the more traditional
      PASV command. */
-  CINIT(FTP_USE_EPSV, LONG, 85),
+  CURLOPT(CURLOPT_FTP_USE_EPSV, CURLOPTTYPE_LONG, 85),
 
   /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
-  CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
+  CURLOPT(CURLOPT_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 86),
 
   /* name of the file keeping your private SSL-key */
-  CINIT(SSLKEY, OBJECTPOINT, 87),
+  CURLOPT(CURLOPT_SSLKEY, CURLOPTTYPE_STRINGPOINT, 87),
 
   /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
-  CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
+  CURLOPT(CURLOPT_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 88),
 
   /* crypto engine for the SSL-sub system */
-  CINIT(SSLENGINE, OBJECTPOINT, 89),
+  CURLOPT(CURLOPT_SSLENGINE, CURLOPTTYPE_STRINGPOINT, 89),
 
   /* set the crypto engine for the SSL-sub system as default
      the param has no meaning...
    */
-  CINIT(SSLENGINE_DEFAULT, LONG, 90),
+  CURLOPT(CURLOPT_SSLENGINE_DEFAULT, CURLOPTTYPE_LONG, 90),
 
   /* Non-zero value means to use the global dns cache */
-  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */
+  /* DEPRECATED, do not use! */
+  CURLOPT(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91),
 
   /* DNS cache timeout */
-  CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
+  CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92),
 
   /* send linked-list of pre-transfer QUOTE commands */
-  CINIT(PREQUOTE, OBJECTPOINT, 93),
+  CURLOPT(CURLOPT_PREQUOTE, CURLOPTTYPE_SLISTPOINT, 93),
 
   /* set the debug function */
-  CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
+  CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94),
 
   /* set the data for the debug function */
-  CINIT(DEBUGDATA, OBJECTPOINT, 95),
+  CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_OBJECTPOINT, 95),
 
   /* mark this as start of a cookie session */
-  CINIT(COOKIESESSION, LONG, 96),
+  CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96),
 
   /* The CApath directory used to validate the peer certificate
      this option is used only if SSL_VERIFYPEER is true */
-  CINIT(CAPATH, OBJECTPOINT, 97),
+  CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97),
 
   /* Instruct libcurl to use a smaller receive buffer */
-  CINIT(BUFFERSIZE, LONG, 98),
+  CURLOPT(CURLOPT_BUFFERSIZE, CURLOPTTYPE_LONG, 98),
 
   /* Instruct libcurl to not use any signal/alarm handlers, even when using
      timeouts. This option is useful for multi-threaded applications.
      See libcurl-the-guide for more background information. */
-  CINIT(NOSIGNAL, LONG, 99),
+  CURLOPT(CURLOPT_NOSIGNAL, CURLOPTTYPE_LONG, 99),
 
   /* Provide a CURLShare for mutexing non-ts data */
-  CINIT(SHARE, OBJECTPOINT, 100),
+  CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100),
 
   /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
-     CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */
-  CINIT(PROXYTYPE, LONG, 101),
+     CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and
+     CURLPROXY_SOCKS5. */
+  CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_LONG, 101),
 
   /* Set the Accept-Encoding string. Use this to tell a server you would like
      the response to be compressed. Before 7.21.6, this was known as
      CURLOPT_ENCODING */
-  CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102),
+  CURLOPT(CURLOPT_ACCEPT_ENCODING, CURLOPTTYPE_STRINGPOINT, 102),
 
   /* Set pointer to private data */
-  CINIT(PRIVATE, OBJECTPOINT, 103),
+  CURLOPT(CURLOPT_PRIVATE, CURLOPTTYPE_OBJECTPOINT, 103),
 
   /* Set aliases for HTTP 200 in the HTTP Response header */
-  CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
+  CURLOPT(CURLOPT_HTTP200ALIASES, CURLOPTTYPE_SLISTPOINT, 104),
 
   /* Continue to send authentication (user+password) when following locations,
      even when hostname changed. This can potentially send off the name
      and password to whatever host the server decides. */
-  CINIT(UNRESTRICTED_AUTH, LONG, 105),
+  CURLOPT(CURLOPT_UNRESTRICTED_AUTH, CURLOPTTYPE_LONG, 105),
 
-  /* Specifically switch on or off the FTP engine's use of the EPRT command ( it
-     also disables the LPRT attempt). By default, those ones will always be
+  /* Specifically switch on or off the FTP engine's use of the EPRT command (
+     it also disables the LPRT attempt). By default, those ones will always be
      attempted before the good old traditional PORT command. */
-  CINIT(FTP_USE_EPRT, LONG, 106),
+  CURLOPT(CURLOPT_FTP_USE_EPRT, CURLOPTTYPE_LONG, 106),
 
   /* Set this to a bitmask value to enable the particular authentications
      methods you like. Use this in combination with CURLOPT_USERPWD.
      Note that setting multiple bits may cause extra network round-trips. */
-  CINIT(HTTPAUTH, LONG, 107),
+  CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_LONG, 107),
 
-  /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
-     in second argument. The function must be matching the
-     curl_ssl_ctx_callback proto. */
-  CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
+  /* Set the ssl context callback function, currently only for OpenSSL or
+     WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
+     The function must match the curl_ssl_ctx_callback prototype. */
+  CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),
 
   /* Set the userdata for the ssl context callback function's third
      argument */
-  CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
+  CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_OBJECTPOINT, 109),
 
   /* FTP Option that causes missing dirs to be created on the remote server.
      In 7.19.4 we introduced the convenience enums for this option using the
      CURLFTP_CREATE_DIR prefix.
   */
-  CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
+  CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110),
 
   /* Set this to a bitmask value to enable the particular authentications
      methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
      Note that setting multiple bits may cause extra network round-trips. */
-  CINIT(PROXYAUTH, LONG, 111),
+  CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_LONG, 111),
 
   /* FTP option that changes the timeout, in seconds, associated with
      getting a response.  This is different from transfer timeout time and
      essentially places a demand on the FTP server to acknowledge commands
      in a timely manner. */
-  CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
+  CURLOPT(CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),
 #define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
 
   /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
      tell libcurl to resolve names to those IP versions only. This only has
      affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
-  CINIT(IPRESOLVE, LONG, 113),
+  CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_LONG, 113),
 
   /* Set this option to limit the size of a file that will be downloaded from
      an HTTP or FTP server.
 
      Note there is also _LARGE version which adds large file support for
      platforms which have larger off_t sizes.  See MAXFILESIZE_LARGE below. */
-  CINIT(MAXFILESIZE, LONG, 114),
+  CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114),
 
   /* See the comment for INFILESIZE above, but in short, specifies
    * the size of the file being uploaded.  -1 means unknown.
    */
-  CINIT(INFILESIZE_LARGE, OFF_T, 115),
+  CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115),
 
-  /* Sets the continuation offset.  There is also a LONG version of this;
-   * look above for RESUME_FROM.
+  /* Sets the continuation offset.  There is also a CURLOPTTYPE_LONG version
+   * of this; look above for RESUME_FROM.
    */
-  CINIT(RESUME_FROM_LARGE, OFF_T, 116),
+  CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116),
 
   /* Sets the maximum size of data that will be downloaded from
    * an HTTP or FTP server.  See MAXFILESIZE above for the LONG version.
    */
-  CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
+  CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117),
 
   /* Set this option to the file name of your .netrc file you want libcurl
      to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
      a poor attempt to find the user's home directory and check for a .netrc
      file in there. */
-  CINIT(NETRC_FILE, OBJECTPOINT, 118),
+  CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118),
 
   /* Enable SSL/TLS for FTP, pick one of:
-     CURLFTPSSL_TRY     - try using SSL, proceed anyway otherwise
-     CURLFTPSSL_CONTROL - SSL for the control connection or fail
-     CURLFTPSSL_ALL     - SSL for all communication or fail
+     CURLUSESSL_TRY     - try using SSL, proceed anyway otherwise
+     CURLUSESSL_CONTROL - SSL for the control connection or fail
+     CURLUSESSL_ALL     - SSL for all communication or fail
   */
-  CINIT(USE_SSL, LONG, 119),
+  CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_LONG, 119),
 
   /* The _LARGE version of the standard POSTFIELDSIZE option */
-  CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
+  CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120),
 
   /* Enable/disable the TCP Nagle algorithm */
-  CINIT(TCP_NODELAY, LONG, 121),
+  CURLOPT(CURLOPT_TCP_NODELAY, CURLOPTTYPE_LONG, 121),
 
   /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
   /* 123 OBSOLETE. Gone in 7.16.0 */
@@ -1220,144 +1427,143 @@ typedef enum {
      CURLFTPAUTH_SSL     - try "AUTH SSL" first, then TLS
      CURLFTPAUTH_TLS     - try "AUTH TLS" first, then SSL
   */
-  CINIT(FTPSSLAUTH, LONG, 129),
+  CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_LONG, 129),
 
-  CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
-  CINIT(IOCTLDATA, OBJECTPOINT, 131),
+  CURLOPT(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130),
+  CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_OBJECTPOINT, 131),
 
   /* 132 OBSOLETE. Gone in 7.16.0 */
   /* 133 OBSOLETE. Gone in 7.16.0 */
 
   /* zero terminated string for pass on to the FTP server when asked for
      "account" info */
-  CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
+  CURLOPT(CURLOPT_FTP_ACCOUNT, CURLOPTTYPE_STRINGPOINT, 134),
 
-  /* feed cookies into cookie engine */
-  CINIT(COOKIELIST, OBJECTPOINT, 135),
+  /* feed cookie into cookie engine */
+  CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135),
 
   /* ignore Content-Length */
-  CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
+  CURLOPT(CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPTTYPE_LONG, 136),
 
   /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
      response. Typically used for FTP-SSL purposes but is not restricted to
      that. libcurl will then instead use the same IP address it used for the
      control connection. */
-  CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+  CURLOPT(CURLOPT_FTP_SKIP_PASV_IP, CURLOPTTYPE_LONG, 137),
 
   /* Select "file method" to use when doing FTP, see the curl_ftpmethod
      above. */
-  CINIT(FTP_FILEMETHOD, LONG, 138),
+  CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_LONG, 138),
 
   /* Local port number to bind the socket to */
-  CINIT(LOCALPORT, LONG, 139),
+  CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139),
 
   /* Number of ports to try, including the first one set with LOCALPORT.
      Thus, setting it to 1 will make no additional attempts but the first.
   */
-  CINIT(LOCALPORTRANGE, LONG, 140),
+  CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140),
 
   /* no transfer, set up connection and let application use the socket by
      extracting it with CURLINFO_LASTSOCKET */
-  CINIT(CONNECT_ONLY, LONG, 141),
+  CURLOPT(CURLOPT_CONNECT_ONLY, CURLOPTTYPE_LONG, 141),
 
   /* Function that will be called to convert from the
      network encoding (instead of using the iconv calls in libcurl) */
-  CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
+  CURLOPT(CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 142),
 
   /* Function that will be called to convert to the
      network encoding (instead of using the iconv calls in libcurl) */
-  CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
+  CURLOPT(CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 143),
 
   /* Function that will be called to convert from UTF8
      (instead of using the iconv calls in libcurl)
      Note that this is used only for SSL certificate processing */
-  CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
+  CURLOPT(CURLOPT_CONV_FROM_UTF8_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 144),
 
   /* if the connection proceeds too quickly then need to slow it down */
   /* limit-rate: maximum number of bytes per second to send or receive */
-  CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
-  CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
+  CURLOPT(CURLOPT_MAX_SEND_SPEED_LARGE, CURLOPTTYPE_OFF_T, 145),
+  CURLOPT(CURLOPT_MAX_RECV_SPEED_LARGE, CURLOPTTYPE_OFF_T, 146),
 
   /* Pointer to command string to send if USER/PASS fails. */
-  CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
+  CURLOPT(CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPTTYPE_STRINGPOINT, 147),
 
   /* callback function for setting socket options */
-  CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
-  CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
+  CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148),
+  CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_OBJECTPOINT, 149),
 
   /* set to 0 to disable session ID re-use for this transfer, default is
      enabled (== 1) */
-  CINIT(SSL_SESSIONID_CACHE, LONG, 150),
+  CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150),
 
   /* allowed SSH authentication methods */
-  CINIT(SSH_AUTH_TYPES, LONG, 151),
+  CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_LONG, 151),
 
   /* Used by scp/sftp to do public/private key authentication */
-  CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
-  CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
+  CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152),
+  CURLOPT(CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPTTYPE_STRINGPOINT, 153),
 
   /* Send CCC (Clear Command Channel) after authentication */
-  CINIT(FTP_SSL_CCC, LONG, 154),
+  CURLOPT(CURLOPT_FTP_SSL_CCC, CURLOPTTYPE_LONG, 154),
 
   /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
-  CINIT(TIMEOUT_MS, LONG, 155),
-  CINIT(CONNECTTIMEOUT_MS, LONG, 156),
+  CURLOPT(CURLOPT_TIMEOUT_MS, CURLOPTTYPE_LONG, 155),
+  CURLOPT(CURLOPT_CONNECTTIMEOUT_MS, CURLOPTTYPE_LONG, 156),
 
   /* set to zero to disable the libcurl's decoding and thus pass the raw body
      data to the application even when it is encoded/compressed */
-  CINIT(HTTP_TRANSFER_DECODING, LONG, 157),
-  CINIT(HTTP_CONTENT_DECODING, LONG, 158),
+  CURLOPT(CURLOPT_HTTP_TRANSFER_DECODING, CURLOPTTYPE_LONG, 157),
+  CURLOPT(CURLOPT_HTTP_CONTENT_DECODING, CURLOPTTYPE_LONG, 158),
 
   /* Permission used when creating new files and directories on the remote
      server for protocols that support it, SFTP/SCP/FILE */
-  CINIT(NEW_FILE_PERMS, LONG, 159),
-  CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
+  CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159),
+  CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160),
 
   /* Set the behaviour of POST when redirecting. Values must be set to one
      of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
-  CINIT(POSTREDIR, LONG, 161),
+  CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_LONG, 161),
 
   /* used by scp/sftp to verify the host's public key */
-  CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
+  CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162),
 
   /* Callback function for opening socket (instead of socket(2)). Optionally,
      callback is able change the address or refuse to connect returning
      CURL_SOCKET_BAD.  The callback should have type
      curl_opensocket_callback */
-  CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
-  CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
+  CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
+  CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 164),
 
   /* POST volatile input fields. */
-  CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
+  CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165),
 
   /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
-  CINIT(PROXY_TRANSFER_MODE, LONG, 166),
+  CURLOPT(CURLOPT_PROXY_TRANSFER_MODE, CURLOPTTYPE_LONG, 166),
 
   /* Callback function for seeking in the input stream */
-  CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
-  CINIT(SEEKDATA, OBJECTPOINT, 168),
+  CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167),
+  CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_OBJECTPOINT, 168),
 
   /* CRL file */
-  CINIT(CRLFILE, OBJECTPOINT, 169),
+  CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169),
 
   /* Issuer certificate */
-  CINIT(ISSUERCERT, OBJECTPOINT, 170),
+  CURLOPT(CURLOPT_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 170),
 
   /* (IPv6) Address scope */
-  CINIT(ADDRESS_SCOPE, LONG, 171),
+  CURLOPT(CURLOPT_ADDRESS_SCOPE, CURLOPTTYPE_LONG, 171),
 
   /* Collect certificate chain info and allow it to get retrievable with
-     CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only
-     working with OpenSSL-powered builds. */
-  CINIT(CERTINFO, LONG, 172),
+     CURLINFO_CERTINFO after the transfer is complete. */
+  CURLOPT(CURLOPT_CERTINFO, CURLOPTTYPE_LONG, 172),
 
   /* "name" and "pwd" to use when fetching. */
-  CINIT(USERNAME, OBJECTPOINT, 173),
-  CINIT(PASSWORD, OBJECTPOINT, 174),
+  CURLOPT(CURLOPT_USERNAME, CURLOPTTYPE_STRINGPOINT, 173),
+  CURLOPT(CURLOPT_PASSWORD, CURLOPTTYPE_STRINGPOINT, 174),
 
     /* "name" and "pwd" to use with Proxy when fetching. */
-  CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
-  CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
+  CURLOPT(CURLOPT_PROXYUSERNAME, CURLOPTTYPE_STRINGPOINT, 175),
+  CURLOPT(CURLOPT_PROXYPASSWORD, CURLOPTTYPE_STRINGPOINT, 176),
 
   /* Comma separated list of hostnames defining no-proxy zones. These should
      match both hostnames directly, and hostnames within a domain. For
@@ -1366,103 +1572,103 @@ typedef enum {
      implementations of this, .local.com will be considered to be the same as
      local.com. A single * is the only valid wildcard, and effectively
      disables the use of proxy. */
-  CINIT(NOPROXY, OBJECTPOINT, 177),
+  CURLOPT(CURLOPT_NOPROXY, CURLOPTTYPE_STRINGPOINT, 177),
 
   /* block size for TFTP transfers */
-  CINIT(TFTP_BLKSIZE, LONG, 178),
+  CURLOPT(CURLOPT_TFTP_BLKSIZE, CURLOPTTYPE_LONG, 178),
 
   /* Socks Service */
-  CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179),
+  /* DEPRECATED, do not use! */
+  CURLOPT(CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPTTYPE_STRINGPOINT, 179),
 
   /* Socks Service */
-  CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
+  CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180),
 
   /* set the bitmask for the protocols that are allowed to be used for the
      transfer, which thus helps the app which takes URLs from users or other
      external inputs and want to restrict what protocol(s) to deal
      with. Defaults to CURLPROTO_ALL. */
-  CINIT(PROTOCOLS, LONG, 181),
+  CURLOPT(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181),
 
   /* set the bitmask for the protocols that libcurl is allowed to follow to,
      as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
-     to be set in both bitmasks to be allowed to get redirected to. Defaults
-     to all protocols except FILE and SCP. */
-  CINIT(REDIR_PROTOCOLS, LONG, 182),
+     to be set in both bitmasks to be allowed to get redirected to. */
+  CURLOPT(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182),
 
   /* set the SSH knownhost file name to use */
-  CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183),
+  CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),
 
   /* set the SSH host key callback, must point to a curl_sshkeycallback
      function */
-  CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184),
+  CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184),
 
   /* set the SSH host key callback custom pointer */
-  CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
+  CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_OBJECTPOINT, 185),
 
   /* set the SMTP mail originator */
-  CINIT(MAIL_FROM, OBJECTPOINT, 186),
+  CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186),
 
-  /* set the SMTP mail receiver(s) */
-  CINIT(MAIL_RCPT, OBJECTPOINT, 187),
+  /* set the list of SMTP mail receiver(s) */
+  CURLOPT(CURLOPT_MAIL_RCPT, CURLOPTTYPE_SLISTPOINT, 187),
 
   /* FTP: send PRET before PASV */
-  CINIT(FTP_USE_PRET, LONG, 188),
+  CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188),
 
   /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
-  CINIT(RTSP_REQUEST, LONG, 189),
+  CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_LONG, 189),
 
   /* The RTSP session identifier */
-  CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
+  CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190),
 
   /* The RTSP stream URI */
-  CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
+  CURLOPT(CURLOPT_RTSP_STREAM_URI, CURLOPTTYPE_STRINGPOINT, 191),
 
   /* The Transport: header to use in RTSP requests */
-  CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
+  CURLOPT(CURLOPT_RTSP_TRANSPORT, CURLOPTTYPE_STRINGPOINT, 192),
 
   /* Manually initialize the client RTSP CSeq for this handle */
-  CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
+  CURLOPT(CURLOPT_RTSP_CLIENT_CSEQ, CURLOPTTYPE_LONG, 193),
 
   /* Manually initialize the server RTSP CSeq for this handle */
-  CINIT(RTSP_SERVER_CSEQ, LONG, 194),
+  CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194),
 
   /* The stream to pass to INTERLEAVEFUNCTION. */
-  CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
+  CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_OBJECTPOINT, 195),
 
   /* Let the application define a custom write method for RTP data */
-  CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
+  CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196),
 
   /* Turn on wildcard matching */
-  CINIT(WILDCARDMATCH, LONG, 197),
+  CURLOPT(CURLOPT_WILDCARDMATCH, CURLOPTTYPE_LONG, 197),
 
   /* Directory matching callback called before downloading of an
      individual file (chunk) started */
-  CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198),
+  CURLOPT(CURLOPT_CHUNK_BGN_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 198),
 
   /* Directory matching callback called after the file (chunk)
      was downloaded, or skipped */
-  CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199),
+  CURLOPT(CURLOPT_CHUNK_END_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 199),
 
   /* Change match (fnmatch-like) callback for wildcard matching */
-  CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200),
+  CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200),
 
   /* Let the application define custom chunk data pointer */
-  CINIT(CHUNK_DATA, OBJECTPOINT, 201),
+  CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_OBJECTPOINT, 201),
 
   /* FNMATCH_FUNCTION user pointer */
-  CINIT(FNMATCH_DATA, OBJECTPOINT, 202),
+  CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_OBJECTPOINT, 202),
 
   /* send linked-list of name:port:address sets */
-  CINIT(RESOLVE, OBJECTPOINT, 203),
+  CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203),
 
   /* Set a username for authenticated TLS */
-  CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204),
+  CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204),
 
   /* Set a password for authenticated TLS */
-  CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205),
+  CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205),
 
   /* Set authentication type for authenticated TLS */
-  CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206),
+  CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206),
 
   /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
      compressed transfer-encoded responses. Set to 0 to disable the use of TE:
@@ -1474,7 +1680,274 @@ typedef enum {
      option is set to 1.
 
   */
-  CINIT(TRANSFER_ENCODING, LONG, 207),
+  CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207),
+
+  /* Callback function for closing socket (instead of close(2)). The callback
+     should have type curl_closesocket_callback */
+  CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208),
+  CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 209),
+
+  /* allow GSSAPI credential delegation */
+  CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_LONG, 210),
+
+  /* Set the name servers to use for DNS resolution */
+  CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211),
+
+  /* Time-out accept operations (currently for FTP only) after this amount
+     of milliseconds. */
+  CURLOPT(CURLOPT_ACCEPTTIMEOUT_MS, CURLOPTTYPE_LONG, 212),
+
+  /* Set TCP keepalive */
+  CURLOPT(CURLOPT_TCP_KEEPALIVE, CURLOPTTYPE_LONG, 213),
+
+  /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
+  CURLOPT(CURLOPT_TCP_KEEPIDLE, CURLOPTTYPE_LONG, 214),
+  CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215),
+
+  /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
+  CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_LONG, 216),
+
+  /* Set the SMTP auth originator */
+  CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217),
+
+  /* Enable/disable SASL initial response */
+  CURLOPT(CURLOPT_SASL_IR, CURLOPTTYPE_LONG, 218),
+
+  /* Function that will be called instead of the internal progress display
+   * function. This function should be defined as the curl_xferinfo_callback
+   * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
+  CURLOPT(CURLOPT_XFERINFOFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 219),
+
+  /* The XOAUTH2 bearer token */
+  CURLOPT(CURLOPT_XOAUTH2_BEARER, CURLOPTTYPE_STRINGPOINT, 220),
+
+  /* Set the interface string to use as outgoing network
+   * interface for DNS requests.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_INTERFACE, CURLOPTTYPE_STRINGPOINT, 221),
+
+  /* Set the local IPv4 address to use for outgoing DNS requests.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_LOCAL_IP4, CURLOPTTYPE_STRINGPOINT, 222),
+
+  /* Set the local IPv6 address to use for outgoing DNS requests.
+   * Only supported by the c-ares DNS backend */
+  CURLOPT(CURLOPT_DNS_LOCAL_IP6, CURLOPTTYPE_STRINGPOINT, 223),
+
+  /* Set authentication options directly */
+  CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224),
+
+  /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
+  CURLOPT(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225),
+
+  /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
+  CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226),
+
+  /* Time to wait for a response to a HTTP request containing an
+   * Expect: 100-continue header before sending the data anyway. */
+  CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227),
+
+  /* This points to a linked list of headers used for proxy requests only,
+     struct curl_slist kind */
+  CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228),
+
+  /* Pass in a bitmask of "header options" */
+  CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_LONG, 229),
+
+  /* The public key in DER form used to validate the peer public key
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 230),
+
+  /* Path to Unix domain socket */
+  CURLOPT(CURLOPT_UNIX_SOCKET_PATH, CURLOPTTYPE_STRINGPOINT, 231),
+
+  /* Set if we should verify the certificate status. */
+  CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232),
+
+  /* Set if we should enable TLS false start. */
+  CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233),
+
+  /* Do not squash dot-dot sequences */
+  CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234),
+
+  /* Proxy Service Name */
+  CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235),
+
+  /* Service Name */
+  CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236),
+
+  /* Wait/don't wait for pipe/mutex to clarify */
+  CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237),
+
+  /* Set the protocol used when curl is given a URL without a protocol */
+  CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238),
+
+  /* Set stream weight, 1 - 256 (default is 16) */
+  CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),
+
+  /* Set stream dependency on another CURL handle */
+  CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240),
+
+  /* Set E-xclusive stream dependency on another CURL handle */
+  CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241),
+
+  /* Do not send any tftp option requests to the server */
+  CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242),
+
+  /* Linked-list of host:port:connect-to-host:connect-to-port,
+     overrides the URL's host:port (only for the network layer) */
+  CURLOPT(CURLOPT_CONNECT_TO, CURLOPTTYPE_SLISTPOINT, 243),
+
+  /* Set TCP Fast Open */
+  CURLOPT(CURLOPT_TCP_FASTOPEN, CURLOPTTYPE_LONG, 244),
+
+  /* Continue to send data if the server responds early with an
+   * HTTP status code >= 300 */
+  CURLOPT(CURLOPT_KEEP_SENDING_ON_ERROR, CURLOPTTYPE_LONG, 245),
+
+  /* The CApath or CAfile used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246),
+
+  /* The CApath directory used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247),
+
+  /* Set if we should verify the proxy in ssl handshake,
+     set 1 to verify. */
+  CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248),
+
+  /* Set if we should verify the Common name from the proxy certificate in ssl
+   * handshake, set 1 to check existence, 2 to ensure that it matches
+   * the provided hostname. */
+  CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249),
+
+  /* What version to specifically try to use for proxy.
+     See CURL_SSLVERSION defines below. */
+  CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_LONG, 250),
+
+  /* Set a username for authenticated TLS for proxy */
+  CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251),
+
+  /* Set a password for authenticated TLS for proxy */
+  CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252),
+
+  /* Set authentication type for authenticated TLS for proxy */
+  CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253),
+
+  /* name of the file keeping your private SSL-certificate for proxy */
+  CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254),
+
+  /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for
+     proxy */
+  CURLOPT(CURLOPT_PROXY_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 255),
+
+  /* name of the file keeping your private SSL-key for proxy */
+  CURLOPT(CURLOPT_PROXY_SSLKEY, CURLOPTTYPE_STRINGPOINT, 256),
+
+  /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for
+     proxy */
+  CURLOPT(CURLOPT_PROXY_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 257),
+
+  /* password for the SSL private key for proxy */
+  CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258),
+
+  /* Specify which SSL ciphers to use for proxy */
+  CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259),
+
+  /* CRL file for proxy */
+  CURLOPT(CURLOPT_PROXY_CRLFILE, CURLOPTTYPE_STRINGPOINT, 260),
+
+  /* Enable/disable specific SSL features with a bitmask for proxy, see
+     CURLSSLOPT_* */
+  CURLOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLOPTTYPE_LONG, 261),
+
+  /* Name of pre proxy to use. */
+  CURLOPT(CURLOPT_PRE_PROXY, CURLOPTTYPE_STRINGPOINT, 262),
+
+  /* The public key in DER form used to validate the proxy public key
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263),
+
+  /* Path to an abstract Unix domain socket */
+  CURLOPT(CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOPTTYPE_STRINGPOINT, 264),
+
+  /* Suppress proxy CONNECT response headers from user callbacks */
+  CURLOPT(CURLOPT_SUPPRESS_CONNECT_HEADERS, CURLOPTTYPE_LONG, 265),
+
+  /* The request target, instead of extracted from the URL */
+  CURLOPT(CURLOPT_REQUEST_TARGET, CURLOPTTYPE_STRINGPOINT, 266),
+
+  /* bitmask of allowed auth methods for connections to SOCKS5 proxies */
+  CURLOPT(CURLOPT_SOCKS5_AUTH, CURLOPTTYPE_LONG, 267),
+
+  /* Enable/disable SSH compression */
+  CURLOPT(CURLOPT_SSH_COMPRESSION, CURLOPTTYPE_LONG, 268),
+
+  /* Post MIME data. */
+  CURLOPT(CURLOPT_MIMEPOST, CURLOPTTYPE_OBJECTPOINT, 269),
+
+  /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of
+     seconds since 1 Jan 1970. */
+  CURLOPT(CURLOPT_TIMEVALUE_LARGE, CURLOPTTYPE_OFF_T, 270),
+
+  /* Head start in milliseconds to give happy eyeballs. */
+  CURLOPT(CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPTTYPE_LONG, 271),
+
+  /* Function that will be called before a resolver request is made */
+  CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272),
+
+  /* User data to pass to the resolver start callback. */
+  CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_OBJECTPOINT, 273),
+
+  /* send HAProxy PROXY protocol header? */
+  CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274),
+
+  /* shuffle addresses before use when DNS returns multiple */
+  CURLOPT(CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOPTTYPE_LONG, 275),
+
+  /* Specify which TLS 1.3 ciphers suites to use */
+  CURLOPT(CURLOPT_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 276),
+  CURLOPT(CURLOPT_PROXY_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 277),
+
+  /* Disallow specifying username/login in URL. */
+  CURLOPT(CURLOPT_DISALLOW_USERNAME_IN_URL, CURLOPTTYPE_LONG, 278),
+
+  /* DNS-over-HTTPS URL */
+  CURLOPT(CURLOPT_DOH_URL, CURLOPTTYPE_STRINGPOINT, 279),
+
+  /* Preferred buffer size to use for uploads */
+  CURLOPT(CURLOPT_UPLOAD_BUFFERSIZE, CURLOPTTYPE_LONG, 280),
+
+  /* Time in ms between connection upkeep calls for long-lived connections. */
+  CURLOPT(CURLOPT_UPKEEP_INTERVAL_MS, CURLOPTTYPE_LONG, 281),
+
+  /* Specify URL using CURL URL API. */
+  CURLOPT(CURLOPT_CURLU, CURLOPTTYPE_OBJECTPOINT, 282),
+
+  /* add trailing data just after no more data is available */
+  CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283),
+
+  /* pointer to be passed to HTTP_TRAILER_FUNCTION */
+  CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_OBJECTPOINT, 284),
+
+  /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
+  CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285),
+
+  /* alt-svc control bitmask */
+  CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286),
+
+  /* alt-svc cache file name to possibly read from/write to */
+  CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
+
+  /* maximum age of a connection to consider it for reuse (in seconds) */
+  CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
+
+  /* SASL authorisation identity */
+  CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),
+
+  /* allow RCPT TO command to fail for some recipients */
+  CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
 
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
@@ -1512,13 +1985,10 @@ typedef enum {
      option might be handy to force libcurl to use a specific IP version. */
 #define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
                                      versions that your system allows */
-#define CURL_IPRESOLVE_V4       1 /* resolve to ipv4 addresses */
-#define CURL_IPRESOLVE_V6       2 /* resolve to ipv6 addresses */
+#define CURL_IPRESOLVE_V4       1 /* resolve to IPv4 addresses */
+#define CURL_IPRESOLVE_V6       2 /* resolve to IPv6 addresses */
 
   /* three convenient "aliases" that follow the name scheme better */
-#define CURLOPT_WRITEDATA CURLOPT_FILE
-#define CURLOPT_READDATA  CURLOPT_INFILE
-#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
 #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
 
   /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
@@ -1528,10 +1998,20 @@ enum {
                              for us! */
   CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
   CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
-
+  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
+  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
+  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
+                                           Upgrade */
+  CURL_HTTP_VERSION_3 = 30, /* Makes use of explicit HTTP/3 without fallback.
+                               Use CURLOPT_ALTSVC to enable HTTP/3 upgrade */
   CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
 };
 
+/* Convenience definition simple because the name of the version is HTTP/2 and
+   not 2.0. The 2_0 version of the enum name was set while the version was
+   still planned to be 2.0 and we stick to it for compatibility. */
+#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0
+
 /*
  * Public API enums for RTSP requests
  */
@@ -1565,13 +2045,29 @@ enum CURL_NETRC_OPTION {
 
 enum {
   CURL_SSLVERSION_DEFAULT,
-  CURL_SSLVERSION_TLSv1,
+  CURL_SSLVERSION_TLSv1, /* TLS 1.x */
   CURL_SSLVERSION_SSLv2,
   CURL_SSLVERSION_SSLv3,
+  CURL_SSLVERSION_TLSv1_0,
+  CURL_SSLVERSION_TLSv1_1,
+  CURL_SSLVERSION_TLSv1_2,
+  CURL_SSLVERSION_TLSv1_3,
 
   CURL_SSLVERSION_LAST /* never use, keep last */
 };
 
+enum {
+  CURL_SSLVERSION_MAX_NONE =     0,
+  CURL_SSLVERSION_MAX_DEFAULT =  (CURL_SSLVERSION_TLSv1   << 16),
+  CURL_SSLVERSION_MAX_TLSv1_0 =  (CURL_SSLVERSION_TLSv1_0 << 16),
+  CURL_SSLVERSION_MAX_TLSv1_1 =  (CURL_SSLVERSION_TLSv1_1 << 16),
+  CURL_SSLVERSION_MAX_TLSv1_2 =  (CURL_SSLVERSION_TLSv1_2 << 16),
+  CURL_SSLVERSION_MAX_TLSv1_3 =  (CURL_SSLVERSION_TLSv1_3 << 16),
+
+  /* never use, keep last */
+  CURL_SSLVERSION_MAX_LAST =     (CURL_SSLVERSION_LAST    << 16)
+};
+
 enum CURL_TLSAUTH {
   CURL_TLSAUTH_NONE,
   CURL_TLSAUTH_SRP,
@@ -1579,13 +2075,16 @@ enum CURL_TLSAUTH {
 };
 
 /* symbols to use with CURLOPT_POSTREDIR.
-   CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that
-   CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */
+   CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
+   can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
+   | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */
 
 #define CURL_REDIR_GET_ALL  0
 #define CURL_REDIR_POST_301 1
 #define CURL_REDIR_POST_302 2
-#define CURL_REDIR_POST_ALL (CURL_REDIR_POST_301|CURL_REDIR_POST_302)
+#define CURL_REDIR_POST_303 4
+#define CURL_REDIR_POST_ALL \
+    (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
 
 typedef enum {
   CURL_TIMECOND_NONE,
@@ -1597,56 +2096,168 @@ typedef enum {
   CURL_TIMECOND_LAST
 } curl_TimeCond;
 
+/* Special size_t value signaling a zero-terminated string. */
+#define CURL_ZERO_TERMINATED ((size_t) -1)
 
 /* curl_strequal() and curl_strnequal() are subject for removal in a future
-   libcurl, see lib/README.curlx for details */
-CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
-CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n);
+   release */
+CURL_EXTERN int curl_strequal(const char *s1, const char *s2);
+CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n);
 
-/* name is uppercase CURLFORM_<name> */
-#ifdef CFINIT
-#undef CFINIT
-#endif
+/* Mime/form handling support. */
+typedef struct curl_mime_s      curl_mime;      /* Mime context. */
+typedef struct curl_mimepart_s  curl_mimepart;  /* Mime part context. */
 
-#ifdef CURL_ISOCPP
-#define CFINIT(name) CURLFORM_ ## name
-#else
-/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
-#define CFINIT(name) CURLFORM_/**/name
-#endif
+/*
+ * NAME curl_mime_init()
+ *
+ * DESCRIPTION
+ *
+ * Create a mime context and return its handle. The easy parameter is the
+ * target handle.
+ */
+CURL_EXTERN curl_mime *curl_mime_init(CURL *easy);
+
+/*
+ * NAME curl_mime_free()
+ *
+ * DESCRIPTION
+ *
+ * release a mime handle and its substructures.
+ */
+CURL_EXTERN void curl_mime_free(curl_mime *mime);
+
+/*
+ * NAME curl_mime_addpart()
+ *
+ * DESCRIPTION
+ *
+ * Append a new empty part to the given mime context and return a handle to
+ * the created part.
+ */
+CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime);
+
+/*
+ * NAME curl_mime_name()
+ *
+ * DESCRIPTION
+ *
+ * Set mime/form part name.
+ */
+CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);
+
+/*
+ * NAME curl_mime_filename()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part remote file name.
+ */
+CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
+                                        const char *filename);
+
+/*
+ * NAME curl_mime_type()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part type.
+ */
+CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype);
+
+/*
+ * NAME curl_mime_encoder()
+ *
+ * DESCRIPTION
+ *
+ * Set mime data transfer encoder.
+ */
+CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part,
+                                       const char *encoding);
+
+/*
+ * NAME curl_mime_data()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from memory data,
+ */
+CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part,
+                                    const char *data, size_t datasize);
+
+/*
+ * NAME curl_mime_filedata()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from named file.
+ */
+CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part,
+                                        const char *filename);
+
+/*
+ * NAME curl_mime_data_cb()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from callback function.
+ */
+CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part,
+                                       curl_off_t datasize,
+                                       curl_read_callback readfunc,
+                                       curl_seek_callback seekfunc,
+                                       curl_free_callback freefunc,
+                                       void *arg);
+
+/*
+ * NAME curl_mime_subparts()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from subparts.
+ */
+CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part,
+                                        curl_mime *subparts);
+/*
+ * NAME curl_mime_headers()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part headers.
+ */
+CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part,
+                                       struct curl_slist *headers,
+                                       int take_ownership);
 
 typedef enum {
-  CFINIT(NOTHING),        /********* the first one is unused ************/
-
-  /*  */
-  CFINIT(COPYNAME),
-  CFINIT(PTRNAME),
-  CFINIT(NAMELENGTH),
-  CFINIT(COPYCONTENTS),
-  CFINIT(PTRCONTENTS),
-  CFINIT(CONTENTSLENGTH),
-  CFINIT(FILECONTENT),
-  CFINIT(ARRAY),
-  CFINIT(OBSOLETE),
-  CFINIT(FILE),
-
-  CFINIT(BUFFER),
-  CFINIT(BUFFERPTR),
-  CFINIT(BUFFERLENGTH),
-
-  CFINIT(CONTENTTYPE),
-  CFINIT(CONTENTHEADER),
-  CFINIT(FILENAME),
-  CFINIT(END),
-  CFINIT(OBSOLETE2),
-
-  CFINIT(STREAM),
+  CURLFORM_NOTHING,        /********* the first one is unused ************/
+  CURLFORM_COPYNAME,
+  CURLFORM_PTRNAME,
+  CURLFORM_NAMELENGTH,
+  CURLFORM_COPYCONTENTS,
+  CURLFORM_PTRCONTENTS,
+  CURLFORM_CONTENTSLENGTH,
+  CURLFORM_FILECONTENT,
+  CURLFORM_ARRAY,
+  CURLFORM_OBSOLETE,
+  CURLFORM_FILE,
+
+  CURLFORM_BUFFER,
+  CURLFORM_BUFFERPTR,
+  CURLFORM_BUFFERLENGTH,
+
+  CURLFORM_CONTENTTYPE,
+  CURLFORM_CONTENTHEADER,
+  CURLFORM_FILENAME,
+  CURLFORM_END,
+  CURLFORM_OBSOLETE2,
+
+  CURLFORM_STREAM,
+  CURLFORM_CONTENTLEN, /* added in 7.46.0, provide a curl_off_t length */
 
   CURLFORM_LASTENTRY /* the last unused */
 } CURLformoption;
 
-#undef CFINIT /* done */
-
 /* structure to be used as parameter for CURLFORM_ARRAY */
 struct curl_forms {
   CURLformoption option;
@@ -1704,7 +2315,8 @@ CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
  * Should return the buffer length passed to it as the argument "len" on
  *   success.
  */
-typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len);
+typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
+                                        size_t len);
 
 /*
  * NAME curl_formget()
@@ -1842,6 +2454,47 @@ struct curl_slist {
   struct curl_slist *next;
 };
 
+/*
+ * NAME curl_global_sslset()
+ *
+ * DESCRIPTION
+ *
+ * When built with multiple SSL backends, curl_global_sslset() allows to
+ * choose one. This function can only be called once, and it must be called
+ * *before* curl_global_init().
+ *
+ * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The
+ * backend can also be specified via the name parameter (passing -1 as id).
+ * If both id and name are specified, the name will be ignored. If neither id
+ * nor name are specified, the function will fail with
+ * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the
+ * NULL-terminated list of available backends.
+ *
+ * Upon success, the function returns CURLSSLSET_OK.
+ *
+ * If the specified SSL backend is not available, the function returns
+ * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated
+ * list of available SSL backends.
+ *
+ * The SSL backend can be set only once. If it has already been set, a
+ * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE.
+ */
+
+typedef struct {
+  curl_sslbackend id;
+  const char *name;
+} curl_ssl_backend;
+
+typedef enum {
+  CURLSSLSET_OK = 0,
+  CURLSSLSET_UNKNOWN_BACKEND,
+  CURLSSLSET_TOO_LATE,
+  CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */
+} CURLsslset;
+
+CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
+                                          const curl_ssl_backend ***avail);
+
 /*
  * NAME curl_slist_append()
  *
@@ -1873,8 +2526,8 @@ CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
  */
 CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
 
-/* info about the certificate chain, only for OpenSSL builds. Asked
-   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+/* info about the certificate chain, only for OpenSSL, GnuTLS, Schannel, NSS
+   and GSKit builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
 struct curl_certinfo {
   int num_of_certs;             /* number of certificates with information */
   struct curl_slist **certinfo; /* for each index in this array, there's a
@@ -1882,10 +2535,21 @@ struct curl_certinfo {
                                    format "name: value" */
 };
 
+/* Information about the SSL library used and the respective internal SSL
+   handle, which can be used to obtain further information regarding the
+   connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
+struct curl_tlssessioninfo {
+  curl_sslbackend backend;
+  void *internals;
+};
+
 #define CURLINFO_STRING   0x100000
 #define CURLINFO_LONG     0x200000
 #define CURLINFO_DOUBLE   0x300000
 #define CURLINFO_SLIST    0x400000
+#define CURLINFO_PTR      0x400000 /* same as SLIST */
+#define CURLINFO_SOCKET   0x500000
+#define CURLINFO_OFF_T    0x600000
 #define CURLINFO_MASK     0x0fffff
 #define CURLINFO_TYPEMASK 0xf00000
 
@@ -1898,15 +2562,22 @@ typedef enum {
   CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
   CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
   CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
+  CURLINFO_SIZE_UPLOAD_T    = CURLINFO_OFF_T  + 7,
   CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
+  CURLINFO_SIZE_DOWNLOAD_T  = CURLINFO_OFF_T  + 8,
   CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
+  CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T  + 9,
   CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
+  CURLINFO_SPEED_UPLOAD_T   = CURLINFO_OFF_T  + 10,
   CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
   CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
   CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
   CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
+  CURLINFO_FILETIME_T       = CURLINFO_OFF_T  + 14,
   CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T  + 15,
   CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
+  CURLINFO_CONTENT_LENGTH_UPLOAD_T   = CURLINFO_OFF_T  + 16,
   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
   CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
   CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
@@ -1924,7 +2595,7 @@ typedef enum {
   CURLINFO_REDIRECT_URL     = CURLINFO_STRING + 31,
   CURLINFO_PRIMARY_IP       = CURLINFO_STRING + 32,
   CURLINFO_APPCONNECT_TIME  = CURLINFO_DOUBLE + 33,
-  CURLINFO_CERTINFO         = CURLINFO_SLIST  + 34,
+  CURLINFO_CERTINFO         = CURLINFO_PTR    + 34,
   CURLINFO_CONDITION_UNMET  = CURLINFO_LONG   + 35,
   CURLINFO_RTSP_SESSION_ID  = CURLINFO_STRING + 36,
   CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG   + 37,
@@ -1933,9 +2604,27 @@ typedef enum {
   CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
+  CURLINFO_TLS_SESSION      = CURLINFO_PTR    + 43,
+  CURLINFO_ACTIVESOCKET     = CURLINFO_SOCKET + 44,
+  CURLINFO_TLS_SSL_PTR      = CURLINFO_PTR    + 45,
+  CURLINFO_HTTP_VERSION     = CURLINFO_LONG   + 46,
+  CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
+  CURLINFO_PROTOCOL         = CURLINFO_LONG   + 48,
+  CURLINFO_SCHEME           = CURLINFO_STRING + 49,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 42
+  /* Preferably these would be defined conditionally based on the
+     sizeof curl_off_t being 64-bits */
+  CURLINFO_TOTAL_TIME_T     = CURLINFO_OFF_T + 50,
+  CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51,
+  CURLINFO_CONNECT_TIME_T   = CURLINFO_OFF_T + 52,
+  CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53,
+  CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54,
+  CURLINFO_REDIRECT_TIME_T  = CURLINFO_OFF_T + 55,
+  CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56,
+  CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
+
+  CURLINFO_LASTONE          = 57
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -1954,11 +2643,12 @@ typedef enum {
   CURLCLOSEPOLICY_LAST /* last, never use this */
 } curl_closepolicy;
 
-#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */
 #define CURL_GLOBAL_WIN32 (1<<1)
 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
 #define CURL_GLOBAL_NOTHING 0
 #define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
+#define CURL_GLOBAL_ACK_EINTR (1<<2)
 
 
 /*****************************************************************************
@@ -1977,6 +2667,7 @@ typedef enum {
   CURL_LOCK_DATA_DNS,
   CURL_LOCK_DATA_SSL_SESSION,
   CURL_LOCK_DATA_CONNECT,
+  CURL_LOCK_DATA_PSL,
   CURL_LOCK_DATA_LAST
 } curl_lock_data;
 
@@ -1996,15 +2687,15 @@ typedef void (*curl_unlock_function)(CURL *handle,
                                      curl_lock_data data,
                                      void *userptr);
 
-typedef void CURLSH;
 
 typedef enum {
   CURLSHE_OK,  /* all is fine */
   CURLSHE_BAD_OPTION, /* 1 */
   CURLSHE_IN_USE,     /* 2 */
   CURLSHE_INVALID,    /* 3 */
-  CURLSHE_NOMEM,      /* out of memory */
-  CURLSHE_LAST /* never use */
+  CURLSHE_NOMEM,      /* 4 out of memory */
+  CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
+  CURLSHE_LAST        /* never use */
 } CURLSHcode;
 
 typedef enum {
@@ -2031,6 +2722,8 @@ typedef enum {
   CURLVERSION_SECOND,
   CURLVERSION_THIRD,
   CURLVERSION_FOURTH,
+  CURLVERSION_FIFTH,
+  CURLVERSION_SIXTH,
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 
@@ -2039,7 +2732,7 @@ typedef enum {
    meant to be a built-in version number for what kind of struct the caller
    expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
-#define CURLVERSION_NOW CURLVERSION_FOURTH
+#define CURLVERSION_NOW CURLVERSION_SIXTH
 
 typedef struct {
   CURLversion age;          /* age of the returned struct */
@@ -2067,25 +2760,54 @@ typedef struct {
 
   const char *libssh_version; /* human readable string */
 
+  /* These fields were added in CURLVERSION_FIFTH */
+  unsigned int brotli_ver_num; /* Numeric Brotli version
+                                  (MAJOR << 24) | (MINOR << 12) | PATCH */
+  const char *brotli_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_SIXTH */
+  unsigned int nghttp2_ver_num; /* Numeric nghttp2 version
+                                   (MAJOR << 16) | (MINOR << 8) | PATCH */
+  const char *nghttp2_version; /* human readable string. */
+  const char *quic_version;    /* human readable quic (+ HTTP/3) library +
+                                  version or NULL */
 } curl_version_info_data;
 
-#define CURL_VERSION_IPV6      (1<<0)  /* IPv6-enabled */
-#define CURL_VERSION_KERBEROS4 (1<<1)  /* kerberos auth is supported */
-#define CURL_VERSION_SSL       (1<<2)  /* SSL options are present */
-#define CURL_VERSION_LIBZ      (1<<3)  /* libz features are present */
-#define CURL_VERSION_NTLM      (1<<4)  /* NTLM auth is supported */
-#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
-#define CURL_VERSION_DEBUG     (1<<6)  /* built with debug capabilities */
-#define CURL_VERSION_ASYNCHDNS (1<<7)  /* asynchronous dns resolves */
-#define CURL_VERSION_SPNEGO    (1<<8)  /* SPNEGO auth */
-#define CURL_VERSION_LARGEFILE (1<<9)  /* supports files bigger than 2GB */
-#define CURL_VERSION_IDN       (1<<10) /* International Domain Names support */
-#define CURL_VERSION_SSPI      (1<<11) /* SSPI is supported */
-#define CURL_VERSION_CONV      (1<<12) /* character conversions supported */
-#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */
-#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
-
-/*
+#define CURL_VERSION_IPV6         (1<<0)  /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4    (1<<1)  /* Kerberos V4 auth is supported
+                                             (deprecated) */
+#define CURL_VERSION_SSL          (1<<2)  /* SSL options are present */
+#define CURL_VERSION_LIBZ         (1<<3)  /* libz features are present */
+#define CURL_VERSION_NTLM         (1<<4)  /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5)  /* Negotiate auth is supported
+                                             (deprecated) */
+#define CURL_VERSION_DEBUG        (1<<6)  /* Built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS    (1<<7)  /* Asynchronous DNS resolves */
+#define CURL_VERSION_SPNEGO       (1<<8)  /* SPNEGO auth is supported */
+#define CURL_VERSION_LARGEFILE    (1<<9)  /* Supports files larger than 2GB */
+#define CURL_VERSION_IDN          (1<<10) /* Internationized Domain Names are
+                                             supported */
+#define CURL_VERSION_SSPI         (1<<11) /* Built against Windows SSPI */
+#define CURL_VERSION_CONV         (1<<12) /* Character conversions supported */
+#define CURL_VERSION_CURLDEBUG    (1<<13) /* Debug memory tracking supported */
+#define CURL_VERSION_TLSAUTH_SRP  (1<<14) /* TLS-SRP auth is supported */
+#define CURL_VERSION_NTLM_WB      (1<<15) /* NTLM delegation to winbind helper
+                                             is supported */
+#define CURL_VERSION_HTTP2        (1<<16) /* HTTP2 support built-in */
+#define CURL_VERSION_GSSAPI       (1<<17) /* Built against a GSS-API library */
+#define CURL_VERSION_KERBEROS5    (1<<18) /* Kerberos V5 auth is supported */
+#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
+#define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
+                                             for cookie domain verification */
+#define CURL_VERSION_HTTPS_PROXY  (1<<21) /* HTTPS-proxy support built-in */
+#define CURL_VERSION_MULTI_SSL    (1<<22) /* Multiple SSL backends available */
+#define CURL_VERSION_BROTLI       (1<<23) /* Brotli features are present. */
+#define CURL_VERSION_ALTSVC       (1<<24) /* Alt-Svc handling built-in */
+#define CURL_VERSION_HTTP3        (1<<25) /* HTTP3 support built-in */
+
+#define CURL_VERSION_ESNI         (1<<26) /* ESNI support */
+
+ /*
  * NAME curl_version_info()
  *
  * DESCRIPTION
@@ -2145,6 +2867,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
   stuff before they can be included! */
 #include "easy.h" /* nothing in curl is fun without the easy stuff */
 #include "multi.h"
+#include "urlapi.h"
 
 /* the typechecker doesn't work in C++ (yet) */
 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
@@ -2163,4 +2886,4 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #endif /* __STDC__ >= 1 */
 #endif /* gcc >= 4.3 && !__cplusplus */
 
-#endif /* __CURL_CURL_H */
+#endif /* CURLINC_CURL_H */
diff --git a/libs/curl/include/curl/curlver.h b/libs/curl/include/curl/curlver.h
index 4db21857d833c3ddebdf8b9cf20b3429902d9b19..5264f19865ea3d2d14524851416547edc23fbea5 100644
--- a/libs/curl/include/curl/curlver.h
+++ b/libs/curl/include/curl/curlver.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_CURLVER_H
-#define __CURL_CURLVER_H
+#ifndef CURLINC_CURLVER_H
+#define CURLINC_CURLVER_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -26,17 +26,17 @@
    a script at release-time. This was made its own header file in 7.11.2 */
 
 /* This is the global package copyright */
-#define LIBCURL_COPYRIGHT "1996 - 2011 Daniel Stenberg, <daniel@haxx.se>."
+#define LIBCURL_COPYRIGHT "1996 - 2020 Daniel Stenberg, <daniel@haxx.se>."
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.21.6"
+#define LIBCURL_VERSION "7.69.0"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 21
-#define LIBCURL_VERSION_PATCH 6
+#define LIBCURL_VERSION_MINOR 69
+#define LIBCURL_VERSION_PATCH 0
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
@@ -52,18 +52,26 @@
    This 6-digit (24 bits) hexadecimal number does not show pre-release number,
    and it is always a greater number in a more recent release. It makes
    comparisons with greater than and less than work.
+
+   Note: This define is the full hex number and _does not_ use the
+   CURL_VERSION_BITS() macro since curl's own configure script greps for it
+   and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x071506
+#define LIBCURL_VERSION_NUM 0x074500
 
 /*
  * This is the date and time when the full source package was created. The
  * timestamp is not stored in git, as the timestamp is properly set in the
  * tarballs by the maketgz script.
  *
- * The format of the date should follow this template:
+ * The format of the date follows this template:
  *
- * "Mon Feb 12 11:35:33 UTC 2007"
+ * "2007-11-23"
  */
-#define LIBCURL_TIMESTAMP "Fri Apr 22 17:18:50 UTC 2011"
+#define LIBCURL_TIMESTAMP "2020-03-04"
+
+#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
+#define CURL_AT_LEAST_VERSION(x,y,z) \
+  (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
 
-#endif /* __CURL_CURLVER_H */
+#endif /* CURLINC_CURLVER_H */
diff --git a/libs/curl/include/curl/easy.h b/libs/curl/include/curl/easy.h
index c1e3e76096e3925821da279a2f2eae67ae61e0e8..592f5d3c1c3ca110d5ddd02db67fd20dcfab265c 100644
--- a/libs/curl/include/curl/easy.h
+++ b/libs/curl/include/curl/easy.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_EASY_H
-#define __CURL_EASY_H
+#ifndef CURLINC_EASY_H
+#define CURLINC_EASY_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -58,7 +58,7 @@ CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
  * curl_easy_duphandle() for each new thread to avoid a series of identical
  * curl_easy_setopt() invokes in every thread.
  */
-CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
+CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl);
 
 /*
  * NAME curl_easy_reset()
@@ -95,6 +95,16 @@ CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
 CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
                                     size_t buflen, size_t *n);
 
+
+/*
+ * NAME curl_easy_upkeep()
+ *
+ * DESCRIPTION
+ *
+ * Performs connection upkeep for the given session handle.
+ */
+CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/libs/curl/include/curl/mprintf.h b/libs/curl/include/curl/mprintf.h
index de7dd2f3c360e327e6280372e8a10f335fcf3504..f615ed7d63d9e047824bd1cda14fc75f26ff623a 100644
--- a/libs/curl/include/curl/mprintf.h
+++ b/libs/curl/include/curl/mprintf.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_MPRINTF_H
-#define __CURL_MPRINTF_H
+#ifndef CURLINC_MPRINTF_H
+#define CURLINC_MPRINTF_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -24,8 +24,7 @@
 
 #include <stdarg.h>
 #include <stdio.h> /* needed for FILE */
-
-#include "curl.h"
+#include "curl.h"  /* for CURL_EXTERN */
 
 #ifdef  __cplusplus
 extern "C" {
@@ -44,38 +43,8 @@ CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
 CURL_EXTERN char *curl_maprintf(const char *format, ...);
 CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
 
-#ifdef _MPRINTF_REPLACE
-# undef printf
-# undef fprintf
-# undef sprintf
-# undef vsprintf
-# undef snprintf
-# undef vprintf
-# undef vfprintf
-# undef vsnprintf
-# undef aprintf
-# undef vaprintf
-# define printf curl_mprintf
-# define fprintf curl_mfprintf
-#ifdef CURLDEBUG
-/* When built with CURLDEBUG we define away the sprintf() functions since we
-   don't want internal code to be using them */
-# define sprintf sprintf_was_used
-# define vsprintf vsprintf_was_used
-#else
-# define sprintf curl_msprintf
-# define vsprintf curl_mvsprintf
-#endif
-# define snprintf curl_msnprintf
-# define vprintf curl_mvprintf
-# define vfprintf curl_mvfprintf
-# define vsnprintf curl_mvsnprintf
-# define aprintf curl_maprintf
-# define vaprintf curl_mvaprintf
-#endif
-
 #ifdef  __cplusplus
 }
 #endif
 
-#endif /* __CURL_MPRINTF_H */
+#endif /* CURLINC_MPRINTF_H */
diff --git a/libs/curl/include/curl/multi.h b/libs/curl/include/curl/multi.h
index f96566669c6771fbbf2e1735f826d8cb3a1fce11..bda9bb7b816c400e2cde1795f4dae8937afbfd0a 100644
--- a/libs/curl/include/curl/multi.h
+++ b/libs/curl/include/curl/multi.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_MULTI_H
-#define __CURL_MULTI_H
+#ifndef CURLINC_MULTI_H
+#define CURLINC_MULTI_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -52,7 +52,11 @@
 extern "C" {
 #endif
 
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_multi CURLM;
+#else
 typedef void CURLM;
+#endif
 
 typedef enum {
   CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
@@ -64,6 +68,12 @@ typedef enum {
   CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
   CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
   CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
+  CURLM_ADDED_ALREADY,   /* an easy handle already added to a multi handle was
+                            attempted to get added - again */
+  CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
+                               callback */
+  CURLM_WAKEUP_FAILURE,  /* wakeup is unavailable or failed */
+  CURLM_BAD_FUNCTION_ARGUMENT,  /* function called with a bad parameter */
   CURLM_LAST
 } CURLMcode;
 
@@ -72,6 +82,11 @@ typedef enum {
    curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
 #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
 
+/* bitmask bits for CURLMOPT_PIPELINING */
+#define CURLPIPE_NOTHING   0L
+#define CURLPIPE_HTTP1     1L
+#define CURLPIPE_MULTIPLEX 2L
+
 typedef enum {
   CURLMSG_NONE, /* first, not used */
   CURLMSG_DONE, /* This easy handle has completed. 'result' contains
@@ -89,6 +104,19 @@ struct CURLMsg {
 };
 typedef struct CURLMsg CURLMsg;
 
+/* Based on poll(2) structure and values.
+ * We don't use pollfd and POLL* constants explicitly
+ * to cover platforms without poll(). */
+#define CURL_WAIT_POLLIN    0x0001
+#define CURL_WAIT_POLLPRI   0x0002
+#define CURL_WAIT_POLLOUT   0x0004
+
+struct curl_waitfd {
+  curl_socket_t fd;
+  short events;
+  short revents; /* not supported yet */
+};
+
 /*
  * Name:    curl_multi_init()
  *
@@ -133,6 +161,43 @@ CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
                                        fd_set *exc_fd_set,
                                        int *max_fd);
 
+/*
+ * Name:     curl_multi_wait()
+ *
+ * Desc:     Poll on all fds within a CURLM set as well as any
+ *           additional fds passed to the function.
+ *
+ * Returns:  CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
+                                      struct curl_waitfd extra_fds[],
+                                      unsigned int extra_nfds,
+                                      int timeout_ms,
+                                      int *ret);
+
+/*
+ * Name:     curl_multi_poll()
+ *
+ * Desc:     Poll on all fds within a CURLM set as well as any
+ *           additional fds passed to the function.
+ *
+ * Returns:  CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle,
+                                      struct curl_waitfd extra_fds[],
+                                      unsigned int extra_nfds,
+                                      int timeout_ms,
+                                      int *ret);
+
+/*
+ * Name:     curl_multi_wakeup()
+ *
+ * Desc:     wakes up a sleeping curl_multi_poll call.
+ *
+ * Returns:  CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
+
  /*
   * Name:    curl_multi_perform()
   *
@@ -146,8 +211,8 @@ CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
   *
   * Returns: CURLMcode type, general multi error code. *NOTE* that this only
   *          returns errors etc regarding the whole multi stack. There might
-  *          still have occurred problems on invidual transfers even when this
-  *          returns OK.
+  *          still have occurred problems on individual transfers even when
+  *          this returns OK.
   */
 CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
                                          int *running_handles);
@@ -180,7 +245,7 @@ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
  *          curl_multi_cleanup().
  *
  *          The 'CURLMsg' struct is meant to be very simple and only contain
- *          very basic informations. If more involved information is wanted,
+ *          very basic information. If more involved information is wanted,
  *          we will provide the particular "transfer handle" in that struct
  *          and that should/could/would be used in subsequent
  *          curl_easy_getinfo() calls (or similar). The point being that we
@@ -279,37 +344,58 @@ CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
 CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
                                          long *milliseconds);
 
-#undef CINIT /* re-using the same name as in curl.h */
-
-#ifdef CURL_ISOCPP
-#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
-#else
-/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
-#define LONG          CURLOPTTYPE_LONG
-#define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
-#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
-#define OFF_T         CURLOPTTYPE_OFF_T
-#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
-#endif
-
 typedef enum {
   /* This is the socket callback function pointer */
-  CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
+  CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1),
 
   /* This is the argument passed to the socket callback */
-  CINIT(SOCKETDATA, OBJECTPOINT, 2),
+  CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2),
 
     /* set to 1 to enable pipelining for this multi handle */
-  CINIT(PIPELINING, LONG, 3),
+  CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3),
 
    /* This is the timer callback function pointer */
-  CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+  CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4),
 
   /* This is the argument passed to the timer callback */
-  CINIT(TIMERDATA, OBJECTPOINT, 5),
+  CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5),
 
   /* maximum number of entries in the connection cache */
-  CINIT(MAXCONNECTS, LONG, 6),
+  CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6),
+
+  /* maximum number of (pipelining) connections to one host */
+  CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7),
+
+  /* maximum number of requests in a pipeline */
+  CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8),
+
+  /* a connection with a content-length longer than this
+     will not be considered for pipelining */
+  CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9),
+
+  /* a connection with a chunk length longer than this
+     will not be considered for pipelining */
+  CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10),
+
+  /* a list of site names(+port) that are blacklisted from
+     pipelining */
+  CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11),
+
+  /* a list of server types that are blacklisted from
+     pipelining */
+  CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12),
+
+  /* maximum number of open connections in total */
+  CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13),
+
+   /* This is the server push callback function pointer */
+  CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14),
+
+  /* This is the argument passed to the server push callback */
+  CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15),
+
+  /* maximum number of concurrent streams to support on a connection */
+  CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16),
 
   CURLMOPT_LASTENTRY /* the last unused */
 } CURLMoption;
@@ -338,6 +424,31 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
 CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
                                         curl_socket_t sockfd, void *sockp);
 
+
+/*
+ * Name: curl_push_callback
+ *
+ * Desc: This callback gets called when a new stream is being pushed by the
+ *       server. It approves or denies the new stream.
+ *
+ * Returns: CURL_PUSH_OK or CURL_PUSH_DENY.
+ */
+#define CURL_PUSH_OK   0
+#define CURL_PUSH_DENY 1
+
+struct curl_pushheaders;  /* forward declaration only */
+
+CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
+                                        size_t num);
+CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
+                                         const char *name);
+
+typedef int (*curl_push_callback)(CURL *parent,
+                                  CURL *easy,
+                                  size_t num_headers,
+                                  struct curl_pushheaders *headers,
+                                  void *userp);
+
 #ifdef __cplusplus
 } /* end of extern "C" */
 #endif
diff --git a/libs/curl/include/curl/stdcheaders.h b/libs/curl/include/curl/stdcheaders.h
index ad82ef6335d6167aecf8b9e49d68c462ea028bfd..a6bdc1a25ca3ee8e7dcea56575212a7e73239b9e 100644
--- a/libs/curl/include/curl/stdcheaders.h
+++ b/libs/curl/include/curl/stdcheaders.h
@@ -1,5 +1,5 @@
-#ifndef __STDC_HEADERS_H
-#define __STDC_HEADERS_H
+#ifndef CURLINC_STDCHEADERS_H
+#define CURLINC_STDCHEADERS_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -24,10 +24,10 @@
 
 #include <sys/types.h>
 
-size_t fread (void *, size_t, size_t, FILE *);
-size_t fwrite (const void *, size_t, size_t, FILE *);
+size_t fread(void *, size_t, size_t, FILE *);
+size_t fwrite(const void *, size_t, size_t, FILE *);
 
 int strcasecmp(const char *, const char *);
 int strncasecmp(const char *, const char *, size_t);
 
-#endif /* __STDC_HEADERS_H */
+#endif /* CURLINC_STDCHEADERS_H */
diff --git a/libs/curl/include/curl/system.h b/libs/curl/include/curl/system.h
new file mode 100644
index 0000000000000000000000000000000000000000..867af614187227cba7734ace2df73eb85e48c6cb
--- /dev/null
+++ b/libs/curl/include/curl/system.h
@@ -0,0 +1,504 @@
+#ifndef CURLINC_SYSTEM_H
+#define CURLINC_SYSTEM_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Try to keep one section per platform, compiler and architecture, otherwise,
+ * if an existing section is reused for a different one and later on the
+ * original is adjusted, probably the piggybacking one can be adversely
+ * changed.
+ *
+ * In order to differentiate between platforms/compilers/architectures use
+ * only compiler built in predefined preprocessor symbols.
+ *
+ * curl_off_t
+ * ----------
+ *
+ * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit
+ * wide signed integral data type. The width of this data type must remain
+ * constant and independent of any possible large file support settings.
+ *
+ * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit
+ * wide signed integral data type if there is no 64-bit type.
+ *
+ * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
+ * only be violated if off_t is the only 64-bit data type available and the
+ * size of off_t is independent of large file support settings. Keep your
+ * build on the safe side avoiding an off_t gating.  If you have a 64-bit
+ * off_t then take for sure that another 64-bit data type exists, dig deeper
+ * and you will find it.
+ *
+ */
+
+#if defined(__DJGPP__) || defined(__GO32__)
+#  if defined(__DJGPP__) && (__DJGPP__ > 1)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__SALFORDC__)
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__BORLANDC__)
+#  if (__BORLANDC__ < 0x520)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__TURBOC__)
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__WATCOMC__)
+#  if defined(__386__)
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__POCC__)
+#  if (__POCC__ < 280)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  elif defined(_MSC_VER)
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__LCC__)
+#  if defined(__e2k__) /* MCST eLbrus C Compiler */
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
+#  else                /* Local (or Little) C Compiler */
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  endif
+
+#elif defined(__SYMBIAN32__)
+#  if defined(__EABI__) /* Treat all ARM compilers equally */
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__CW32__)
+#    pragma longlong on
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__VC32__)
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+
+#elif defined(__MWERKS__)
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(_WIN32_WCE)
+#  define CURL_TYPEOF_CURL_OFF_T     __int64
+#  define CURL_FORMAT_CURL_OFF_T     "I64d"
+#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#  define CURL_SUFFIX_CURL_OFF_T     i64
+#  define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__MINGW32__)
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "I64d"
+#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_WS2TCPIP_H       1
+
+#elif defined(__VMS)
+#  if defined(__VAX)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+
+#elif defined(__OS400__)
+#  if defined(__ILEC400__)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
+#  endif
+
+#elif defined(__MVS__)
+#  if defined(__IBMC__) || defined(__IBMCPP__)
+#    if defined(_ILP32)
+#    elif defined(_LP64)
+#    endif
+#    if defined(_LONG_LONG)
+#      define CURL_TYPEOF_CURL_OFF_T     long long
+#      define CURL_FORMAT_CURL_OFF_T     "lld"
+#      define CURL_FORMAT_CURL_OFF_TU    "llu"
+#      define CURL_SUFFIX_CURL_OFF_T     LL
+#      define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    elif defined(_LP64)
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
+#    else
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
+#    endif
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
+#  endif
+
+#elif defined(__370__)
+#  if defined(__IBMC__) || defined(__IBMCPP__)
+#    if defined(_ILP32)
+#    elif defined(_LP64)
+#    endif
+#    if defined(_LONG_LONG)
+#      define CURL_TYPEOF_CURL_OFF_T     long long
+#      define CURL_FORMAT_CURL_OFF_T     "lld"
+#      define CURL_FORMAT_CURL_OFF_TU    "llu"
+#      define CURL_SUFFIX_CURL_OFF_T     LL
+#      define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    elif defined(_LP64)
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
+#    else
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
+#    endif
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
+#  endif
+
+#elif defined(TPF)
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+#elif defined(__TINYC__) /* also known as tcc */
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */
+#  if !defined(__LP64) && (defined(__ILP32) ||                          \
+                           defined(__i386) ||                           \
+                           defined(__sparcv8) ||                        \
+                           defined(__sparcv8plus))
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__LP64) || \
+        defined(__amd64) || defined(__sparcv9)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__xlc__) /* IBM xlc compiler */
+#  if !defined(_LP64)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+/* ===================================== */
+/*    KEEP MSVC THE PENULTIMATE ENTRY    */
+/* ===================================== */
+
+#elif defined(_MSC_VER)
+#  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
+
+/* ===================================== */
+/*    KEEP GENERIC GCC THE LAST ENTRY    */
+/* ===================================== */
+
+#elif defined(__GNUC__) && !defined(_SCO_DS)
+#  if !defined(__LP64__) &&                                             \
+  (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) ||      \
+   defined(__ppc__) || defined(__powerpc__) || defined(__arm__) ||      \
+   defined(__sparc__) || defined(__mips__) || defined(__sh__) ||        \
+   defined(__XTENSA__) ||                                               \
+   (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4)  ||               \
+   (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L))
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__LP64__) || \
+        defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \
+        defined(__e2k__) || \
+        (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \
+        (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#else
+/* generic "safe guess" on old 32 bit style */
+# define CURL_TYPEOF_CURL_OFF_T     long
+# define CURL_FORMAT_CURL_OFF_T     "ld"
+# define CURL_FORMAT_CURL_OFF_TU    "lu"
+# define CURL_SUFFIX_CURL_OFF_T     L
+# define CURL_SUFFIX_CURL_OFF_TU    UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+#endif
+
+#ifdef _AIX
+/* AIX needs <sys/poll.h> */
+#define CURL_PULL_SYS_POLL_H
+#endif
+
+
+/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file  */
+/* ws2tcpip.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_WS2TCPIP_H
+#  include <winsock2.h>
+#  include <windows.h>
+#  include <ws2tcpip.h>
+#endif
+
+/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file  */
+/* sys/types.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file  */
+/* sys/socket.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+
+/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file    */
+/* sys/poll.h is required here to properly make type definitions below.   */
+#ifdef CURL_PULL_SYS_POLL_H
+#  include <sys/poll.h>
+#endif
+
+/* Data type definition of curl_socklen_t. */
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+  typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+#endif
+
+/* Data type definition of curl_off_t. */
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+  typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+#endif
+
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * curl_setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
+
+/*
+ * Figure out if we can use the ## preprocessor operator, which is supported
+ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
+ * or  __cplusplus so we need to carefully check for them too.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+  defined(__ILEC400__)
+  /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+  /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
+#  define CURLINC_OFF_T_C_HLPR2(x) x
+#  define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x)
+#  define CURL_OFF_T_C(Val)  CURLINC_OFF_T_C_HLPR1(Val) ## \
+                             CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
+#  define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
+                             CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
+#else
+#  ifdef CURL_ISOCPP
+#    define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
+#  else
+#    define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
+#  endif
+#  define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix)
+#  define CURL_OFF_T_C(Val)  CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
+#  define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
+#endif
+
+#endif /* CURLINC_SYSTEM_H */
diff --git a/libs/curl/include/curl/typecheck-gcc.h b/libs/curl/include/curl/typecheck-gcc.h
index 46f92d728be99e49927d8adeb6af6b6b39a507ec..03c84fc85b2d5b0de873ea02857e556589938b04 100644
--- a/libs/curl/include/curl/typecheck-gcc.h
+++ b/libs/curl/include/curl/typecheck-gcc.h
@@ -1,5 +1,5 @@
-#ifndef __CURL_TYPECHECK_GCC_H
-#define __CURL_TYPECHECK_GCC_H
+#ifndef CURLINC_TYPECHECK_GCC_H
+#define CURLINC_TYPECHECK_GCC_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
  *
  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  * copies of the Software, and permit persons to whom the Software is
@@ -25,10 +25,10 @@
 /* wraps curl_easy_setopt() with typechecking */
 
 /* To add a new kind of warning, add an
- *   if(_curl_is_sometype_option(_curl_opt))
- *     if(!_curl_is_sometype(value))
+ *   if(curlcheck_sometype_option(_curl_opt))
+ *     if(!curlcheck_sometype(value))
  *       _curl_easy_setopt_err_sometype();
- * block and define _curl_is_sometype_option, _curl_is_sometype and
+ * block and define curlcheck_sometype_option, curlcheck_sometype and
  * _curl_easy_setopt_err_sometype below
  *
  * NOTE: We use two nested 'if' statements here instead of the && operator, in
@@ -38,99 +38,115 @@
  * To add an option that uses the same type as an existing option, you'll just
  * need to extend the appropriate _curl_*_option macro
  */
-#define curl_easy_setopt(handle, option, value)                               \
-__extension__ ({                                                              \
-  __typeof__ (option) _curl_opt = option;                                     \
-  if (__builtin_constant_p(_curl_opt)) {                                      \
-    if (_curl_is_long_option(_curl_opt))                                      \
-      if (!_curl_is_long(value))                                              \
-        _curl_easy_setopt_err_long();                                         \
-    if (_curl_is_off_t_option(_curl_opt))                                     \
-      if (!_curl_is_off_t(value))                                             \
-        _curl_easy_setopt_err_curl_off_t();                                   \
-    if (_curl_is_string_option(_curl_opt))                                    \
-      if (!_curl_is_string(value))                                            \
-        _curl_easy_setopt_err_string();                                       \
-    if (_curl_is_write_cb_option(_curl_opt))                                  \
-      if (!_curl_is_write_cb(value))                                          \
-        _curl_easy_setopt_err_write_callback();                               \
-    if ((_curl_opt) == CURLOPT_READFUNCTION)                                  \
-      if (!_curl_is_read_cb(value))                                           \
-        _curl_easy_setopt_err_read_cb();                                      \
-    if ((_curl_opt) == CURLOPT_IOCTLFUNCTION)                                 \
-      if (!_curl_is_ioctl_cb(value))                                          \
-        _curl_easy_setopt_err_ioctl_cb();                                     \
-    if ((_curl_opt) == CURLOPT_SOCKOPTFUNCTION)                               \
-      if (!_curl_is_sockopt_cb(value))                                        \
-        _curl_easy_setopt_err_sockopt_cb();                                   \
-    if ((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION)                            \
-      if (!_curl_is_opensocket_cb(value))                                     \
-        _curl_easy_setopt_err_opensocket_cb();                                \
-    if ((_curl_opt) == CURLOPT_PROGRESSFUNCTION)                              \
-      if (!_curl_is_progress_cb(value))                                       \
-        _curl_easy_setopt_err_progress_cb();                                  \
-    if ((_curl_opt) == CURLOPT_DEBUGFUNCTION)                                 \
-      if (!_curl_is_debug_cb(value))                                          \
-        _curl_easy_setopt_err_debug_cb();                                     \
-    if ((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION)                              \
-      if (!_curl_is_ssl_ctx_cb(value))                                        \
-        _curl_easy_setopt_err_ssl_ctx_cb();                                   \
-    if (_curl_is_conv_cb_option(_curl_opt))                                   \
-      if (!_curl_is_conv_cb(value))                                           \
-        _curl_easy_setopt_err_conv_cb();                                      \
-    if ((_curl_opt) == CURLOPT_SEEKFUNCTION)                                  \
-      if (!_curl_is_seek_cb(value))                                           \
-        _curl_easy_setopt_err_seek_cb();                                      \
-    if (_curl_is_cb_data_option(_curl_opt))                                   \
-      if (!_curl_is_cb_data(value))                                           \
-        _curl_easy_setopt_err_cb_data();                                      \
-    if ((_curl_opt) == CURLOPT_ERRORBUFFER)                                   \
-      if (!_curl_is_error_buffer(value))                                      \
-        _curl_easy_setopt_err_error_buffer();                                 \
-    if ((_curl_opt) == CURLOPT_STDERR)                                        \
-      if (!_curl_is_FILE(value))                                              \
-        _curl_easy_setopt_err_FILE();                                         \
-    if (_curl_is_postfields_option(_curl_opt))                                \
-      if (!_curl_is_postfields(value))                                        \
-        _curl_easy_setopt_err_postfields();                                   \
-    if ((_curl_opt) == CURLOPT_HTTPPOST)                                      \
-      if (!_curl_is_arr((value), struct curl_httppost))                       \
-        _curl_easy_setopt_err_curl_httpost();                                 \
-    if (_curl_is_slist_option(_curl_opt))                                     \
-      if (!_curl_is_arr((value), struct curl_slist))                          \
-        _curl_easy_setopt_err_curl_slist();                                   \
-    if ((_curl_opt) == CURLOPT_SHARE)                                         \
-      if (!_curl_is_ptr((value), CURLSH))                                     \
-        _curl_easy_setopt_err_CURLSH();                                       \
-  }                                                                           \
-  curl_easy_setopt(handle, _curl_opt, value);                                 \
-})
+#define curl_easy_setopt(handle, option, value)                         \
+  __extension__({                                                       \
+      __typeof__(option) _curl_opt = option;                            \
+      if(__builtin_constant_p(_curl_opt)) {                             \
+        if(curlcheck_long_option(_curl_opt))                            \
+          if(!curlcheck_long(value))                                    \
+            _curl_easy_setopt_err_long();                               \
+        if(curlcheck_off_t_option(_curl_opt))                           \
+          if(!curlcheck_off_t(value))                                   \
+            _curl_easy_setopt_err_curl_off_t();                         \
+        if(curlcheck_string_option(_curl_opt))                          \
+          if(!curlcheck_string(value))                                  \
+            _curl_easy_setopt_err_string();                             \
+        if(curlcheck_write_cb_option(_curl_opt))                        \
+          if(!curlcheck_write_cb(value))                                \
+            _curl_easy_setopt_err_write_callback();                     \
+        if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION)              \
+          if(!curlcheck_resolver_start_callback(value))                 \
+            _curl_easy_setopt_err_resolver_start_callback();            \
+        if((_curl_opt) == CURLOPT_READFUNCTION)                         \
+          if(!curlcheck_read_cb(value))                                 \
+            _curl_easy_setopt_err_read_cb();                            \
+        if((_curl_opt) == CURLOPT_IOCTLFUNCTION)                        \
+          if(!curlcheck_ioctl_cb(value))                                \
+            _curl_easy_setopt_err_ioctl_cb();                           \
+        if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION)                      \
+          if(!curlcheck_sockopt_cb(value))                              \
+            _curl_easy_setopt_err_sockopt_cb();                         \
+        if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION)                   \
+          if(!curlcheck_opensocket_cb(value))                           \
+            _curl_easy_setopt_err_opensocket_cb();                      \
+        if((_curl_opt) == CURLOPT_PROGRESSFUNCTION)                     \
+          if(!curlcheck_progress_cb(value))                             \
+            _curl_easy_setopt_err_progress_cb();                        \
+        if((_curl_opt) == CURLOPT_DEBUGFUNCTION)                        \
+          if(!curlcheck_debug_cb(value))                                \
+            _curl_easy_setopt_err_debug_cb();                           \
+        if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION)                     \
+          if(!curlcheck_ssl_ctx_cb(value))                              \
+            _curl_easy_setopt_err_ssl_ctx_cb();                         \
+        if(curlcheck_conv_cb_option(_curl_opt))                         \
+          if(!curlcheck_conv_cb(value))                                 \
+            _curl_easy_setopt_err_conv_cb();                            \
+        if((_curl_opt) == CURLOPT_SEEKFUNCTION)                         \
+          if(!curlcheck_seek_cb(value))                                 \
+            _curl_easy_setopt_err_seek_cb();                            \
+        if(curlcheck_cb_data_option(_curl_opt))                         \
+          if(!curlcheck_cb_data(value))                                 \
+            _curl_easy_setopt_err_cb_data();                            \
+        if((_curl_opt) == CURLOPT_ERRORBUFFER)                          \
+          if(!curlcheck_error_buffer(value))                            \
+            _curl_easy_setopt_err_error_buffer();                       \
+        if((_curl_opt) == CURLOPT_STDERR)                               \
+          if(!curlcheck_FILE(value))                                    \
+            _curl_easy_setopt_err_FILE();                               \
+        if(curlcheck_postfields_option(_curl_opt))                      \
+          if(!curlcheck_postfields(value))                              \
+            _curl_easy_setopt_err_postfields();                         \
+        if((_curl_opt) == CURLOPT_HTTPPOST)                             \
+          if(!curlcheck_arr((value), struct curl_httppost))             \
+            _curl_easy_setopt_err_curl_httpost();                       \
+        if((_curl_opt) == CURLOPT_MIMEPOST)                             \
+          if(!curlcheck_ptr((value), curl_mime))                        \
+            _curl_easy_setopt_err_curl_mimepost();                      \
+        if(curlcheck_slist_option(_curl_opt))                           \
+          if(!curlcheck_arr((value), struct curl_slist))                \
+            _curl_easy_setopt_err_curl_slist();                         \
+        if((_curl_opt) == CURLOPT_SHARE)                                \
+          if(!curlcheck_ptr((value), CURLSH))                           \
+            _curl_easy_setopt_err_CURLSH();                             \
+      }                                                                 \
+      curl_easy_setopt(handle, _curl_opt, value);                       \
+    })
 
 /* wraps curl_easy_getinfo() with typechecking */
-/* FIXME: don't allow const pointers */
-#define curl_easy_getinfo(handle, info, arg)                                  \
-__extension__ ({                                                              \
-  __typeof__ (info) _curl_info = info;                                        \
-  if (__builtin_constant_p(_curl_info)) {                                     \
-    if (_curl_is_string_info(_curl_info))                                     \
-      if (!_curl_is_arr((arg), char *))                                       \
-        _curl_easy_getinfo_err_string();                                      \
-    if (_curl_is_long_info(_curl_info))                                       \
-      if (!_curl_is_arr((arg), long))                                         \
-        _curl_easy_getinfo_err_long();                                        \
-    if (_curl_is_double_info(_curl_info))                                     \
-      if (!_curl_is_arr((arg), double))                                       \
-        _curl_easy_getinfo_err_double();                                      \
-    if (_curl_is_slist_info(_curl_info))                                      \
-      if (!_curl_is_arr((arg), struct curl_slist *))                          \
-        _curl_easy_getinfo_err_curl_slist();                                  \
-  }                                                                           \
-  curl_easy_getinfo(handle, _curl_info, arg);                                 \
-})
-
-/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
- * for now just make sure that the functions are called with three
- * arguments
+#define curl_easy_getinfo(handle, info, arg)                            \
+  __extension__({                                                      \
+      __typeof__(info) _curl_info = info;                               \
+      if(__builtin_constant_p(_curl_info)) {                            \
+        if(curlcheck_string_info(_curl_info))                           \
+          if(!curlcheck_arr((arg), char *))                             \
+            _curl_easy_getinfo_err_string();                            \
+        if(curlcheck_long_info(_curl_info))                             \
+          if(!curlcheck_arr((arg), long))                               \
+            _curl_easy_getinfo_err_long();                              \
+        if(curlcheck_double_info(_curl_info))                           \
+          if(!curlcheck_arr((arg), double))                             \
+            _curl_easy_getinfo_err_double();                            \
+        if(curlcheck_slist_info(_curl_info))                            \
+          if(!curlcheck_arr((arg), struct curl_slist *))                \
+            _curl_easy_getinfo_err_curl_slist();                        \
+        if(curlcheck_tlssessioninfo_info(_curl_info))                   \
+          if(!curlcheck_arr((arg), struct curl_tlssessioninfo *))       \
+            _curl_easy_getinfo_err_curl_tlssesssioninfo();              \
+        if(curlcheck_certinfo_info(_curl_info))                         \
+          if(!curlcheck_arr((arg), struct curl_certinfo *))             \
+            _curl_easy_getinfo_err_curl_certinfo();                     \
+        if(curlcheck_socket_info(_curl_info))                           \
+          if(!curlcheck_arr((arg), curl_socket_t))                      \
+            _curl_easy_getinfo_err_curl_socket();                       \
+        if(curlcheck_off_t_info(_curl_info))                            \
+          if(!curlcheck_arr((arg), curl_off_t))                         \
+            _curl_easy_getinfo_err_curl_off_t();                        \
+      }                                                                 \
+      curl_easy_getinfo(handle, _curl_info, arg);                       \
+    })
+
+/*
+ * For now, just make sure that the functions are called with three arguments
  */
 #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
 #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
@@ -140,61 +156,84 @@ __extension__ ({                                                              \
  * functions */
 
 /* To define a new warning, use _CURL_WARNING(identifier, "message") */
-#define _CURL_WARNING(id, message)                                            \
-  static void __attribute__((warning(message))) __attribute__((unused))       \
-  __attribute__((noinline)) id(void) { __asm__(""); }
+#define CURLWARNING(id, message)                                        \
+  static void __attribute__((__warning__(message)))                     \
+  __attribute__((__unused__)) __attribute__((__noinline__))             \
+  id(void) { __asm__(""); }
 
-_CURL_WARNING(_curl_easy_setopt_err_long,
+CURLWARNING(_curl_easy_setopt_err_long,
   "curl_easy_setopt expects a long argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_curl_off_t,
+CURLWARNING(_curl_easy_setopt_err_curl_off_t,
   "curl_easy_setopt expects a curl_off_t argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_string,
-  "curl_easy_setopt expects a string (char* or char[]) argument for this option"
+CURLWARNING(_curl_easy_setopt_err_string,
+              "curl_easy_setopt expects a "
+              "string ('char *' or char[]) argument for this option"
   )
-_CURL_WARNING(_curl_easy_setopt_err_write_callback,
+CURLWARNING(_curl_easy_setopt_err_write_callback,
   "curl_easy_setopt expects a curl_write_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_read_cb,
+CURLWARNING(_curl_easy_setopt_err_resolver_start_callback,
+              "curl_easy_setopt expects a "
+              "curl_resolver_start_callback argument for this option"
+  )
+CURLWARNING(_curl_easy_setopt_err_read_cb,
   "curl_easy_setopt expects a curl_read_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
+CURLWARNING(_curl_easy_setopt_err_ioctl_cb,
   "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
+CURLWARNING(_curl_easy_setopt_err_sockopt_cb,
   "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb,
-  "curl_easy_setopt expects a curl_opensocket_callback argument for this option"
+CURLWARNING(_curl_easy_setopt_err_opensocket_cb,
+              "curl_easy_setopt expects a "
+              "curl_opensocket_callback argument for this option"
   )
-_CURL_WARNING(_curl_easy_setopt_err_progress_cb,
+CURLWARNING(_curl_easy_setopt_err_progress_cb,
   "curl_easy_setopt expects a curl_progress_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_debug_cb,
+CURLWARNING(_curl_easy_setopt_err_debug_cb,
   "curl_easy_setopt expects a curl_debug_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb,
+CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb,
   "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_conv_cb,
+CURLWARNING(_curl_easy_setopt_err_conv_cb,
   "curl_easy_setopt expects a curl_conv_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_seek_cb,
+CURLWARNING(_curl_easy_setopt_err_seek_cb,
   "curl_easy_setopt expects a curl_seek_callback argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_cb_data,
-  "curl_easy_setopt expects a private data pointer as argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_error_buffer,
-  "curl_easy_setopt expects a char buffer of CURL_ERROR_SIZE as argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_FILE,
-  "curl_easy_setopt expects a FILE* argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_postfields,
-  "curl_easy_setopt expects a void* or char* argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
-  "curl_easy_setopt expects a struct curl_httppost* argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_curl_slist,
-  "curl_easy_setopt expects a struct curl_slist* argument for this option")
-_CURL_WARNING(_curl_easy_setopt_err_CURLSH,
+CURLWARNING(_curl_easy_setopt_err_cb_data,
+              "curl_easy_setopt expects a "
+              "private data pointer as argument for this option")
+CURLWARNING(_curl_easy_setopt_err_error_buffer,
+              "curl_easy_setopt expects a "
+              "char buffer of CURL_ERROR_SIZE as argument for this option")
+CURLWARNING(_curl_easy_setopt_err_FILE,
+  "curl_easy_setopt expects a 'FILE *' argument for this option")
+CURLWARNING(_curl_easy_setopt_err_postfields,
+  "curl_easy_setopt expects a 'void *' or 'char *' argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_httpost,
+              "curl_easy_setopt expects a 'struct curl_httppost *' "
+              "argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_mimepost,
+              "curl_easy_setopt expects a 'curl_mime *' "
+              "argument for this option")
+CURLWARNING(_curl_easy_setopt_err_curl_slist,
+  "curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
+CURLWARNING(_curl_easy_setopt_err_CURLSH,
   "curl_easy_setopt expects a CURLSH* argument for this option")
 
-_CURL_WARNING(_curl_easy_getinfo_err_string,
-  "curl_easy_getinfo expects a pointer to char * for this info")
-_CURL_WARNING(_curl_easy_getinfo_err_long,
+CURLWARNING(_curl_easy_getinfo_err_string,
+  "curl_easy_getinfo expects a pointer to 'char *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_long,
   "curl_easy_getinfo expects a pointer to long for this info")
-_CURL_WARNING(_curl_easy_getinfo_err_double,
+CURLWARNING(_curl_easy_getinfo_err_double,
   "curl_easy_getinfo expects a pointer to double for this info")
-_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
-  "curl_easy_getinfo expects a pointer to struct curl_slist * for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_slist,
+  "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo,
+              "curl_easy_getinfo expects a pointer to "
+              "'struct curl_tlssessioninfo *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_certinfo,
+              "curl_easy_getinfo expects a pointer to "
+              "'struct curl_certinfo *' for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_socket,
+  "curl_easy_getinfo expects a pointer to curl_socket_t for this info")
+CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
+  "curl_easy_getinfo expects a pointer to curl_off_t for this info")
 
 /* groups of curl_easy_setops options that take the same type of argument */
 
@@ -205,131 +244,188 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
  */
 
 /* evaluates to true if option takes a long argument */
-#define _curl_is_long_option(option)                                          \
+#define curlcheck_long_option(option)                   \
   (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
 
-#define _curl_is_off_t_option(option)                                         \
+#define curlcheck_off_t_option(option)          \
   ((option) > CURLOPTTYPE_OFF_T)
 
 /* evaluates to true if option takes a char* argument */
-#define _curl_is_string_option(option)                                        \
-  ((option) == CURLOPT_URL ||                                                 \
-   (option) == CURLOPT_PROXY ||                                               \
-   (option) == CURLOPT_INTERFACE ||                                           \
-   (option) == CURLOPT_NETRC_FILE ||                                          \
-   (option) == CURLOPT_USERPWD ||                                             \
-   (option) == CURLOPT_USERNAME ||                                            \
-   (option) == CURLOPT_PASSWORD ||                                            \
-   (option) == CURLOPT_PROXYUSERPWD ||                                        \
-   (option) == CURLOPT_PROXYUSERNAME ||                                       \
-   (option) == CURLOPT_PROXYPASSWORD ||                                       \
-   (option) == CURLOPT_NOPROXY ||                                             \
+#define curlcheck_string_option(option)                                       \
+  ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET ||                                \
    (option) == CURLOPT_ACCEPT_ENCODING ||                                     \
-   (option) == CURLOPT_REFERER ||                                             \
-   (option) == CURLOPT_USERAGENT ||                                           \
+   (option) == CURLOPT_ALTSVC ||                                              \
+   (option) == CURLOPT_CAINFO ||                                              \
+   (option) == CURLOPT_CAPATH ||                                              \
    (option) == CURLOPT_COOKIE ||                                              \
    (option) == CURLOPT_COOKIEFILE ||                                          \
    (option) == CURLOPT_COOKIEJAR ||                                           \
    (option) == CURLOPT_COOKIELIST ||                                          \
+   (option) == CURLOPT_CRLFILE ||                                             \
+   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
+   (option) == CURLOPT_DEFAULT_PROTOCOL ||                                    \
+   (option) == CURLOPT_DNS_INTERFACE ||                                       \
+   (option) == CURLOPT_DNS_LOCAL_IP4 ||                                       \
+   (option) == CURLOPT_DNS_LOCAL_IP6 ||                                       \
+   (option) == CURLOPT_DNS_SERVERS ||                                         \
+   (option) == CURLOPT_DOH_URL ||                                             \
+   (option) == CURLOPT_EGDSOCKET ||                                           \
    (option) == CURLOPT_FTPPORT ||                                             \
-   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
    (option) == CURLOPT_FTP_ACCOUNT ||                                         \
-   (option) == CURLOPT_RANGE ||                                               \
-   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
-   (option) == CURLOPT_SSLCERT ||                                             \
-   (option) == CURLOPT_SSLCERTTYPE ||                                         \
-   (option) == CURLOPT_SSLKEY ||                                              \
-   (option) == CURLOPT_SSLKEYTYPE ||                                          \
+   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
+   (option) == CURLOPT_INTERFACE ||                                           \
+   (option) == CURLOPT_ISSUERCERT ||                                          \
    (option) == CURLOPT_KEYPASSWD ||                                           \
-   (option) == CURLOPT_SSLENGINE ||                                           \
-   (option) == CURLOPT_CAINFO ||                                              \
-   (option) == CURLOPT_CAPATH ||                                              \
-   (option) == CURLOPT_RANDOM_FILE ||                                         \
-   (option) == CURLOPT_EGDSOCKET ||                                           \
-   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
    (option) == CURLOPT_KRBLEVEL ||                                            \
-   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
-   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
-   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
-   (option) == CURLOPT_CRLFILE ||                                             \
-   (option) == CURLOPT_ISSUERCERT ||                                          \
-   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
-   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
+   (option) == CURLOPT_LOGIN_OPTIONS ||                                       \
+   (option) == CURLOPT_MAIL_AUTH ||                                           \
    (option) == CURLOPT_MAIL_FROM ||                                           \
+   (option) == CURLOPT_NETRC_FILE ||                                          \
+   (option) == CURLOPT_NOPROXY ||                                             \
+   (option) == CURLOPT_PASSWORD ||                                            \
+   (option) == CURLOPT_PINNEDPUBLICKEY ||                                     \
+   (option) == CURLOPT_PRE_PROXY ||                                           \
+   (option) == CURLOPT_PROXY ||                                               \
+   (option) == CURLOPT_PROXYPASSWORD ||                                       \
+   (option) == CURLOPT_PROXYUSERNAME ||                                       \
+   (option) == CURLOPT_PROXYUSERPWD ||                                        \
+   (option) == CURLOPT_PROXY_CAINFO ||                                        \
+   (option) == CURLOPT_PROXY_CAPATH ||                                        \
+   (option) == CURLOPT_PROXY_CRLFILE ||                                       \
+   (option) == CURLOPT_PROXY_KEYPASSWD ||                                     \
+   (option) == CURLOPT_PROXY_PINNEDPUBLICKEY ||                               \
+   (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
+   (option) == CURLOPT_PROXY_SSLCERT ||                                       \
+   (option) == CURLOPT_PROXY_SSLCERTTYPE ||                                   \
+   (option) == CURLOPT_PROXY_SSLKEY ||                                        \
+   (option) == CURLOPT_PROXY_SSLKEYTYPE ||                                    \
+   (option) == CURLOPT_PROXY_SSL_CIPHER_LIST ||                               \
+   (option) == CURLOPT_PROXY_TLS13_CIPHERS ||                                 \
+   (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD ||                              \
+   (option) == CURLOPT_PROXY_TLSAUTH_TYPE ||                                  \
+   (option) == CURLOPT_PROXY_TLSAUTH_USERNAME ||                              \
+   (option) == CURLOPT_RANDOM_FILE ||                                         \
+   (option) == CURLOPT_RANGE ||                                               \
+   (option) == CURLOPT_REFERER ||                                             \
+   (option) == CURLOPT_REQUEST_TARGET ||                                      \
    (option) == CURLOPT_RTSP_SESSION_ID ||                                     \
    (option) == CURLOPT_RTSP_STREAM_URI ||                                     \
    (option) == CURLOPT_RTSP_TRANSPORT ||                                      \
+   (option) == CURLOPT_SASL_AUTHZID ||                                        \
+   (option) == CURLOPT_SERVICE_NAME ||                                        \
+   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
+   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
+   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
+   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
+   (option) == CURLOPT_SSLCERT ||                                             \
+   (option) == CURLOPT_SSLCERTTYPE ||                                         \
+   (option) == CURLOPT_SSLENGINE ||                                           \
+   (option) == CURLOPT_SSLKEY ||                                              \
+   (option) == CURLOPT_SSLKEYTYPE ||                                          \
+   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
+   (option) == CURLOPT_TLS13_CIPHERS ||                                       \
+   (option) == CURLOPT_TLSAUTH_PASSWORD ||                                    \
+   (option) == CURLOPT_TLSAUTH_TYPE ||                                        \
+   (option) == CURLOPT_TLSAUTH_USERNAME ||                                    \
+   (option) == CURLOPT_UNIX_SOCKET_PATH ||                                    \
+   (option) == CURLOPT_URL ||                                                 \
+   (option) == CURLOPT_USERAGENT ||                                           \
+   (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_USERPWD ||                                             \
+   (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
    0)
 
 /* evaluates to true if option takes a curl_write_callback argument */
-#define _curl_is_write_cb_option(option)                                      \
-  ((option) == CURLOPT_HEADERFUNCTION ||                                      \
+#define curlcheck_write_cb_option(option)                               \
+  ((option) == CURLOPT_HEADERFUNCTION ||                                \
    (option) == CURLOPT_WRITEFUNCTION)
 
 /* evaluates to true if option takes a curl_conv_callback argument */
-#define _curl_is_conv_cb_option(option)                                       \
-  ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION ||                            \
-   (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION ||                          \
+#define curlcheck_conv_cb_option(option)                                \
+  ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION ||                      \
+   (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION ||                    \
    (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
 
 /* evaluates to true if option takes a data argument to pass to a callback */
-#define _curl_is_cb_data_option(option)                                       \
-  ((option) == CURLOPT_WRITEDATA ||                                           \
-   (option) == CURLOPT_READDATA ||                                            \
+#define curlcheck_cb_data_option(option)                                      \
+  ((option) == CURLOPT_CHUNK_DATA ||                                          \
+   (option) == CURLOPT_CLOSESOCKETDATA ||                                     \
+   (option) == CURLOPT_DEBUGDATA ||                                           \
+   (option) == CURLOPT_FNMATCH_DATA ||                                        \
+   (option) == CURLOPT_HEADERDATA ||                                          \
+   (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_IOCTLDATA ||                                           \
-   (option) == CURLOPT_SOCKOPTDATA ||                                         \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
+   (option) == CURLOPT_PRIVATE ||                                             \
    (option) == CURLOPT_PROGRESSDATA ||                                        \
-   (option) == CURLOPT_WRITEHEADER ||                                         \
-   (option) == CURLOPT_DEBUGDATA ||                                           \
-   (option) == CURLOPT_SSL_CTX_DATA ||                                        \
+   (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \
-   (option) == CURLOPT_PRIVATE ||                                             \
+   (option) == CURLOPT_SOCKOPTDATA ||                                         \
    (option) == CURLOPT_SSH_KEYDATA ||                                         \
-   (option) == CURLOPT_INTERLEAVEDATA ||                                      \
-   (option) == CURLOPT_CHUNK_DATA ||                                          \
-   (option) == CURLOPT_FNMATCH_DATA ||                                        \
+   (option) == CURLOPT_SSL_CTX_DATA ||                                        \
+   (option) == CURLOPT_WRITEDATA ||                                           \
+   (option) == CURLOPT_RESOLVER_START_DATA ||                                 \
+   (option) == CURLOPT_TRAILERDATA ||                                         \
    0)
 
 /* evaluates to true if option takes a POST data argument (void* or char*) */
-#define _curl_is_postfields_option(option)                                    \
+#define curlcheck_postfields_option(option)                                   \
   ((option) == CURLOPT_POSTFIELDS ||                                          \
    (option) == CURLOPT_COPYPOSTFIELDS ||                                      \
    0)
 
 /* evaluates to true if option takes a struct curl_slist * argument */
-#define _curl_is_slist_option(option)                                         \
-  ((option) == CURLOPT_HTTPHEADER ||                                          \
-   (option) == CURLOPT_HTTP200ALIASES ||                                      \
-   (option) == CURLOPT_QUOTE ||                                               \
+#define curlcheck_slist_option(option)                                        \
+  ((option) == CURLOPT_HTTP200ALIASES ||                                      \
+   (option) == CURLOPT_HTTPHEADER ||                                          \
+   (option) == CURLOPT_MAIL_RCPT ||                                           \
    (option) == CURLOPT_POSTQUOTE ||                                           \
    (option) == CURLOPT_PREQUOTE ||                                            \
+   (option) == CURLOPT_PROXYHEADER ||                                         \
+   (option) == CURLOPT_QUOTE ||                                               \
+   (option) == CURLOPT_RESOLVE ||                                             \
    (option) == CURLOPT_TELNETOPTIONS ||                                       \
-   (option) == CURLOPT_MAIL_RCPT ||                                           \
+   (option) == CURLOPT_CONNECT_TO ||                                          \
    0)
 
 /* groups of curl_easy_getinfo infos that take the same type of argument */
 
 /* evaluates to true if info expects a pointer to char * argument */
-#define _curl_is_string_info(info)                                            \
+#define curlcheck_string_info(info)                     \
   (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
 
 /* evaluates to true if info expects a pointer to long argument */
-#define _curl_is_long_info(info)                                              \
+#define curlcheck_long_info(info)                       \
   (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
 
 /* evaluates to true if info expects a pointer to double argument */
-#define _curl_is_double_info(info)                                            \
+#define curlcheck_double_info(info)                     \
   (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
 
 /* true if info expects a pointer to struct curl_slist * argument */
-#define _curl_is_slist_info(info)                                             \
-  (CURLINFO_SLIST < (info))
+#define curlcheck_slist_info(info)                                      \
+  (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST))
+
+/* true if info expects a pointer to struct curl_tlssessioninfo * argument */
+#define curlcheck_tlssessioninfo_info(info)                              \
+  (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION))
+
+/* true if info expects a pointer to struct curl_certinfo * argument */
+#define curlcheck_certinfo_info(info) ((info) == CURLINFO_CERTINFO)
+
+/* true if info expects a pointer to struct curl_socket_t argument */
+#define curlcheck_socket_info(info)                     \
+  (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T)
+
+/* true if info expects a pointer to curl_off_t argument */
+#define curlcheck_off_t_info(info)              \
+  (CURLINFO_OFF_T < (info))
 
 
 /* typecheck helpers -- check whether given expression has requested type*/
 
-/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
+/* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros,
  * otherwise define a new macro. Search for __builtin_types_compatible_p
  * in the GCC manual.
  * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
@@ -338,36 +434,36 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
  * == or whatsoever.
  */
 
-/* XXX: should evaluate to true iff expr is a pointer */
-#define _curl_is_any_ptr(expr)                                                \
-  (sizeof(expr) == sizeof(void*))
+/* XXX: should evaluate to true if expr is a pointer */
+#define curlcheck_any_ptr(expr)                 \
+  (sizeof(expr) == sizeof(void *))
 
 /* evaluates to true if expr is NULL */
 /* XXX: must not evaluate expr, so this check is not accurate */
-#define _curl_is_NULL(expr)                                                   \
+#define curlcheck_NULL(expr)                                            \
   (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
 
 /* evaluates to true if expr is type*, const type* or NULL */
-#define _curl_is_ptr(expr, type)                                              \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), type *) ||                  \
+#define curlcheck_ptr(expr, type)                                       \
+  (curlcheck_NULL(expr) ||                                              \
+   __builtin_types_compatible_p(__typeof__(expr), type *) ||            \
    __builtin_types_compatible_p(__typeof__(expr), const type *))
 
 /* evaluates to true if expr is one of type[], type*, NULL or const type* */
-#define _curl_is_arr(expr, type)                                              \
-  (_curl_is_ptr((expr), type) ||                                              \
+#define curlcheck_arr(expr, type)                                       \
+  (curlcheck_ptr((expr), type) ||                                       \
    __builtin_types_compatible_p(__typeof__(expr), type []))
 
 /* evaluates to true if expr is a string */
-#define _curl_is_string(expr)                                                 \
-  (_curl_is_arr((expr), char) ||                                              \
-   _curl_is_arr((expr), signed char) ||                                       \
-   _curl_is_arr((expr), unsigned char))
+#define curlcheck_string(expr)                                          \
+  (curlcheck_arr((expr), char) ||                                       \
+   curlcheck_arr((expr), signed char) ||                                \
+   curlcheck_arr((expr), unsigned char))
 
 /* evaluates to true if expr is a long (no matter the signedness)
  * XXX: for now, int is also accepted (and therefore short and char, which
  * are promoted to int when passed to a variadic function) */
-#define _curl_is_long(expr)                                                   \
+#define curlcheck_long(expr)                                                  \
   (__builtin_types_compatible_p(__typeof__(expr), long) ||                    \
    __builtin_types_compatible_p(__typeof__(expr), signed long) ||             \
    __builtin_types_compatible_p(__typeof__(expr), unsigned long) ||           \
@@ -382,175 +478,194 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
    __builtin_types_compatible_p(__typeof__(expr), unsigned char))
 
 /* evaluates to true if expr is of type curl_off_t */
-#define _curl_is_off_t(expr)                                                  \
+#define curlcheck_off_t(expr)                                   \
   (__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
 
 /* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
 /* XXX: also check size of an char[] array? */
-#define _curl_is_error_buffer(expr)                                           \
-  (__builtin_types_compatible_p(__typeof__(expr), char *) ||                  \
+#define curlcheck_error_buffer(expr)                                    \
+  (curlcheck_NULL(expr) ||                                              \
+   __builtin_types_compatible_p(__typeof__(expr), char *) ||            \
    __builtin_types_compatible_p(__typeof__(expr), char[]))
 
 /* evaluates to true if expr is of type (const) void* or (const) FILE* */
 #if 0
-#define _curl_is_cb_data(expr)                                                \
-  (_curl_is_ptr((expr), void) ||                                              \
-   _curl_is_ptr((expr), FILE))
+#define curlcheck_cb_data(expr)                                         \
+  (curlcheck_ptr((expr), void) ||                                       \
+   curlcheck_ptr((expr), FILE))
 #else /* be less strict */
-#define _curl_is_cb_data(expr)                                                \
-  _curl_is_any_ptr(expr)
+#define curlcheck_cb_data(expr)                 \
+  curlcheck_any_ptr(expr)
 #endif
 
 /* evaluates to true if expr is of type FILE* */
-#define _curl_is_FILE(expr)                                                   \
-  (__builtin_types_compatible_p(__typeof__(expr), FILE *))
+#define curlcheck_FILE(expr)                                            \
+  (curlcheck_NULL(expr) ||                                              \
+   (__builtin_types_compatible_p(__typeof__(expr), FILE *)))
 
 /* evaluates to true if expr can be passed as POST data (void* or char*) */
-#define _curl_is_postfields(expr)                                             \
-  (_curl_is_ptr((expr), void) ||                                              \
-   _curl_is_arr((expr), char))
+#define curlcheck_postfields(expr)                                      \
+  (curlcheck_ptr((expr), void) ||                                       \
+   curlcheck_arr((expr), char) ||                                       \
+   curlcheck_arr((expr), unsigned char))
 
-/* FIXME: the whole callback checking is messy...
- * The idea is to tolerate char vs. void and const vs. not const
- * pointers in arguments at least
- */
 /* helper: __builtin_types_compatible_p distinguishes between functions and
  * function pointers, hide it */
-#define _curl_callback_compatible(func, type)                                 \
-  (__builtin_types_compatible_p(__typeof__(func), type) ||                    \
-   __builtin_types_compatible_p(__typeof__(func), type*))
+#define curlcheck_cb_compatible(func, type)                             \
+  (__builtin_types_compatible_p(__typeof__(func), type) ||              \
+   __builtin_types_compatible_p(__typeof__(func) *, type))
+
+/* evaluates to true if expr is of type curl_resolver_start_callback */
+#define curlcheck_resolver_start_callback(expr)       \
+  (curlcheck_NULL(expr) || \
+   curlcheck_cb_compatible((expr), curl_resolver_start_callback))
 
 /* evaluates to true if expr is of type curl_read_callback or "similar" */
-#define _curl_is_read_cb(expr)                                          \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) ||       \
-   __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) ||      \
-   _curl_callback_compatible((expr), _curl_read_callback1) ||                 \
-   _curl_callback_compatible((expr), _curl_read_callback2) ||                 \
-   _curl_callback_compatible((expr), _curl_read_callback3) ||                 \
-   _curl_callback_compatible((expr), _curl_read_callback4) ||                 \
-   _curl_callback_compatible((expr), _curl_read_callback5) ||                 \
-   _curl_callback_compatible((expr), _curl_read_callback6))
-typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*);
-typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*);
-typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*);
-typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*);
-typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*);
-typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*);
+#define curlcheck_read_cb(expr)                                         \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), __typeof__(fread) *) ||              \
+   curlcheck_cb_compatible((expr), curl_read_callback) ||               \
+   curlcheck_cb_compatible((expr), _curl_read_callback1) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback2) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback3) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback4) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback5) ||             \
+   curlcheck_cb_compatible((expr), _curl_read_callback6))
+typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *);
+typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *);
+typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *);
+typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *);
+typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *);
+typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *);
 
 /* evaluates to true if expr is of type curl_write_callback or "similar" */
-#define _curl_is_write_cb(expr)                                               \
-  (_curl_is_read_cb(expr) ||                                            \
-   __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) ||      \
-   __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) ||     \
-   _curl_callback_compatible((expr), _curl_write_callback1) ||                \
-   _curl_callback_compatible((expr), _curl_write_callback2) ||                \
-   _curl_callback_compatible((expr), _curl_write_callback3) ||                \
-   _curl_callback_compatible((expr), _curl_write_callback4) ||                \
-   _curl_callback_compatible((expr), _curl_write_callback5) ||                \
-   _curl_callback_compatible((expr), _curl_write_callback6))
-typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*);
-typedef size_t (_curl_write_callback2)(const char *, size_t, size_t,
-                                       const void*);
-typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*);
-typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*);
-typedef size_t (_curl_write_callback5)(const void *, size_t, size_t,
-                                       const void*);
-typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*);
+#define curlcheck_write_cb(expr)                                        \
+  (curlcheck_read_cb(expr) ||                                           \
+   curlcheck_cb_compatible((expr), __typeof__(fwrite) *) ||             \
+   curlcheck_cb_compatible((expr), curl_write_callback) ||              \
+   curlcheck_cb_compatible((expr), _curl_write_callback1) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback2) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback3) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback4) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback5) ||            \
+   curlcheck_cb_compatible((expr), _curl_write_callback6))
+typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *);
+typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t,
+                                       const void *);
+typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *);
+typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *);
+typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t,
+                                       const void *);
+typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *);
 
 /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
-#define _curl_is_ioctl_cb(expr)                                         \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) ||     \
-   _curl_callback_compatible((expr), _curl_ioctl_callback1) ||                \
-   _curl_callback_compatible((expr), _curl_ioctl_callback2) ||                \
-   _curl_callback_compatible((expr), _curl_ioctl_callback3) ||                \
-   _curl_callback_compatible((expr), _curl_ioctl_callback4))
-typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*);
-typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*);
-typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*);
-typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*);
+#define curlcheck_ioctl_cb(expr)                                        \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_ioctl_callback) ||              \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback1) ||            \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback2) ||            \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback3) ||            \
+   curlcheck_cb_compatible((expr), _curl_ioctl_callback4))
+typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *);
+typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *);
+typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *);
+typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *);
 
 /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
-#define _curl_is_sockopt_cb(expr)                                       \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) ||   \
-   _curl_callback_compatible((expr), _curl_sockopt_callback1) ||              \
-   _curl_callback_compatible((expr), _curl_sockopt_callback2))
-typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
-typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t,
+#define curlcheck_sockopt_cb(expr)                                      \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_sockopt_callback) ||            \
+   curlcheck_cb_compatible((expr), _curl_sockopt_callback1) ||          \
+   curlcheck_cb_compatible((expr), _curl_sockopt_callback2))
+typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
+typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t,
                                       curlsocktype);
 
-/* evaluates to true if expr is of type curl_opensocket_callback or "similar" */
-#define _curl_is_opensocket_cb(expr)                                    \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\
-   _curl_callback_compatible((expr), _curl_opensocket_callback1) ||           \
-   _curl_callback_compatible((expr), _curl_opensocket_callback2) ||           \
-   _curl_callback_compatible((expr), _curl_opensocket_callback3) ||           \
-   _curl_callback_compatible((expr), _curl_opensocket_callback4))
-typedef curl_socket_t (_curl_opensocket_callback1)
+/* evaluates to true if expr is of type curl_opensocket_callback or
+   "similar" */
+#define curlcheck_opensocket_cb(expr)                                   \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_opensocket_callback) ||         \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback1) ||       \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback2) ||       \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback3) ||       \
+   curlcheck_cb_compatible((expr), _curl_opensocket_callback4))
+typedef curl_socket_t (*_curl_opensocket_callback1)
   (void *, curlsocktype, struct curl_sockaddr *);
-typedef curl_socket_t (_curl_opensocket_callback2)
+typedef curl_socket_t (*_curl_opensocket_callback2)
   (void *, curlsocktype, const struct curl_sockaddr *);
-typedef curl_socket_t (_curl_opensocket_callback3)
+typedef curl_socket_t (*_curl_opensocket_callback3)
   (const void *, curlsocktype, struct curl_sockaddr *);
-typedef curl_socket_t (_curl_opensocket_callback4)
+typedef curl_socket_t (*_curl_opensocket_callback4)
   (const void *, curlsocktype, const struct curl_sockaddr *);
 
 /* evaluates to true if expr is of type curl_progress_callback or "similar" */
-#define _curl_is_progress_cb(expr)                                      \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) ||  \
-   _curl_callback_compatible((expr), _curl_progress_callback1) ||             \
-   _curl_callback_compatible((expr), _curl_progress_callback2))
-typedef int (_curl_progress_callback1)(void *,
+#define curlcheck_progress_cb(expr)                                     \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_progress_callback) ||           \
+   curlcheck_cb_compatible((expr), _curl_progress_callback1) ||         \
+   curlcheck_cb_compatible((expr), _curl_progress_callback2))
+typedef int (*_curl_progress_callback1)(void *,
     double, double, double, double);
-typedef int (_curl_progress_callback2)(const void *,
+typedef int (*_curl_progress_callback2)(const void *,
     double, double, double, double);
 
 /* evaluates to true if expr is of type curl_debug_callback or "similar" */
-#define _curl_is_debug_cb(expr)                                         \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) ||     \
-   _curl_callback_compatible((expr), _curl_debug_callback1) ||                \
-   _curl_callback_compatible((expr), _curl_debug_callback2) ||                \
-   _curl_callback_compatible((expr), _curl_debug_callback3) ||                \
-   _curl_callback_compatible((expr), _curl_debug_callback4))
-typedef int (_curl_debug_callback1) (CURL *,
+#define curlcheck_debug_cb(expr)                                        \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_debug_callback) ||              \
+   curlcheck_cb_compatible((expr), _curl_debug_callback1) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback2) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback3) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback4) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback5) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback6) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback7) ||            \
+   curlcheck_cb_compatible((expr), _curl_debug_callback8))
+typedef int (*_curl_debug_callback1) (CURL *,
     curl_infotype, char *, size_t, void *);
-typedef int (_curl_debug_callback2) (CURL *,
+typedef int (*_curl_debug_callback2) (CURL *,
     curl_infotype, char *, size_t, const void *);
-typedef int (_curl_debug_callback3) (CURL *,
+typedef int (*_curl_debug_callback3) (CURL *,
     curl_infotype, const char *, size_t, void *);
-typedef int (_curl_debug_callback4) (CURL *,
+typedef int (*_curl_debug_callback4) (CURL *,
     curl_infotype, const char *, size_t, const void *);
+typedef int (*_curl_debug_callback5) (CURL *,
+    curl_infotype, unsigned char *, size_t, void *);
+typedef int (*_curl_debug_callback6) (CURL *,
+    curl_infotype, unsigned char *, size_t, const void *);
+typedef int (*_curl_debug_callback7) (CURL *,
+    curl_infotype, const unsigned char *, size_t, void *);
+typedef int (*_curl_debug_callback8) (CURL *,
+    curl_infotype, const unsigned char *, size_t, const void *);
 
 /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
 /* this is getting even messier... */
-#define _curl_is_ssl_ctx_cb(expr)                                       \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) ||   \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) ||              \
-   _curl_callback_compatible((expr), _curl_ssl_ctx_callback8))
-typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *);
-typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
-typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
-typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *);
+#define curlcheck_ssl_ctx_cb(expr)                                      \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) ||            \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) ||          \
+   curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8))
+typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
+                                            const void *);
 #ifdef HEADER_SSL_H
 /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
  * this will of course break if we're included before OpenSSL headers...
  */
-typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
-typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
-typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
-typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX,
+                                           const void *);
 #else
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
@@ -559,26 +674,26 @@ typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
 #endif
 
 /* evaluates to true if expr is of type curl_conv_callback or "similar" */
-#define _curl_is_conv_cb(expr)                                          \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) ||      \
-   _curl_callback_compatible((expr), _curl_conv_callback1) ||                 \
-   _curl_callback_compatible((expr), _curl_conv_callback2) ||                 \
-   _curl_callback_compatible((expr), _curl_conv_callback3) ||                 \
-   _curl_callback_compatible((expr), _curl_conv_callback4))
+#define curlcheck_conv_cb(expr)                                         \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_conv_callback) ||               \
+   curlcheck_cb_compatible((expr), _curl_conv_callback1) ||             \
+   curlcheck_cb_compatible((expr), _curl_conv_callback2) ||             \
+   curlcheck_cb_compatible((expr), _curl_conv_callback3) ||             \
+   curlcheck_cb_compatible((expr), _curl_conv_callback4))
 typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
 typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
 typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
 typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
 
 /* evaluates to true if expr is of type curl_seek_callback or "similar" */
-#define _curl_is_seek_cb(expr)                                          \
-  (_curl_is_NULL(expr) ||                                                     \
-   __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) ||      \
-   _curl_callback_compatible((expr), _curl_seek_callback1) ||                 \
-   _curl_callback_compatible((expr), _curl_seek_callback2))
+#define curlcheck_seek_cb(expr)                                         \
+  (curlcheck_NULL(expr) ||                                              \
+   curlcheck_cb_compatible((expr), curl_seek_callback) ||               \
+   curlcheck_cb_compatible((expr), _curl_seek_callback1) ||             \
+   curlcheck_cb_compatible((expr), _curl_seek_callback2))
 typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
 typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
 
 
-#endif /* __CURL_TYPECHECK_GCC_H */
+#endif /* CURLINC_TYPECHECK_GCC_H */
diff --git a/libs/curl/include/curl/urlapi.h b/libs/curl/include/curl/urlapi.h
new file mode 100644
index 0000000000000000000000000000000000000000..f2d06770dc88fdd1b6c9a4d8b7dbcce2a6bd2c93
--- /dev/null
+++ b/libs/curl/include/curl/urlapi.h
@@ -0,0 +1,125 @@
+#ifndef CURLINC_URLAPI_H
+#define CURLINC_URLAPI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2018 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* the error codes for the URL API */
+typedef enum {
+  CURLUE_OK,
+  CURLUE_BAD_HANDLE,          /* 1 */
+  CURLUE_BAD_PARTPOINTER,     /* 2 */
+  CURLUE_MALFORMED_INPUT,     /* 3 */
+  CURLUE_BAD_PORT_NUMBER,     /* 4 */
+  CURLUE_UNSUPPORTED_SCHEME,  /* 5 */
+  CURLUE_URLDECODE,           /* 6 */
+  CURLUE_OUT_OF_MEMORY,       /* 7 */
+  CURLUE_USER_NOT_ALLOWED,    /* 8 */
+  CURLUE_UNKNOWN_PART,        /* 9 */
+  CURLUE_NO_SCHEME,           /* 10 */
+  CURLUE_NO_USER,             /* 11 */
+  CURLUE_NO_PASSWORD,         /* 12 */
+  CURLUE_NO_OPTIONS,          /* 13 */
+  CURLUE_NO_HOST,             /* 14 */
+  CURLUE_NO_PORT,             /* 15 */
+  CURLUE_NO_QUERY,            /* 16 */
+  CURLUE_NO_FRAGMENT          /* 17 */
+} CURLUcode;
+
+typedef enum {
+  CURLUPART_URL,
+  CURLUPART_SCHEME,
+  CURLUPART_USER,
+  CURLUPART_PASSWORD,
+  CURLUPART_OPTIONS,
+  CURLUPART_HOST,
+  CURLUPART_PORT,
+  CURLUPART_PATH,
+  CURLUPART_QUERY,
+  CURLUPART_FRAGMENT,
+  CURLUPART_ZONEID /* added in 7.65.0 */
+} CURLUPart;
+
+#define CURLU_DEFAULT_PORT (1<<0)       /* return default port number */
+#define CURLU_NO_DEFAULT_PORT (1<<1)    /* act as if no port number was set,
+                                           if the port number matches the
+                                           default for the scheme */
+#define CURLU_DEFAULT_SCHEME (1<<2)     /* return default scheme if
+                                           missing */
+#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */
+#define CURLU_PATH_AS_IS (1<<4)         /* leave dot sequences */
+#define CURLU_DISALLOW_USER (1<<5)      /* no user+password allowed */
+#define CURLU_URLDECODE (1<<6)          /* URL decode on get */
+#define CURLU_URLENCODE (1<<7)          /* URL encode on set */
+#define CURLU_APPENDQUERY (1<<8)        /* append a form style part */
+#define CURLU_GUESS_SCHEME (1<<9)       /* legacy curl-style guessing */
+#define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
+                                           scheme is unknown. */
+
+typedef struct Curl_URL CURLU;
+
+/*
+ * curl_url() creates a new CURLU handle and returns a pointer to it.
+ * Must be freed with curl_url_cleanup().
+ */
+CURL_EXTERN CURLU *curl_url(void);
+
+/*
+ * curl_url_cleanup() frees the CURLU handle and related resources used for
+ * the URL parsing. It will not free strings previously returned with the URL
+ * API.
+ */
+CURL_EXTERN void curl_url_cleanup(CURLU *handle);
+
+/*
+ * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
+ * handle must also be freed with curl_url_cleanup().
+ */
+CURL_EXTERN CURLU *curl_url_dup(CURLU *in);
+
+/*
+ * curl_url_get() extracts a specific part of the URL from a CURLU
+ * handle. Returns error code. The returned pointer MUST be freed with
+ * curl_free() afterwards.
+ */
+CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
+                                   char **part, unsigned int flags);
+
+/*
+ * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns
+ * error code. The passed in string will be copied. Passing a NULL instead of
+ * a part string, clears that part.
+ */
+CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
+                                   const char *part, unsigned int flags);
+
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* CURLINC_URLAPI_H */
diff --git a/libs/curl/lib32/libcurl.a b/libs/curl/lib32/libcurl.a
index 2f5a29f62a792824da80e7fc18e6de2e00088c81..4e4907c5bf0637e86738c31f2d65488d4cf87548 100644
Binary files a/libs/curl/lib32/libcurl.a and b/libs/curl/lib32/libcurl.a differ
diff --git a/libs/curl/lib32/libcurl.dll b/libs/curl/lib32/libcurl.dll
new file mode 100644
index 0000000000000000000000000000000000000000..61925326fda809e108b050fd47012ecd0d0c7216
Binary files /dev/null and b/libs/curl/lib32/libcurl.dll differ
diff --git a/libs/curl/lib32/libcurl.dll.a b/libs/curl/lib32/libcurl.dll.a
new file mode 100644
index 0000000000000000000000000000000000000000..ff1003b6e0a6b62bafa9d713a8e3152f00fe7da8
Binary files /dev/null and b/libs/curl/lib32/libcurl.dll.a differ
diff --git a/libs/curl/lib64/libcurl-x64.dll b/libs/curl/lib64/libcurl-x64.dll
new file mode 100644
index 0000000000000000000000000000000000000000..7dab52541745f2e5127394e5878d70ed5fb2b9c3
Binary files /dev/null and b/libs/curl/lib64/libcurl-x64.dll differ
diff --git a/libs/curl/lib64/libcurl.a b/libs/curl/lib64/libcurl.a
index 2112cd8f0dffcc3918d8b479dc764fd6eb3195eb..d30b71aca2ae49bce3291375e00e741e2e4d5b77 100644
Binary files a/libs/curl/lib64/libcurl.a and b/libs/curl/lib64/libcurl.a differ
diff --git a/libs/curl/lib64/libcurl.dll.a b/libs/curl/lib64/libcurl.dll.a
new file mode 100644
index 0000000000000000000000000000000000000000..d83f092d57f0b13a103603c807977e88c8db7c46
Binary files /dev/null and b/libs/curl/lib64/libcurl.dll.a differ
diff --git a/objs/djgppdos/Debug/.gitignore b/objs/djgppdos/Debug/.gitignore
deleted file mode 100644
index 42c6dc2c662642792a8860e166dfd81126695e8f..0000000000000000000000000000000000000000
--- a/objs/djgppdos/Debug/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# DON'T REMOVE
-# This keeps the folder from disappearing
diff --git a/objs/djgppdos/Release/.gitignore b/objs/djgppdos/Release/.gitignore
deleted file mode 100644
index 42c6dc2c662642792a8860e166dfd81126695e8f..0000000000000000000000000000000000000000
--- a/objs/djgppdos/Release/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# DON'T REMOVE
-# This keeps the folder from disappearing
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5ec8d1534c20183f0ac7e888a08577dc61a43326..ba574f41448bfac956c680db347eb8e5b4ef1fa9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRB2_CORE_SOURCES
 	m_random.c
 	md5.c
 	mserv.c
+	http-mserv.c
 	s_sound.c
 	screen.c
 	sounds.c
@@ -230,6 +231,8 @@ set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL
 	"Enable GME support.")
 set(SRB2_CONFIG_HAVE_OPENMPT ON CACHE BOOL
 	"Enable OpenMPT support.")
+set(SRB2_CONFIG_HAVE_CURL ON CACHE BOOL
+	"Enable curl support, used for downloading files via HTTP.")
 if(${CMAKE_SYSTEM} MATCHES Windows)
 	set(SRB2_CONFIG_HAVE_MIXERX ON CACHE BOOL
 		"Enable SDL Mixer X support.")
@@ -449,6 +452,26 @@ if(${SRB2_CONFIG_HAVE_PNG} AND ${SRB2_CONFIG_HAVE_ZLIB})
 	endif()
 endif()
 
+if(${SRB2_CONFIG_HAVE_CURL})
+	if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
+		set(CURL_FOUND ON)
+		set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl)
+		if(${SRB2_SYSTEM_BITS} EQUAL 64)
+			set(CURL_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/curl/lib64 -lcurl")
+		else() # 32-bit
+			set(CURL_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/curl/lib32 -lcurl")
+		endif()
+	else()
+		find_package(CURL)
+	endif()
+	if(${CURL_FOUND})
+		set(SRB2_HAVE_CURL ON)
+		add_definitions(-DHAVE_CURL)
+	else()
+		message(WARNING "You have specified that CURL is available but it was not found. SRB2 may not compile correctly.")
+	endif()
+endif()
+
 if(${SRB2_CONFIG_HWRENDER})
 	add_definitions(-DHWRENDER)
 	set(SRB2_HWRENDER_SOURCES
diff --git a/src/Makefile b/src/Makefile
index e69bccd260fb43eeaa6dc7169aeb5998192dbc59..f5084092053cdcaa5b589ae9269785985f982656 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -8,13 +8,11 @@
 # terms of the GNU General Public License, version 2.
 # See the 'LICENSE' file for more details.
 #
-#     -DPC_DOS    -> use DOS specific code (eg:textmode stuff)...
 #     -DLINUX     -> use for the GNU/Linux specific
 #     -D_WINDOWS  -> use for the Win32/DirectX specific
 #     -DHAVE_SDL  -> use for the SDL interface
 #
 # Sets:
-#     Compile the DGJPP/DOS version with 'make WATTCP=1'
 #     Compile the DirectX/Mingw version with 'make MINGW=1'
 #     Compile the SDL/Mingw version with 'make MINGW=1 SDL=1'
 #     Compile the SDL/Linux version with 'make LINUX=1'
@@ -58,10 +56,10 @@
 #     Compile with GCC 4.6x version, add 'GCC46=1'
 #     Compile a profile version, add 'PROFILEMODE=1'
 #     Compile a debug version, add 'DEBUGMODE=1'
-#     Compile with extra warnings, add 'WARNINGMODE=1'
+#     Compile with less warnings, add 'RELAXWARNINGS=1'
+#     Generate compiler errors for most compiler warnings, add 'ERRORMODE=1'
 #     Compile without NASM's tmap.nas, add 'NOASM=1'
 #     Compile without 3D hardware support, add 'NOHW=1'
-#     Compile without 3D sound support, add 'NOHS=1'
 #     Compile with GDBstubs, add 'RDB=1'
 #     Compile without PNG, add 'NOPNG=1'
 #     Compile without zlib, add 'NOZLIB=1'
@@ -82,6 +80,58 @@
 #
 #############################################################################
 
+ALL_SYSTEMS=\
+	PANDORA\
+	LINUX64\
+	MINGW64\
+	HAIKU\
+	DUMMY\
+	DJGPPDOS\
+	MINGW\
+	UNIX\
+	LINUX\
+	SOLARIS\
+	FREEBSD\
+	MACOSX\
+	SDL\
+
+# check for user specified system
+ifeq (,$(filter $(ALL_SYSTEMS),$(.VARIABLES)))
+ifeq ($(OS),Windows_NT) # all windows are Windows_NT...
+
+ $(info Detected a Windows system, compiling for 32-bit MinGW SDL2...)
+
+ # go for a 32-bit sdl mingw exe by default
+ MINGW=1
+ SDL=1
+ WINDOWSHELL=1
+
+else # if you on the *nix
+
+ system:=$(shell uname -s)
+
+ ifeq ($(system),Linux)
+ new_system=LINUX
+ else
+
+ $(error \
+	 Could not automatically detect your system,\
+	 try specifying a system manually)
+
+ endif
+
+ ifeq ($(shell getconf LONG_BIT),64)
+ system+=64-bit
+ new_system:=$(new_system)64
+ endif
+
+ $(info Detected $(system) ($(new_system))...)
+ $(new_system)=1
+
+endif
+endif
+
+
 # SRB2 data files
 D_DIR?=../bin/Resources
 D_FILES=$(D_DIR)/srb2.pk3 \
@@ -121,7 +171,6 @@ NOPNG=1
 NOZLIB=1
 NONET=1
 NOHW=1
-NOHS=1
 NOASM=1
 NOIPX=1
 EXENAME?=srb2dummy
@@ -143,11 +192,6 @@ endif
 ifdef PANDORA
 NONX86=1
 NOHW=1
-NOHS=1
-endif
-
-ifdef DJGPPDOS
-include djgppdos/Makefile.cfg
 endif
 
 ifndef NOOPENMPT
@@ -213,6 +257,7 @@ endif
 
 ifdef NONET
 	OPTS+=-DNONET
+	NOCURL=1
 else
 ifdef NO_IPV6
 	OPTS+=-DNO_IPV6
@@ -228,13 +273,6 @@ else
 		 $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o
 endif
 
-ifdef NOHS
-	OPTS+=-DNOHS
-else
-	OPTS+=-DHW3SOUND
-	OBJS+=$(OBJDIR)/hw3sound.o
-endif
-
 OPTS += -DCOMPVERSION
 
 ifndef NONX86
@@ -322,6 +360,16 @@ else
 NOPNG=1
 endif
 
+ifndef NOCURL
+OPTS+=-DHAVE_CURL
+CURLCONFIG?=curl-config
+CURL_CFLAGS?=$(shell $(CURLCONFIG) --cflags)
+CURL_LDFLAGS?=$(shell $(CURLCONFIG) --libs)
+
+LIBS+=$(CURL_LDFLAGS)
+CFLAGS+=$(CURL_CFLAGS)
+endif
+
 ifdef STATIC
 LIBS:=-static $(LIBS)
 endif
@@ -480,11 +528,11 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/w_wad.o    \
 		$(OBJDIR)/filesrch.o \
 		$(OBJDIR)/mserv.o    \
+		$(OBJDIR)/http-mserv.o\
 		$(OBJDIR)/i_tcp.o    \
 		$(OBJDIR)/lzf.o	     \
 		$(OBJDIR)/vid_copy.o \
 		$(OBJDIR)/b_bot.o \
-		$(i_cdmus_o)    \
 		$(i_net_o)      \
 		$(i_system_o)   \
 		$(i_sound_o)    \
@@ -500,10 +548,6 @@ POS:=$(BIN)/en.mo
 OPTS+=-DGETTEXT
 endif
 
-ifdef DJGPPDOS
-all:	 pre-build $(BIN)/$(EXENAME)
-endif
-
 ifdef PANDORA
 all:	pre-build $(BIN)/$(PNDNAME)
 endif
@@ -751,19 +795,6 @@ $(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \
 	$(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@
 endif
 
-ifndef NOHS
-$(OBJDIR)/s_ds3d.o: hardware/s_ds3d/s_ds3d.c hardware/hw3dsdrv.h \
- hardware/hw_dll.h
-	$(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_ds3d.o $(WFLAGS) -D_WINDOWS -mwindows -c hardware/s_ds3d/s_ds3d.c
-
-$(OBJDIR)/s_fmod.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \
- hardware/hw_dll.h
-	$(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_fmod.o $(WFLAGS) -D_WINDOWS -mwindows -c hardware/s_fmod/s_fmod.c
-
-$(OBJDIR)/s_openal.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \
- hardware/hw_dll.h
-	$(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_openal.o $(WFLAGS) -D_WINDOWS -mwindows -c hardware/s_openal/s_openal.c
-endif
 endif
 endif
 
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index 5c56978e717da251d54494ab68399213b2f92e82..db7230bb4b42ffe4a21f27d94fddf73174153e1c 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -48,7 +48,9 @@ endif
 
 # Automatically set version flag, but not if one was manually set
 ifeq   (,$(filter GCC%,$(.VARIABLES)))
- ifneq (,$(findstring gcc,$(shell $(CC) --version))) # if it's GCC
+ version:=$(shell $(CC) --version)
+ # check if this is in fact GCC
+ ifneq (,$(or $(findstring gcc,$(version)),$(findstring GCC,$(version))))
   version:=$(shell $(CC) -dumpversion)
 
   # Turn version into words of major, minor
@@ -208,10 +210,7 @@ WFLAGS=-Wall
 ifndef GCC295
 #WFLAGS+=-Wno-packed
 endif
-ifdef ERRORMODE
-WARNINGMODE=1
-endif
-ifdef WARNINGMODE
+ifndef RELAXWARNINGS
  WFLAGS+=-W
 #WFLAGS+=-Wno-sign-compare
 ifndef GCC295
@@ -345,7 +344,7 @@ ifndef MINGW
 ifndef MINGW64
 ifndef SDL
 ifndef DUMMY
-	DJGPPDOS=1
+$(error No interface or platform flag defined)
 endif
 endif
 endif
@@ -355,7 +354,6 @@ endif
 endif
 
 #determine the interface directory (where you put all i_*.c)
-i_cdmus_o=$(OBJDIR)/i_cdmus.o
 i_net_o=$(OBJDIR)/i_net.o
 i_system_o=$(OBJDIR)/i_system.o
 i_sound_o=$(OBJDIR)/i_sound.o
@@ -381,16 +379,6 @@ UPX_OPTS+=-q
 endif
 
 #Interface Setup
-ifdef DJGPPDOS
-	INTERFACE=djgppdos
-	NASMFORMAT=coff
-	OBJDIR:=$(OBJDIR)/djgppdos
-ifdef WATTCP
-	OBJDIR:=$(OBJDIR)/wattcp
-endif
-	WFLAGS+=-Wno-format
-	BIN:=$(BIN)/Dos
-else
 ifdef DUMMY
 	INTERFACE=dummy
 	OBJDIR:=$(OBJDIR)/dummy
@@ -449,7 +437,6 @@ endif
 endif
 endif
 endif
-endif
 
 ifdef ARCHNAME
 	OBJDIR:=$(OBJDIR)/$(ARCHNAME)
diff --git a/src/android/i_cdmus.c b/src/android/i_cdmus.c
index 426bc5dc9ebdbf130614725e96fadbba42f6dd2c..12063745b3fa9adef15155d780664eee4dd4a2aa 100644
--- a/src/android/i_cdmus.c
+++ b/src/android/i_cdmus.c
@@ -8,8 +8,8 @@
 
 UINT8 cdaudio_started = 0;
 
-consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = CVAR_INIT ("cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL);
+consvar_t cdUpdate  = CVAR_INIT ("cd_update","1",CV_SAVE, NULL, NULL);
 
 
 void I_InitCD(void){}
diff --git a/src/android/i_video.c b/src/android/i_video.c
index a38078a5dbf624df633abaee1f64b126473be12b..bf0decb74118385ff2b776d8d470e5ea3a03a2ba 100644
--- a/src/android/i_video.c
+++ b/src/android/i_video.c
@@ -17,7 +17,7 @@ boolean allow_fullscreen = false;
 
 
 
-consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
 
 void I_StartupGraphics(void){}
 void I_ShutdownGraphics(void){}
diff --git a/src/b_bot.c b/src/b_bot.c
index 4397938c1ae42e90807493b8edbfac81225c12bd..d3635f32c5d75ca1ad56c199241ebfa91c79ea0f 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -193,7 +193,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
 		{
 			cmd->forwardmove = pcmd->forwardmove;
 			cmd->sidemove = pcmd->sidemove;
-			if (pcmd->buttons & BT_USE)
+			if (pcmd->buttons & BT_SPIN)
 			{
 				spin = true;
 				jump = false;
@@ -441,7 +441,7 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
 	if (jump)
 		cmd->buttons |= BT_JUMP;
 	if (spin)
-		cmd->buttons |= BT_USE;
+		cmd->buttons |= BT_SPIN;
 }
 
 void B_MoveBlocked(player_t *player)
diff --git a/src/blua/lstrlib.c b/src/blua/lstrlib.c
index 297504e95bf93cd0dbcc46ab1acd8f65a874e1b5..af933d25a297887b057f4709edbcaa856a50211f 100644
--- a/src/blua/lstrlib.c
+++ b/src/blua/lstrlib.c
@@ -19,6 +19,7 @@
 #include "lauxlib.h"
 #include "lualib.h"
 
+#include "../m_fixed.h"
 
 /* macro to `unsign' a character */
 #define uchar(c)        ((unsigned char)(c))
@@ -790,7 +791,7 @@ static int str_format (lua_State *L) {
         case 'e':  case 'E': case 'f':
         case 'g': case 'G': {
 					lua_Number n = luaL_checknumber(L, arg);
-          sprintf(buff, form, (double)n);
+          sprintf(buff, form, (double)n / FRACUNIT);
           break;
         }
         case 'q': {
diff --git a/src/blua/lvm.c b/src/blua/lvm.c
index b654613f422550956782923e5a348b21acf1a821..46a015c1eb254bc86a59d726d041e5b6461e30d2 100644
--- a/src/blua/lvm.c
+++ b/src/blua/lvm.c
@@ -322,8 +322,8 @@ static void Arith (lua_State *L, StkId ra, TValue *rb,
       case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
       case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
       case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
-      case TM_DIV: if (nc == 0) { lua_pushliteral(L, "divide by zero error"); lua_error(L); } else setnvalue(ra, luai_numdiv(nb, nc)); break;
-      case TM_MOD: if (nc == 0) { lua_pushliteral(L, "modulo by zero error"); lua_error(L); } else setnvalue(ra, luai_nummod(nb, nc)); break;
+      case TM_DIV: if (nc == 0) { luaG_runerror(L, "divide by zero error"); } else setnvalue(ra, luai_numdiv(nb, nc)); break;
+      case TM_MOD: if (nc == 0) { luaG_runerror(L, "modulo by zero error"); } else setnvalue(ra, luai_nummod(nb, nc)); break;
       case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
       case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
       case TM_AND: setnvalue(ra, luai_numand(nb, nc)); break;
@@ -492,8 +492,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
         if (ttisnumber(rb) && ttisnumber(rc)) {
           lua_Number nb = nvalue(rb), nc = nvalue(rc);
           if (nc == 0) {
-            lua_pushliteral(L, "divide by zero error");
-            lua_error(L);
+            luaG_runerror(L, "divide by zero error");
           }
           else
             setnvalue(ra, luai_numdiv(nb, nc));
@@ -508,8 +507,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
         if (ttisnumber(rb) && ttisnumber(rc)) {
           lua_Number nb = nvalue(rb), nc = nvalue(rc);
           if (nc == 0) {
-            lua_pushliteral(L, "modulo by zero error");
-            lua_error(L);
+            luaG_runerror(L, "modulo by zero error");
           }
           else
             setnvalue(ra, luai_nummod(nb, nc));
diff --git a/src/command.c b/src/command.c
index 0a46839f343f45c69034cf52918ac6a3cb4b56e2..51dec0f5fc13d78d689966c23953f714f92c8dbf 100644
--- a/src/command.c
+++ b/src/command.c
@@ -79,7 +79,7 @@ CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
 // First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20)
 // Also set CV_HIDEN during runtime, after config is loaded
 static boolean execversion_enabled = false;
-consvar_t cv_execversion = {"execversion","25",CV_CALL,CV_Unsigned, CV_EnforceExecVersion, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_execversion = CVAR_INIT ("execversion","25",CV_CALL,CV_Unsigned, CV_EnforceExecVersion);
 
 // for default joyaxis detection
 static boolean joyaxis_default = false;
@@ -560,7 +560,7 @@ static boolean COM_Exists(const char *com_name)
   * \param partial The partial name of the command (potentially).
   * \param skips   Number of commands to skip.
   * \return The complete command name, or NULL.
-  * \sa CV_CompleteVar
+  * \sa CV_CompleteAlias, CV_CompleteVar
   */
 const char *COM_CompleteCommand(const char *partial, INT32 skips)
 {
@@ -581,6 +581,32 @@ const char *COM_CompleteCommand(const char *partial, INT32 skips)
 	return NULL;
 }
 
+/** Completes the name of an alias.
+  *
+  * \param partial The partial name of the alias (potentially).
+  * \param skips   Number of aliases to skip.
+  * \return The complete alias name, or NULL.
+  * \sa CV_CompleteCommand, CV_CompleteVar
+  */
+const char *COM_CompleteAlias(const char *partial, INT32 skips)
+{
+	cmdalias_t *a;
+	size_t len;
+
+	len = strlen(partial);
+
+	if (!len)
+		return NULL;
+
+	// check functions
+	for (a = com_alias; a; a = a->next)
+		if (!strncmp(partial, a->name, len))
+			if (!skips--)
+				return a->name;
+
+	return NULL;
+}
+
 /** Parses a single line of text into arguments and tries to execute it.
   * The text can come from the command buffer, a remote client, or stdin.
   *
@@ -1201,7 +1227,7 @@ static consvar_t *CV_FindNetVar(UINT16 netid)
 {
 	consvar_t *cvar;
 
-	if (netid >= consvar_number_of_netids)
+	if (netid > consvar_number_of_netids)
 		return NULL;
 
 	for (cvar = consvar_vars; cvar; cvar = cvar->next)
@@ -1262,12 +1288,12 @@ void CV_RegisterVar(consvar_t *variable)
 	// check net variables
 	if (variable->flags & CV_NETVAR)
 	{
-		variable->netid = consvar_number_of_netids++;
-
 		/* in case of overflow... */
-		if (variable->netid > consvar_number_of_netids)
+		if (consvar_number_of_netids == UINT16_MAX)
 			I_Error("Way too many netvars");
 
+		variable->netid = ++consvar_number_of_netids;
+
 #ifdef OLD22DEMOCOMPAT
 		CV_RegisterOldDemoVar(variable);
 #endif
@@ -1321,7 +1347,7 @@ static const char *CV_StringValue(const char *var_name)
   * \param partial The partial name of the variable (potentially).
   * \param skips   Number of variables to skip.
   * \return The complete variable name, or NULL.
-  * \sa COM_CompleteCommand
+  * \sa COM_CompleteCommand, CV_CompleteAlias
   */
 const char *CV_CompleteVar(char *partial, INT32 skips)
 {
@@ -2370,15 +2396,6 @@ skipwhite:
 		}
 	}
 
-	// parse single characters
-	if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'')
-	{
-		com_token[len] = c;
-		len++;
-		com_token[len] = 0;
-		return data + 1;
-	}
-
 	// parse a regular word
 	do
 	{
@@ -2398,8 +2415,6 @@ skipwhite:
 			len++;
 			c = *data;
 		}
-		if (c == '{' || c == '}' || c == ')'|| c == '(' || c == '\'')
-			break;
 	} while (c > 32);
 
 	com_token[len] = 0;
diff --git a/src/command.h b/src/command.h
index b39153a659802cb4fbb54d489e5bdc883f02dbe5..ec19b403a5d714c750a10b44df628a7655bda8c5 100644
--- a/src/command.h
+++ b/src/command.h
@@ -49,6 +49,8 @@ size_t COM_FirstOption(void);
 // match existing command or NULL
 const char *COM_CompleteCommand(const char *partial, INT32 skips);
 
+const char *COM_CompleteAlias(const char *partial, INT32 skips);
+
 // insert at queu (at end of other command)
 #define COM_BufAddText(s) COM_BufAddTextEx(s, 0)
 void COM_BufAddTextEx(const char *btext, int flags);
@@ -144,6 +146,10 @@ typedef struct consvar_s //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NUL
 	struct consvar_s *next;
 } consvar_t;
 
+/* name, defaultvalue, flags, PossibleValue, func */
+#define CVAR_INIT( ... ) \
+{ __VA_ARGS__, 0, NULL, NULL, 0U, (char)0, NULL }
+
 #ifdef OLD22DEMOCOMPAT
 typedef struct old_demo_var old_demo_var_t;
 
diff --git a/src/config.h.in b/src/config.h.in
index 595bea7b388f01de7375c78db36adb025b0dc9ae..a6f43a7d7b6ab1df4f2abc00e110b97c4290a0cd 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -32,12 +32,14 @@
  * Last updated 2020 / 05 / 11 - v2.2.4 - patch.pk3
  * Last updated 2020 / 07 / 07 - v2.2.5 - player.dta & patch.pk3
  * Last updated 2020 / 07 / 10 - v2.2.6 - player.dta & patch.pk3
+ * Last updated 2020 / 09 / 27 - v2.2.7 - patch.pk3
+ * Last updated 2020 / 10 / 02 - v2.2.8 - patch.pk3
  */
 #define ASSET_HASH_SRB2_PK3   "0277c9416756627004e83cbb5b2e3e28"
 #define ASSET_HASH_ZONES_PK3  "f7e88afb6af7996a834c7d663144bead"
 #define ASSET_HASH_PLAYER_DTA "49dad7b24634c89728cc3e0b689e12bb"
 #ifdef USE_PATCH_DTA
-#define ASSET_HASH_PATCH_PK3  "ecf00060f03c76b3e49c6ae3925b627f"
+#define ASSET_HASH_PATCH_PK3  "466cdf60075262b3f5baa5e07f0999e8"
 #endif
 
 #endif
diff --git a/src/console.c b/src/console.c
index 630feb2aab6d43fd1734f1ee1be1e0747c1c88ba..29794d0170e4a578b93a0cc208600ed17a5416c8 100644
--- a/src/console.c
+++ b/src/console.c
@@ -29,6 +29,7 @@
 #include "i_video.h"
 #include "z_zone.h"
 #include "i_system.h"
+#include "i_threads.h"
 #include "d_main.h"
 #include "m_menu.h"
 #include "filesrch.h"
@@ -44,6 +45,16 @@
 
 #define MAXHUDLINES 20
 
+#ifdef HAVE_THREADS
+I_mutex con_mutex;
+
+#  define Lock_state()    I_lock_mutex(&con_mutex)
+#  define Unlock_state() I_unlock_mutex(con_mutex)
+#else/*HAVE_THREADS*/
+#  define Lock_state()
+#  define Unlock_state()
+#endif/*HAVE_THREADS*/
+
 static boolean con_started = false; // console has been initialised
        boolean con_startup = false; // true at game startup
        boolean con_refresh = false; // screen needs refreshing
@@ -114,22 +125,22 @@ static void CONS_backcolor_Change(void);
 static char con_buffer[CON_BUFFERSIZE];
 
 // how many seconds the hud messages lasts on the screen
-static consvar_t cons_msgtimeout = {"con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cons_msgtimeout = CVAR_INIT ("con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL);
 
 // number of lines displayed on the HUD
-static consvar_t cons_hudlines = {"con_hudlines", "5", CV_CALL|CV_SAVE, CV_Unsigned, CONS_hudlines_Change, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, CV_Unsigned, CONS_hudlines_Change);
 
 // number of lines console move per frame
 // (con_speed needs a limit, apparently)
 static CV_PossibleValue_t speed_cons_t[] = {{0, "MIN"}, {64, "MAX"}, {0, NULL}};
-static consvar_t cons_speed = {"con_speed", "8", CV_SAVE, speed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cons_speed = CVAR_INIT ("con_speed", "8", CV_SAVE, speed_cons_t, NULL);
 
 // percentage of screen height to use for console
-static consvar_t cons_height = {"con_height", "50", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_SAVE, CV_Unsigned, NULL);
 
 static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}, {0, NULL}};
 // whether to use console background picture, or translucent mode
-static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cons_backpic = CVAR_INIT ("con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL);
 
 static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, 		{1, "Black"},		{2, "Sepia"},
 												{3, "Brown"},		{4, "Pink"},		{5, "Raspberry"},
@@ -141,7 +152,7 @@ static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, 		{1, "Black"},		{
 												{0, NULL}};
 
 
-consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cons_backcolor = CVAR_INIT ("con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change);
 
 static void CON_Print(char *msg);
 
@@ -151,6 +162,8 @@ static void CONS_hudlines_Change(void)
 {
 	INT32 i;
 
+	Lock_state();
+
 	// Clear the currently displayed lines
 	for (i = 0; i < con_hudlines; i++)
 		con_hudtime[i] = 0;
@@ -162,6 +175,8 @@ static void CONS_hudlines_Change(void)
 
 	con_hudlines = cons_hudlines.value;
 
+	Unlock_state();
+
 	CONS_Printf(M_GetText("Number of console HUD lines is now %d\n"), con_hudlines);
 }
 
@@ -169,12 +184,16 @@ static void CONS_hudlines_Change(void)
 //
 static void CONS_Clear_f(void)
 {
+	Lock_state();
+
 	memset(con_buffer, 0, CON_BUFFERSIZE);
 
 	con_cx = 0;
 	con_cy = con_totallines-1;
 	con_line = &con_buffer[con_cy*con_width];
 	con_scrollup = 0;
+
+	Unlock_state();
 }
 
 // Choose english keymap
@@ -378,20 +397,29 @@ void CON_Init(void)
 	for (i = 0; i < NUMINPUTS; i++)
 		bindtable[i] = NULL;
 
+	Lock_state();
+
 	// clear all lines
 	memset(con_buffer, 0, CON_BUFFERSIZE);
 
 	// make sure it is ready for the loading screen
 	con_width = 0;
+
+	Unlock_state();
+
 	CON_RecalcSize();
 
 	CON_SetupColormaps();
 
+	Lock_state();
+
 	//note: CON_Ticker should always execute at least once before D_Display()
 	con_clipviewtop = -1; // -1 does not clip
 
 	con_hudlines = atoi(cons_hudlines.defaultvalue);
 
+	Unlock_state();
+
 	// setup console input filtering
 	CON_InputInit();
 
@@ -400,16 +428,24 @@ void CON_Init(void)
 	COM_AddCommand("cls", CONS_Clear_f);
 	//COM_AddCommand("english", CONS_English_f);
 	// set console full screen for game startup MAKE SURE VID_Init() done !!!
+	Lock_state();
+
 	con_destlines = vid.height;
 	con_curlines = vid.height;
 
+	Unlock_state();
 
 	if (!dedicated)
 	{
+		Lock_state();
+
 		con_started = true;
 		con_startup = true;
 		con_refresh = true; // needs explicit screen refresh until we are in the main game loop
 		consoletoggle = false;
+
+		Unlock_state();
+
 		CV_RegisterVar(&cons_msgtimeout);
 		CV_RegisterVar(&cons_hudlines);
 		CV_RegisterVar(&cons_speed);
@@ -420,20 +456,28 @@ void CON_Init(void)
 	}
 	else
 	{
+		Lock_state();
+
 		con_started = true;
 		con_startup = false;
 		con_refresh = false; // disable explicit screen refresh
 		consoletoggle = true;
+
+		Unlock_state();
 	}
 }
 // Console input initialization
 //
 static void CON_InputInit(void)
 {
+	Lock_state();
+
 	// prepare the first prompt line
 	memset(inputlines, 0, sizeof (inputlines));
 	inputline = 0;
 	input_cur = input_sel = input_len = 0;
+
+	Unlock_state();
 }
 
 //======================================================================
@@ -449,6 +493,8 @@ static void CON_RecalcSize(void)
 	char *tmp_buffer;
 	char *string;
 
+	Lock_state();
+
 	switch (cv_constextsize.value)
 	{
 	case V_NOSCALEPATCH:
@@ -486,11 +532,18 @@ static void CON_RecalcSize(void)
 
 	// check for change of video width
 	if (conw == con_width)
+	{
+		Unlock_state();
 		return; // didn't change
+	}
+
+	Unlock_state();
 
 	tmp_buffer = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL);
 	string = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL); // BP: it is a line but who know
 
+	Lock_state();
+
 	oldcon_width = con_width;
 	oldnumlines = con_totallines;
 	oldcon_cy = con_cy;
@@ -511,6 +564,8 @@ static void CON_RecalcSize(void)
 	con_line = &con_buffer[con_cy*con_width];
 	con_scrollup = 0;
 
+	Unlock_state();
+
 	// re-arrange console text buffer to keep text
 	if (oldcon_width) // not the first time
 	{
@@ -535,7 +590,11 @@ static void CON_RecalcSize(void)
 
 static void CON_ChangeHeight(void)
 {
-	INT32 minheight = 20 * con_scalefactor;	// 20 = 8+8+4
+	INT32 minheight;
+
+	Lock_state();
+
+	minheight = 20 * con_scalefactor;	// 20 = 8+8+4
 
 	// toggle console in
 	con_destlines = (cons_height.value*vid.height)/100;
@@ -545,13 +604,19 @@ static void CON_ChangeHeight(void)
 		con_destlines = vid.height;
 
 	con_destlines &= ~0x3; // multiple of text row height
+
+	Unlock_state();
 }
 
 // Handles Console moves in/out of screen (per frame)
 //
 static void CON_MoveConsole(void)
 {
-	const fixed_t conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
+	fixed_t conspeed;
+
+	Lock_state();
+
+	conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
 
 	// instant
 	if (!cons_speed.value)
@@ -573,6 +638,8 @@ static void CON_MoveConsole(void)
 		if (con_curlines < con_destlines)
 			con_curlines = con_destlines;
 	}
+
+	Unlock_state();
 }
 
 // Clear time of console heads up messages
@@ -581,16 +648,25 @@ void CON_ClearHUD(void)
 {
 	INT32 i;
 
+	Lock_state();
+
 	for (i = 0; i < con_hudlines; i++)
 		con_hudtime[i] = 0;
+
+	Unlock_state();
 }
 
 // Force console to move out immediately
 // note: con_ticker will set consoleready false
 void CON_ToggleOff(void)
 {
+	Lock_state();
+
 	if (!con_destlines)
+	{
+		Unlock_state();
 		return;
+	}
 
 	con_destlines = 0;
 	con_curlines = 0;
@@ -599,11 +675,19 @@ void CON_ToggleOff(void)
 	con_clipviewtop = -1; // remove console clipping of view
 
 	I_UpdateMouseGrab();
+
+	Unlock_state();
 }
 
 boolean CON_Ready(void)
 {
-	return consoleready;
+	boolean ready;
+	Lock_state();
+	{
+		ready = consoleready;
+	}
+	Unlock_state();
+	return ready;
 }
 
 // Console ticker: handles console move in/out, cursor blinking
@@ -611,7 +695,11 @@ boolean CON_Ready(void)
 void CON_Ticker(void)
 {
 	INT32 i;
-	INT32 minheight = 20 * con_scalefactor;	// 20 = 8+8+4
+	INT32 minheight;
+
+	Lock_state();
+
+	minheight = 20 * con_scalefactor;	// 20 = 8+8+4
 
 	// cursor blinking
 	con_tick++;
@@ -662,6 +750,8 @@ void CON_Ticker(void)
 		if (con_hudtime[i] < 0)
 			con_hudtime[i] = 0;
 	}
+
+	Unlock_state();
 }
 
 //
@@ -673,32 +763,51 @@ void CON_Ticker(void)
 
 static void CON_InputClear(void)
 {
+	Lock_state();
+
 	memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
 	input_cur = input_sel = input_len = 0;
+
+	Unlock_state();
 }
 
 static void CON_InputSetString(const char *c)
 {
+	Lock_state();
+
 	memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
 	strcpy(inputlines[inputline], c);
 	input_cur = input_sel = input_len = strlen(c);
+
+	Unlock_state();
 }
 
 static void CON_InputAddString(const char *c)
 {
 	size_t csize = strlen(c);
+
+	Lock_state();
+
 	if (input_len + csize > CON_MAXPROMPTCHARS-1)
+	{
+		Unlock_state();
 		return;
+	}
 	if (input_cur != input_len)
 		memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
 	memcpy(&inputlines[inputline][input_cur], c, csize);
 	input_len += csize;
 	input_sel = (input_cur += csize);
+
+	Unlock_state();
 }
 
 static void CON_InputDelSelection(void)
 {
 	size_t start, end, len;
+
+	Lock_state();
+
 	if (input_cur > input_sel)
 	{
 		start = input_sel;
@@ -717,27 +826,39 @@ static void CON_InputDelSelection(void)
 
 	input_len -= len;
 	input_sel = input_cur = start;
+
+	Unlock_state();
 }
 
 static void CON_InputAddChar(char c)
 {
 	if (input_len >= CON_MAXPROMPTCHARS-1)
 		return;
+
+	Lock_state();
+
 	if (input_cur != input_len)
 		memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
 	inputlines[inputline][input_cur++] = c;
 	inputlines[inputline][++input_len] = 0;
 	input_sel = input_cur;
+
+	Unlock_state();
 }
 
 static void CON_InputDelChar(void)
 {
 	if (!input_cur)
 		return;
+
+	Lock_state();
+
 	if (input_cur != input_len)
 		memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
 	inputlines[inputline][--input_len] = 0;
 	input_sel = --input_cur;
+
+	Unlock_state();
 }
 
 //
@@ -752,9 +873,14 @@ boolean CON_Responder(event_t *ev)
 
 	// sequential completions a la 4dos
 	static char completion[80];
-	static INT32 comskips, varskips;
 
-	const char *cmd = "";
+	static INT32 skips;
+
+	static INT32   com_skips;
+	static INT32   var_skips;
+	static INT32 alias_skips;
+
+	const char *cmd = NULL;
 	INT32 key;
 
 	if (chat_on)
@@ -838,6 +964,44 @@ boolean CON_Responder(event_t *ev)
 		return true;
 	}
 
+	// backspace and delete command prompt
+	if (input_sel != input_cur)
+	{
+		if (key == KEY_BACKSPACE || key == KEY_DEL)
+		{
+			CON_InputDelSelection();
+			return true;
+		}
+	}
+	else if (key == KEY_BACKSPACE)
+	{
+		if (ctrldown)
+		{
+			input_sel = M_JumpWordReverse(inputlines[inputline], input_cur);
+			CON_InputDelSelection();
+		}
+		else
+			CON_InputDelChar();
+		return true;
+	}
+	else if (key == KEY_DEL)
+	{
+		if (input_cur == input_len)
+			return true;
+
+		if (ctrldown)
+		{
+			input_sel = input_cur + M_JumpWord(&inputlines[inputline][input_cur]);
+			CON_InputDelSelection();
+		}
+		else
+		{
+			++input_cur;
+			CON_InputDelChar();
+		}
+		return true;
+	}
+
 	// ctrl modifier -- changes behavior, adds shortcuts
 	if (ctrldown)
 	{
@@ -851,7 +1015,6 @@ boolean CON_Responder(event_t *ev)
 				if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
 					return true;
 				strcpy(completion, inputlines[inputline]);
-				comskips = varskips = 0;
 			}
 			len = strlen(completion);
 
@@ -867,6 +1030,14 @@ boolean CON_Responder(event_t *ev)
 				CONS_Printf("  \x83" "%s" "\x80" "%s\n", completion, cmd+len);
 			if (i == 0) CONS_Printf("  (none)\n");
 
+			//and finally aliases
+			CONS_Printf("Aliases:\n");
+			for (i = 0, cmd = COM_CompleteAlias(completion, i); cmd; cmd = COM_CompleteAlias(completion, ++i))
+				CONS_Printf("  \x83" "%s" "\x80" "%s\n", completion, cmd+len);
+			if (i == 0) CONS_Printf("  (none)\n");
+
+			completion[0] = 0;
+
 			return true;
 		}
 		// ---
@@ -935,43 +1106,64 @@ boolean CON_Responder(event_t *ev)
 			if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
 				return true;
 			strcpy(completion, inputlines[inputline]);
-			comskips = varskips = 0;
+			skips       = 0;
+			com_skips   = 0;
+			var_skips   = 0;
+			alias_skips = 0;
 		}
 		else
 		{
 			if (shiftdown)
 			{
-				if (comskips < 0)
-				{
-					if (--varskips < 0)
-						comskips = -comskips - 2;
-				}
-				else if (comskips > 0) comskips--;
+				if (skips > 0)
+					skips--;
 			}
 			else
 			{
-				if (comskips < 0) varskips++;
-				else              comskips++;
+				skips++;
 			}
 		}
 
-		if (comskips >= 0)
+		if (skips <= com_skips)
 		{
-			cmd = COM_CompleteCommand(completion, comskips);
-			if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
-				comskips = -comskips - 1;
+			cmd = COM_CompleteCommand(completion, skips);
+
+			if (cmd && skips == com_skips)
+			{
+				com_skips  ++;
+				var_skips  ++;
+				alias_skips++;
+			}
+		}
+
+		if (!cmd && skips <= var_skips)
+		{
+			cmd = CV_CompleteVar(completion, skips - com_skips);
+
+			if (cmd && skips == var_skips)
+			{
+				var_skips  ++;
+				alias_skips++;
+			}
+		}
+
+		if (!cmd && skips <= alias_skips)
+		{
+			cmd = COM_CompleteAlias(completion, skips - var_skips);
+
+			if (cmd && skips == alias_skips)
+			{
+				alias_skips++;
+			}
 		}
-		if (comskips < 0)
-			cmd = CV_CompleteVar(completion, varskips);
 
 		if (cmd)
+		{
 			CON_InputSetString(va("%s ", cmd));
+		}
 		else
 		{
-			if (comskips > 0)
-				comskips--;
-			else if (varskips > 0)
-				varskips--;
+			skips--;
 		}
 
 		return true;
@@ -1028,29 +1220,6 @@ boolean CON_Responder(event_t *ev)
 		return true;
 	}
 
-	// backspace and delete command prompt
-	if (input_sel != input_cur)
-	{
-		if (key == KEY_BACKSPACE || key == KEY_DEL)
-		{
-			CON_InputDelSelection();
-			return true;
-		}
-	}
-	else if (key == KEY_BACKSPACE)
-	{
-		CON_InputDelChar();
-		return true;
-	}
-	else if (key == KEY_DEL)
-	{
-		if (input_cur == input_len)
-			return true;
-		++input_cur;
-		CON_InputDelChar();
-		return true;
-	}
-
 	// move back in input history
 	if (key == KEY_UPARROW)
 	{
@@ -1156,6 +1325,8 @@ static void CON_Print(char *msg)
 		S_StartSound(NULL, sfx_radio);
 	}
 
+	Lock_state();
+
 	if (!(*msg & 0x80))
 	{
 		con_line[con_cx++] = '\x80';
@@ -1216,7 +1387,10 @@ static void CON_Print(char *msg)
 		}
 
 		if (*msg == '\0')
+		{
+			Unlock_state();
 			return;
+		}
 
 		// printable character
 		for (l = 0; l < (con_width-11) && msg[l] > ' '; l++)
@@ -1234,6 +1408,8 @@ static void CON_Print(char *msg)
 		for (; l > 0; l--)
 			con_line[con_cx++] = *(msg++);
 	}
+
+	Unlock_state();
 }
 
 void CON_LogMessage(const char *msg)
@@ -1265,6 +1441,7 @@ void CONS_Printf(const char *fmt, ...)
 {
 	va_list argptr;
 	static char *txt = NULL;
+	boolean refresh;
 
 	if (txt == NULL)
 		txt = malloc(8192);
@@ -1276,44 +1453,25 @@ void CONS_Printf(const char *fmt, ...)
 	// echo console prints to log file
 	DEBFILE(txt);
 
-	if (!con_started)
-	{
-#ifdef PC_DOS
-		CON_LogMessage(txt);
-		free(txt);
-		return;
-#endif
-	}
-	else
-		// write message in con text buffer
+	// write message in con text buffer
+	if (con_started)
 		CON_Print(txt);
 
-#ifndef PC_DOS
 	CON_LogMessage(txt);
-#endif
+
+	Lock_state();
 
 	// make sure new text is visible
 	con_scrollup = 0;
+	refresh = con_refresh;
+
+	Unlock_state();
 
 	// if not in display loop, force screen update
-	if (con_refresh)
+	if (refresh)
 	{
-#if defined(_WINDOWS)
-		if (con_startup)
-		{
-			patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH);
-
-			// Jimita: CON_DrawBackpic just called V_DrawScaledPatch
-			V_DrawScaledPatch(0, 0, 0, con_backpic);
-
-			W_UnlockCachedPatch(con_backpic);
-			I_LoadingScreen(txt);				// Win32/OS2 only
-		}
-#else
-		// here we display the console text
-		CON_Drawer();
+		CON_Drawer(); // here we display the console text
 		I_FinishUpdate(); // page flip or blit buffer
-#endif
 	}
 }
 
@@ -1544,8 +1702,12 @@ static void CON_DrawBackpic(void)
 	lumpnum_t piclump;
 	int x, w, h;
 
-	// Get the lumpnum for CONSBACK, or fallback into MISSING.
-	piclump = W_CheckNumForName("CONSBACK");
+	// Get the lumpnum for CONSBACK, STARTUP (Only during game startup) or fallback into MISSING.
+	if (con_startup)
+		piclump = W_CheckNumForName("STARTUP");
+	else
+		piclump = W_CheckNumForName("CONSBACK");
+
 	if (piclump == LUMPERROR)
 		piclump = W_GetNumForName("MISSING");
 
@@ -1650,8 +1812,13 @@ static void CON_DrawConsole(void)
 //
 void CON_Drawer(void)
 {
+	Lock_state();
+
 	if (!con_started || !graphics_started)
+	{
+		Unlock_state();
 		return;
+	}
 
 	if (con_recalc)
 	{
@@ -1666,4 +1833,6 @@ void CON_Drawer(void)
 	|| gamestate == GS_INTERMISSION || gamestate == GS_ENDING || gamestate == GS_CUTSCENE
 	|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
 		CON_DrawHudlines();
+
+	Unlock_state();
 }
diff --git a/src/console.h b/src/console.h
index 6f38ca8d010c4441663c01c60bbfb22b830fae0f..0296f4f6e658e82a01d78a2ae05f636d90e411ed 100644
--- a/src/console.h
+++ b/src/console.h
@@ -12,11 +12,16 @@
 
 #include "d_event.h"
 #include "command.h"
+#include "i_threads.h"
 
 void CON_Init(void);
 
 boolean CON_Responder(event_t *ev);
 
+#ifdef HAVE_THREADS
+extern I_mutex con_mutex;
+#endif
+
 // set true when screen size has changed, to adapt console
 extern boolean con_recalc;
 
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index d3cc0b0e278f45fc1f55b8c0a1c74e959838bd19..c9490410b478041b66e4a37fe5c4c333bc54cf61 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -157,10 +157,10 @@ ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
 static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL};
 
 
-consvar_t cv_showjoinaddress = {"showjoinaddress", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE, CV_OnOff, NULL);
 
 static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}};
-consvar_t cv_playbackspeed = {"playbackspeed", "1", 0, playbackspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL);
 
 static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
 {
@@ -1269,19 +1269,25 @@ static UINT8 Snake_GetOppositeDir(UINT8 dir)
 		return 12 + 5 - dir;
 }
 
-static void Snake_FindFreeSlot(UINT8 *x, UINT8 *y, UINT8 headx, UINT8 heady)
+static void Snake_FindFreeSlot(UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady)
 {
+	UINT8 x, y;
 	UINT16 i;
 
 	do
 	{
-		*x = M_RandomKey(SNAKE_NUM_BLOCKS_X);
-		*y = M_RandomKey(SNAKE_NUM_BLOCKS_Y);
+		x = M_RandomKey(SNAKE_NUM_BLOCKS_X);
+		y = M_RandomKey(SNAKE_NUM_BLOCKS_Y);
 
 		for (i = 0; i < snake->snakelength; i++)
-			if (*x == snake->snakex[i] && *y == snake->snakey[i])
+			if (x == snake->snakex[i] && y == snake->snakey[i])
 				break;
-	} while (i < snake->snakelength || (*x == headx && *y == heady));
+	} while (i < snake->snakelength || (x == headx && y == heady)
+		|| (x == snake->applex && y == snake->appley)
+		|| (snake->bonustype != SNAKE_BONUS_NONE && x == snake->bonusx && y == snake->bonusy));
+
+	*freex = x;
+	*freey = y;
 }
 
 static void Snake_Handle(void)
@@ -1412,7 +1418,7 @@ static void Snake_Handle(void)
 	// Check collision with apple
 	if (x == snake->applex && y == snake->appley)
 	{
-		if (snake->snakelength + 1 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y)
+		if (snake->snakelength + 3 < SNAKE_NUM_BLOCKS_X * SNAKE_NUM_BLOCKS_Y)
 		{
 			snake->snakelength++;
 			snake->snakex  [snake->snakelength - 1] = snake->snakex  [snake->snakelength - 2];
@@ -2113,7 +2119,7 @@ static void SV_SendSaveGame(INT32 node)
 
 #ifdef DUMPCONSISTENCY
 #define TMPSAVENAME "badmath.sav"
-static consvar_t cv_dumpconsistency = {"dumpconsistency", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_NETVAR, CV_OnOff, NULL);
 
 static void SV_SavedGame(void)
 {
@@ -2228,7 +2234,7 @@ static void CL_LoadReceivedSavegame(void)
 #endif
 
 #ifndef NONET
-static void SendAskInfo(INT32 node, boolean viams)
+static void SendAskInfo(INT32 node)
 {
 	const tic_t asktime = I_GetTime();
 	netbuffer->packettype = PT_ASKINFO;
@@ -2239,10 +2245,6 @@ static void SendAskInfo(INT32 node, boolean viams)
 	// now allowed traffic from the host to us in, so once the MS relays
 	// our address to the host, it'll be able to speak to us.
 	HSendPacket(node, false, 0, sizeof (askinfo_pak));
-
-	// Also speak to the MS.
-	if (viams && node != 0 && node != BROADCASTADDR)
-		SendAskInfoViaMS(node, asktime);
 }
 
 serverelem_t serverlist[MAXSERVERLIST];
@@ -2310,13 +2312,95 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
 	M_SortServerList();
 }
 
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+struct Fetch_servers_ctx
+{
+	int room;
+	int id;
+};
+
+static void
+Fetch_servers_thread (struct Fetch_servers_ctx *ctx)
+{
+	msg_server_t *server_list;
+
+	server_list = GetShortServersList(ctx->room, ctx->id);
+
+	if (server_list)
+	{
+		I_lock_mutex(&ms_QueryId_mutex);
+		{
+			if (ctx->id != ms_QueryId)
+			{
+				free(server_list);
+				server_list = NULL;
+			}
+		}
+		I_unlock_mutex(ms_QueryId_mutex);
+
+		if (server_list)
+		{
+			I_lock_mutex(&m_menu_mutex);
+			{
+				if (m_waiting_mode == M_WAITING_SERVERS)
+					m_waiting_mode = M_NOT_WAITING;
+			}
+			I_unlock_mutex(m_menu_mutex);
+
+			I_lock_mutex(&ms_ServerList_mutex);
+			{
+				ms_ServerList = server_list;
+			}
+			I_unlock_mutex(ms_ServerList_mutex);
+		}
+	}
+
+	free(ctx);
+}
+#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
+
+void CL_QueryServerList (msg_server_t *server_list)
+{
+	INT32 i;
+
+	for (i = 0; server_list[i].header.buffer[0]; i++)
+	{
+		// Make sure MS version matches our own, to
+		// thwart nefarious servers who lie to the MS.
+
+		/* lol bruh, that version COMES from the servers */
+		//if (strcmp(version, server_list[i].version) == 0)
+		{
+			INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port);
+			if (node == -1)
+				break; // no more node free
+			SendAskInfo(node);
+			// Force close the connection so that servers can't eat
+			// up nodes forever if we never get a reply back from them
+			// (usually when they've not forwarded their ports).
+			//
+			// Don't worry, we'll get in contact with the working
+			// servers again when they send SERVERINFO to us later!
+			//
+			// (Note: as a side effect this probably means every
+			// server in the list will probably be using the same node (e.g. node 1),
+			// not that it matters which nodes they use when
+			// the connections are closed afterwards anyway)
+			// -- Monster Iestyn 12/11/18
+			Net_CloseConnection(node|FORCECLOSE);
+		}
+	}
+}
+
 void CL_UpdateServerList(boolean internetsearch, INT32 room)
 {
+	(void)internetsearch;
+	(void)room;
+
 	SL_ClearServerList(0);
 
 	if (!netgame && I_NetOpenSocket)
 	{
-		MSCloseUDPSocket();		// Tidy up before wiping the slate.
 		if (I_NetOpenSocket())
 		{
 			netgame = true;
@@ -2326,71 +2410,54 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
 
 	// search for local servers
 	if (netgame)
-		SendAskInfo(BROADCASTADDR, false);
+		SendAskInfo(BROADCASTADDR);
 
+#ifdef MASTERSERVER
 	if (internetsearch)
 	{
-		const msg_server_t *server_list;
-		INT32 i = -1;
-		server_list = GetShortServersList(room);
-		if (server_list)
-		{
-			char version[8] = "";
-#ifndef DEVELOP
-			strcpy(version, SRB2VERSION);
-#else
-			strcpy(version, GetRevisionString());
-#endif
-			version[sizeof (version) - 1] = '\0';
+#ifdef HAVE_THREADS
+		struct Fetch_servers_ctx *ctx;
 
-			for (i = 0; server_list[i].header.buffer[0]; i++)
-			{
-				// Make sure MS version matches our own, to
-				// thwart nefarious servers who lie to the MS.
+		ctx = malloc(sizeof *ctx);
 
-				if (strcmp(version, server_list[i].version) == 0)
-				{
-					INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port);
-					if (node == -1)
-						break; // no more node free
-					SendAskInfo(node, true);
-					// Force close the connection so that servers can't eat
-					// up nodes forever if we never get a reply back from them
-					// (usually when they've not forwarded their ports).
-					//
-					// Don't worry, we'll get in contact with the working
-					// servers again when they send SERVERINFO to us later!
-					//
-					// (Note: as a side effect this probably means every
-					// server in the list will probably be using the same node (e.g. node 1),
-					// not that it matters which nodes they use when
-					// the connections are closed afterwards anyway)
-					// -- Monster Iestyn 12/11/18
-					Net_CloseConnection(node|FORCECLOSE);
-				}
-			}
+		/* This called from M_Refresh so I don't use a mutex */
+		m_waiting_mode = M_WAITING_SERVERS;
+
+		I_lock_mutex(&ms_QueryId_mutex);
+		{
+			ctx->id = ms_QueryId;
 		}
+		I_unlock_mutex(ms_QueryId_mutex);
+
+		ctx->room = room;
+
+		I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx);
+#else
+		msg_server_t *server_list;
+
+		server_list = GetShortServersList(room, 0);
 
-		//no server list?(-1) or no servers?(0)
-		if (!i)
+		if (server_list)
 		{
-			; /// TODO: display error or warning?
+			CL_QueryServerList(server_list);
+			free(server_list);
 		}
+#endif
 	}
+#endif/*MASTERSERVER*/
 }
 
 #endif // ifndef NONET
 
 /** Called by CL_ServerConnectionTicker
   *
-  * \param viams ???
-  * \param asksent ???
+  * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
   * \return False if the connection was aborted
   * \sa CL_ServerConnectionTicker
   * \sa CL_ConnectToServer
   *
   */
-static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
+static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
 {
 #ifndef NONET
 	INT32 i;
@@ -2452,11 +2519,11 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
 				CL_Reset();
 				D_StartTitle();
 				M_StartMessage(M_GetText(
-					"You have WAD files loaded or have\n"
-					"modified the game in some way, and\n"
-					"your file list does not match\n"
-					"the server's file list.\n"
-					"Please restart SRB2 before connecting.\n\n"
+					"You have the wrong addons loaded.\n\n"
+					"To play on this server, restart\n"
+					"the game and don't load any addons.\n"
+					"SRB2 will automatically add\n"
+					"everything you need when you join.\n\n"
 					"Press ESC\n"
 				), NULL, MM_NOTHING);
 				return false;
@@ -2501,11 +2568,10 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
 	// Ask the info to the server (askinfo packet)
 	if (*asksent + NEWTICRATE < I_GetTime())
 	{
-		SendAskInfo(servernode, viams);
+		SendAskInfo(servernode);
 		*asksent = I_GetTime();
 	}
 #else
-	(void)viams;
 	(void)asksent;
 	// No netgames, so we skip this state.
 	cl_mode = CL_ASKJOIN;
@@ -2516,7 +2582,6 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
 
 /** Called by CL_ConnectToServer
   *
-  * \param viams ???
   * \param tmpsave The name of the gamestate file???
   * \param oldtic Used for knowing when to poll events and redraw
   * \param asksent ???
@@ -2525,7 +2590,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
   * \sa CL_ConnectToServer
   *
   */
-static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic_t *oldtic, tic_t *asksent)
+static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent)
 {
 	boolean waitmore;
 	INT32 i;
@@ -2537,7 +2602,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
 	switch (cl_mode)
 	{
 		case CL_SEARCHING:
-			if (!CL_ServerConnectionSearchTicker(viams, asksent))
+			if (!CL_ServerConnectionSearchTicker(asksent))
 				return false;
 			break;
 
@@ -2673,11 +2738,10 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
 
 /** Use adaptive send using net_bandwidth and stat.sendbytes
   *
-  * \param viams ???
   * \todo Better description...
   *
   */
-static void CL_ConnectToServer(boolean viams)
+static void CL_ConnectToServer(void)
 {
 	INT32 pnumnodes, nodewaited = doomcom->numnodes, i;
 	tic_t oldtic;
@@ -2737,9 +2801,9 @@ static void CL_ConnectToServer(boolean viams)
 	{
 		// If the connection was aborted for some reason, leave
 #ifndef NONET
-		if (!CL_ServerConnectionTicker(viams, tmpsave, &oldtic, &asksent))
+		if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent))
 #else
-		if (!CL_ServerConnectionTicker(viams, (char*)NULL, &oldtic, (tic_t *)NULL))
+		if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL))
 #endif
 			return;
 
@@ -2916,9 +2980,6 @@ static void Command_ReloadBan(void)  //recheck ban.txt
 
 static void Command_connect(void)
 {
-	// Assume we connect directly.
-	boolean viams = false;
-
 	if (COM_Argc() < 2 || *COM_Argv(1) == 0)
 	{
 		CONS_Printf(M_GetText(
@@ -2954,9 +3015,6 @@ static void Command_connect(void)
 		if (netgame && !stricmp(COM_Argv(1), "node"))
 		{
 			servernode = (SINT8)atoi(COM_Argv(2));
-
-			// Use MS to traverse NAT firewalls.
-			viams = true;
 		}
 		else if (netgame)
 		{
@@ -2965,7 +3023,6 @@ static void Command_connect(void)
 		}
 		else if (I_NetOpenSocket)
 		{
-			MSCloseUDPSocket(); // Tidy up before wiping the slate.
 			I_NetOpenSocket();
 			netgame = true;
 			multiplayer = true;
@@ -2994,7 +3051,7 @@ static void Command_connect(void)
 	SplitScreen_OnChange();
 	botingame = false;
 	botskin = 0;
-	CL_ConnectToServer(viams);
+	CL_ConnectToServer();
 }
 #endif
 
@@ -3110,6 +3167,8 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
 	// Reset the name
 	sprintf(player_names[playernum], "Player %d", playernum+1);
 
+	player_name_changes[playernum] = 0;
+
 	if (IsPlayerAdmin(playernum))
 	{
 		RemoveAdminPlayer(playernum); // don't stay admin after you're gone
@@ -3616,29 +3675,29 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
 }
 
 static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
-consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL);
 
-consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL	};
-consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done
+consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_NETVAR, CV_OnOff, NULL);
+consvar_t cv_joinnextround = CVAR_INIT ("joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL); /// \todo not done
 static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}};
-consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL);
 static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}};
-consvar_t cv_joindelay = {"joindelay", "10", CV_SAVE, joindelay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE, joindelay_cons_t, NULL);
 static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}};
-consvar_t cv_rejointimeout = {"rejointimeout", "Off", CV_SAVE|CV_FLOAT, rejointimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "Off", CV_SAVE|CV_FLOAT, rejointimeout_cons_t, NULL);
 
 static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}};
-consvar_t cv_resynchattempts = {"resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL	};
-consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL	};
+consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL);
+consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE, CV_OnOff, NULL);
 
 // max file size to send to a player (in kilobytes)
 static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
-consvar_t cv_maxsend = {"maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL);
+consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE, CV_OnOff, NULL);
 
 // Speed of file downloading (in packets per tic)
 static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
-consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL);
 
 static void Got_AddPlayer(UINT8 **p, INT32 playernum);
 
@@ -3726,6 +3785,8 @@ void SV_ResetServer(void)
 		adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
 	}
 
+	memset(player_name_changes, 0, sizeof player_name_changes);
+
 	mynode = 0;
 	cl_packetmissed = false;
 
@@ -3791,8 +3852,10 @@ void D_QuitNetGame(void)
 		for (i = 0; i < MAXNETNODES; i++)
 			if (nodeingame[i])
 				HSendPacket(i, true, 0, 0);
+#ifdef MASTERSERVER
 		if (serverrunning && ms_RoomId > 0)
 			UnregisterServer();
+#endif
 	}
 	else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode])
 	{
@@ -4055,15 +4118,16 @@ boolean SV_SpawnServer(void)
 		SV_GenContext();
 		if (netgame && I_NetOpenSocket)
 		{
-			MSCloseUDPSocket();		// Tidy up before wiping the slate.
 			I_NetOpenSocket();
+#ifdef MASTERSERVER
 			if (ms_RoomId > 0)
 				RegisterServer();
+#endif
 		}
 
 		// non dedicated server just connect to itself
 		if (!dedicated)
-			CL_ConnectToServer(false);
+			CL_ConnectToServer();
 		else doomcom->numslots = 1;
 	}
 
@@ -5379,11 +5443,15 @@ void TryRunTics(tic_t realtics)
 			{
 				DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
 
+				rs_tictime = I_GetTimeMicros();
+
 				G_Ticker((gametic % NEWTICRATERATIO) == 0);
 				ExtraDataTicker();
 				gametic++;
 				consistancy[gametic%BACKUPTICS] = Consistancy();
 
+				rs_tictime = I_GetTimeMicros() - rs_tictime;
+
 				// Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame.
 				if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value)
 					break;
@@ -5520,7 +5588,9 @@ void NetUpdate(void)
 	// client send the command after a receive of the server
 	// the server send before because in single player is beter
 
+#ifdef MASTERSERVER
 	MasterClient_Ticker(); // Acking the Master Server
+#endif
 
 	if (client)
 	{
@@ -5595,7 +5665,13 @@ void NetUpdate(void)
 	if (nowtime > resptime)
 	{
 		resptime = nowtime;
+#ifdef HAVE_THREADS
+		I_lock_mutex(&m_menu_mutex);
+#endif
 		M_Ticker();
+#ifdef HAVE_THREADS
+		I_unlock_mutex(m_menu_mutex);
+#endif
 		CON_Ticker();
 	}
 
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index d537984df8a227b53a5b2dc43cc8c4d3669cbba1..adc8a7cc9b090cf4bf5d5881f08070bf34ba1093 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -14,10 +14,12 @@
 #define __D_CLISRV__
 
 #include "d_ticcmd.h"
+#include "d_net.h"
 #include "d_netcmd.h"
 #include "d_net.h"
 #include "tables.h"
 #include "d_player.h"
+#include "mserv.h"
 
 /*
 The 'packet version' is used to distinguish packet formats.
@@ -483,7 +485,7 @@ typedef struct
 #pragma pack()
 #endif
 
-#define MAXSERVERLIST 64 // Depends only on the display
+#define MAXSERVERLIST (MAXNETNODES-1)
 typedef struct
 {
 	SINT8 node;
@@ -525,7 +527,12 @@ typedef enum
 
 } kickreason_t;
 
+/* the max number of name changes in some time period */
+#define MAXNAMECHANGES (5)
+#define NAMECHANGERATE (60*TICRATE)
+
 extern boolean server;
+extern boolean serverrunning;
 #define client (!server)
 extern boolean dedicated; // For dedicated server
 extern UINT16 software_MAXPACKETLENGTH;
@@ -565,6 +572,7 @@ void CL_AddSplitscreenPlayer(void);
 void CL_RemoveSplitscreenPlayer(void);
 void CL_Reset(void);
 void CL_ClearPlayer(INT32 playernum);
+void CL_QueryServerList(msg_server_t *list);
 void CL_UpdateServerList(boolean internetsearch, INT32 room);
 // Is there a game running
 boolean Playing(void);
diff --git a/src/d_main.c b/src/d_main.c
index 6144abd85952c630fb1a34a71957b9daf834592c..9f3934d32dd744869daa756aaaab2893d2766c25 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -24,12 +24,6 @@
 #include <unistd.h> // for getcwd
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-int	snprintf(char *str, size_t n, const char *fmt, ...);
-//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
 #ifdef _WIN32
 #include <direct.h>
 #include <malloc.h>
@@ -46,6 +40,7 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 #include "hu_stuff.h"
 #include "i_sound.h"
 #include "i_system.h"
+#include "i_threads.h"
 #include "i_video.h"
 #include "m_argv.h"
 #include "m_menu.h"
@@ -104,6 +99,7 @@ UINT8 window_notinfocus = false;
 // DEMO LOOP
 //
 static char *startupwadfiles[MAX_WADFILES];
+static char *startuppwads[MAX_WADFILES];
 
 boolean devparm = false; // started game with -devparm
 
@@ -160,10 +156,6 @@ void D_PostEvent(const event_t *ev)
 	events[eventhead] = *ev;
 	eventhead = (eventhead+1) & (MAXEVENTS-1);
 }
-// just for lock this function
-#if defined (PC_DOS) && !defined (DOXYGEN)
-void D_PostEvent_end(void) {};
-#endif
 
 // modifier keys
 // Now handled in I_OsPolling
@@ -180,6 +172,8 @@ void D_ProcessEvents(void)
 {
 	event_t *ev;
 
+	boolean eaten;
+
 	for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
 	{
 		ev = &events[eventtail];
@@ -195,11 +189,31 @@ void D_ProcessEvents(void)
 		}
 
 		// Menu input
-		if (M_Responder(ev))
+#ifdef HAVE_THREADS
+		I_lock_mutex(&m_menu_mutex);
+#endif
+		{
+			eaten = M_Responder(ev);
+		}
+#ifdef HAVE_THREADS
+		I_unlock_mutex(m_menu_mutex);
+#endif
+
+		if (eaten)
 			continue; // menu ate the event
 
 		// console input
-		if (CON_Responder(ev))
+#ifdef HAVE_THREADS
+		I_lock_mutex(&con_mutex);
+#endif
+		{
+			eaten = CON_Responder(ev);
+		}
+#ifdef HAVE_THREADS
+		I_unlock_mutex(con_mutex);
+#endif
+
+		if (eaten)
 			continue; // ate the event
 
 		G_Responder(ev);
@@ -459,6 +473,8 @@ static void D_Display(void)
 				lastdraw = false;
 			}
 
+			rs_uitime = I_GetTimeMicros();
+
 			if (gamestate == GS_LEVEL)
 			{
 				ST_Drawer();
@@ -468,6 +484,10 @@ static void D_Display(void)
 			else
 				F_TitleScreenDrawer();
 		}
+		else
+		{
+			rs_uitime = I_GetTimeMicros();
+		}
 	}
 
 	// change gamma if needed
@@ -497,11 +517,19 @@ static void D_Display(void)
 	// vid size change is now finished if it was on...
 	vid.recalc = 0;
 
+#ifdef HAVE_THREADS
+	I_lock_mutex(&m_menu_mutex);
+#endif
 	M_Drawer(); // menu is drawn even on top of everything
+#ifdef HAVE_THREADS
+	I_unlock_mutex(m_menu_mutex);
+#endif
 	// focus lost moved to M_Drawer
 
 	CON_Drawer();
 
+	rs_uitime = I_GetTimeMicros() - rs_uitime;
+
 	//
 	// wipe update
 	//
@@ -606,6 +634,7 @@ static void D_Display(void)
 			V_DrawThinString(80, 40, V_MONOSPACE | V_BLUEMAP, s);
 			if (rendermode == render_opengl) // OpenGL specific stats
 			{
+#ifdef HWRENDER
 				snprintf(s, sizeof s - 1, "nsrt %d", rs_hw_nodesorttime / divisor);
 				V_DrawThinString(30, 40, V_MONOSPACE | V_YELLOWMAP, s);
 				snprintf(s, sizeof s - 1, "ndrw %d", rs_hw_nodedrawtime / divisor);
@@ -614,8 +643,12 @@ static void D_Display(void)
 				V_DrawThinString(30, 60, V_MONOSPACE | V_YELLOWMAP, s);
 				snprintf(s, sizeof s - 1, "sdrw %d", rs_hw_spritedrawtime / divisor);
 				V_DrawThinString(30, 70, V_MONOSPACE | V_YELLOWMAP, s);
-				snprintf(s, sizeof s - 1, "fin  %d", rs_swaptime / divisor);
+				snprintf(s, sizeof s - 1, "ui   %d", rs_uitime / divisor);
 				V_DrawThinString(30, 80, V_MONOSPACE | V_YELLOWMAP, s);
+				snprintf(s, sizeof s - 1, "fin  %d", rs_swaptime / divisor);
+				V_DrawThinString(30, 90, V_MONOSPACE | V_YELLOWMAP, s);
+				snprintf(s, sizeof s - 1, "tic  %d", rs_tictime / divisor);
+				V_DrawThinString(30, 105, V_MONOSPACE | V_GRAYMAP, s);
 				if (cv_glbatching.value)
 				{
 					snprintf(s, sizeof s - 1, "bsrt %d", rs_hw_batchsorttime / divisor);
@@ -638,6 +671,7 @@ static void D_Display(void)
 					snprintf(s, sizeof s - 1, "ncol %d", rs_hw_numcolors);
 					V_DrawThinString(185, 30, V_MONOSPACE | V_PURPLEMAP, s);
 				}
+#endif
 			}
 			else // software specific stats
 			{
@@ -647,8 +681,12 @@ static void D_Display(void)
 				V_DrawThinString(30, 50, V_MONOSPACE | V_YELLOWMAP, s);
 				snprintf(s, sizeof s - 1, "mskd %d", rs_sw_maskedtime / divisor);
 				V_DrawThinString(30, 60, V_MONOSPACE | V_YELLOWMAP, s);
-				snprintf(s, sizeof s - 1, "fin  %d", rs_swaptime / divisor);
+				snprintf(s, sizeof s - 1, "ui   %d", rs_uitime / divisor);
 				V_DrawThinString(30, 70, V_MONOSPACE | V_YELLOWMAP, s);
+				snprintf(s, sizeof s - 1, "fin  %d", rs_swaptime / divisor);
+				V_DrawThinString(30, 80, V_MONOSPACE | V_YELLOWMAP, s);
+				snprintf(s, sizeof s - 1, "tic  %d", rs_tictime / divisor);
+				V_DrawThinString(30, 95, V_MONOSPACE | V_GRAYMAP, s);
 			}
 		}
 
@@ -667,6 +705,7 @@ tic_t rendergametic;
 void D_SRB2Loop(void)
 {
 	tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
+	static lumpnum_t gstartuplumpnum;
 
 	if (dedicated)
 		server = true;
@@ -707,7 +746,12 @@ void D_SRB2Loop(void)
 	*/
 	/* Smells like a hack... Don't fade Sonic's ass into the title screen. */
 	if (gamestate != GS_TITLESCREEN)
-		V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_PATCH));
+	{
+		gstartuplumpnum = W_CheckNumForName("STARTUP");
+		if (gstartuplumpnum == LUMPERROR)
+			gstartuplumpnum = W_GetNumForName("MISSING");
+		V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(gstartuplumpnum, PU_PATCH));
+	}
 
 	for (;;)
 	{
@@ -783,9 +827,6 @@ void D_SRB2Loop(void)
 		S_UpdateSounds(); // move positional sounds
 		S_UpdateClosedCaptions();
 
-		// check for media change, loop music..
-		I_UpdateCD();
-
 #ifdef HW3SOUND
 		HW3S_EndFrameUpdate();
 #endif
@@ -895,12 +936,12 @@ void D_StartTitle(void)
 //
 // D_AddFile
 //
-static void D_AddFile(const char *file)
+static void D_AddFile(char **list, const char *file)
 {
 	size_t pnumwadfiles;
 	char *newfile;
 
-	for (pnumwadfiles = 0; startupwadfiles[pnumwadfiles]; pnumwadfiles++)
+	for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
 		;
 
 	newfile = malloc(strlen(file) + 1);
@@ -910,16 +951,16 @@ static void D_AddFile(const char *file)
 	}
 	strcpy(newfile, file);
 
-	startupwadfiles[pnumwadfiles] = newfile;
+	list[pnumwadfiles] = newfile;
 }
 
-static inline void D_CleanFile(void)
+static inline void D_CleanFile(char **list)
 {
 	size_t pnumwadfiles;
-	for (pnumwadfiles = 0; startupwadfiles[pnumwadfiles]; pnumwadfiles++)
+	for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
 	{
-		free(startupwadfiles[pnumwadfiles]);
-		startupwadfiles[pnumwadfiles] = NULL;
+		free(list[pnumwadfiles]);
+		list[pnumwadfiles] = NULL;
 	}
 }
 
@@ -1004,7 +1045,7 @@ static void IdentifyVersion(void)
 
 	// Load the IWAD
 	if (srb2wad != NULL && FIL_ReadFileOK(srb2wad))
-		D_AddFile(srb2wad);
+		D_AddFile(startupwadfiles, srb2wad);
 	else
 		I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad);
 
@@ -1015,14 +1056,14 @@ static void IdentifyVersion(void)
 	// checking in D_SRB2Main
 
 	// Add the maps
-	D_AddFile(va(pandf,srb2waddir,"zones.pk3"));
+	D_AddFile(startupwadfiles, va(pandf,srb2waddir,"zones.pk3"));
 
 	// Add the players
-	D_AddFile(va(pandf,srb2waddir, "player.dta"));
+	D_AddFile(startupwadfiles, va(pandf,srb2waddir, "player.dta"));
 
 #ifdef USE_PATCH_DTA
 	// Add our crappy patches to fix our bugs
-	D_AddFile(va(pandf,srb2waddir,"patch.pk3"));
+	D_AddFile(startupwadfiles, va(pandf,srb2waddir,"patch.pk3"));
 #endif
 
 #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
@@ -1032,7 +1073,7 @@ static void IdentifyVersion(void)
 			const char *musicpath = va(pandf,srb2waddir,str);\
 			int ms = W_VerifyNMUSlumps(musicpath); \
 			if (ms == 1) \
-				D_AddFile(musicpath); \
+				D_AddFile(startupwadfiles, musicpath); \
 			else if (ms == 0) \
 				I_Error("File "str" has been modified with non-music/sound lumps"); \
 		}
@@ -1046,64 +1087,6 @@ static void IdentifyVersion(void)
 #endif
 }
 
-#ifdef PC_DOS
-/* ======================================================================== */
-// Code for printing SRB2's title bar in DOS
-/* ======================================================================== */
-
-//
-// Center the title string, then add the date and time of compilation.
-//
-static inline void D_MakeTitleString(char *s)
-{
-	char temp[82];
-	char *t;
-	const char *u;
-	INT32 i;
-
-	for (i = 0, t = temp; i < 82; i++)
-		*t++=' ';
-
-	for (t = temp + (80-strlen(s))/2, u = s; *u != '\0' ;)
-		*t++ = *u++;
-
-	u = compdate;
-	for (t = temp + 1, i = 11; i-- ;)
-		*t++ = *u++;
-	u = comptime;
-	for (t = temp + 71, i = 8; i-- ;)
-		*t++ = *u++;
-
-	temp[80] = '\0';
-	strcpy(s, temp);
-}
-
-static inline void D_Titlebar(void)
-{
-	char title1[82]; // srb2 title banner
-	char title2[82];
-
-	strcpy(title1, "Sonic Robo Blast 2");
-	strcpy(title2, "Sonic Robo Blast 2");
-
-	D_MakeTitleString(title1);
-
-	// SRB2 banner
-	clrscr();
-	textattr((BLUE<<4)+WHITE);
-	clreol();
-	cputs(title1);
-
-	// standard srb2 banner
-	textattr((RED<<4)+WHITE);
-	clreol();
-	gotoxy((80-strlen(title2))/2, 2);
-	cputs(title2);
-	normvideo();
-	gotoxy(1,3);
-}
-#endif
-
 static void
 D_ConvertVersionNumbers (void)
 {
@@ -1147,7 +1130,7 @@ void D_SRB2Main(void)
 	"in this program.\n\n");
 
 	// keep error messages until the final flush(stderr)
-#if !defined (PC_DOS) && !defined(NOTERMIOS)
+#if !defined(NOTERMIOS)
 	if (setvbuf(stderr, NULL, _IOFBF, 1000))
 		I_OutputMsg("setvbuf didnt work\n");
 #endif
@@ -1185,10 +1168,6 @@ void D_SRB2Main(void)
 	dedicated = M_CheckParm("-dedicated") != 0;
 #endif
 
-#ifdef PC_DOS
-	D_Titlebar();
-#endif
-
 	if (devparm)
 		CONS_Printf(M_GetText("Development mode ON.\n"));
 
@@ -1284,7 +1263,7 @@ void D_SRB2Main(void)
 				{
 					if (!W_VerifyNMUSlumps(s))
 						G_SetGameModified(true);
-					D_AddFile(s);
+					D_AddFile(startuppwads, s);
 				}
 			}
 		}
@@ -1325,8 +1304,8 @@ void D_SRB2Main(void)
 
 	// load wad, including the main wad file
 	CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n");
-	W_InitMultipleFiles(startupwadfiles, mainwads);
-	D_CleanFile();
+	W_InitMultipleFiles(startupwadfiles);
+	D_CleanFile(startupwadfiles);
 
 #ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy)
 
@@ -1362,8 +1341,6 @@ void D_SRB2Main(void)
 	// setup loading screen
 	SCR_Startup();
 
-	// we need the font of the console
-	CONS_Printf("HU_Init(): Setting up heads up display.\n");
 	HU_Init();
 
 	CON_Init();
@@ -1375,6 +1352,13 @@ void D_SRB2Main(void)
 
 	I_RegisterSysCommands();
 
+	CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n");
+	W_InitMultipleFiles(startuppwads);
+	D_CleanFile(startuppwads);
+
+	CONS_Printf("HU_LoadGraphics()...\n");
+	HU_LoadGraphics();
+
 	//--------------------------------------------------------- CONFIG.CFG
 	M_FirstLoadConfig(); // WARNING : this do a "COM_BufExecute()"
 
@@ -1398,9 +1382,6 @@ void D_SRB2Main(void)
 
 		// Set cv_renderer to the new render mode
 		CV_StealthSetValue(&cv_renderer, rendermode);
-#ifdef HWRENDER
-		CV_StealthSetValue(&cv_newrenderer, rendermode);
-#endif
 	}
 
 	wipegamestate = gamestate;
@@ -1426,10 +1407,6 @@ void D_SRB2Main(void)
 		}
 	}
 
-	// Initialize CD-Audio
-	if (M_CheckParm("-usecd") && !dedicated)
-		I_InitCD();
-
 	if (M_CheckParm("-noupload"))
 		COM_BufAddText("downloading 0\n");
 
diff --git a/src/d_net.h b/src/d_net.h
index ed4f6628476caca25493d0f66ed09f33cb021f00..ea6b5d4d9a58e6b5d8fd8f62a3ca980e2986b4e6 100644
--- a/src/d_net.h
+++ b/src/d_net.h
@@ -19,7 +19,9 @@
 #define __D_NET__
 
 // Max computers in a game
-#define MAXNETNODES (MAXPLAYERS+4)
+// 127 is probably as high as this can go, because
+// SINT8 is used for nodes sometimes >:(
+#define MAXNETNODES 127
 #define BROADCASTADDR MAXNETNODES
 #define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
 //#define NETSPLITSCREEN // Kart's splitscreen netgame feature
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 6aa168aa7680fbe804e382f71ac4142f017e9964..6f4bcdb1d26c89596c39b755dfec1243fbc239a0 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -197,186 +197,179 @@ static CV_PossibleValue_t matchboxes_cons_t[] = {{0, "Normal"}, {1, "Mystery"},
 static CV_PossibleValue_t chances_cons_t[] = {{0, "MIN"}, {9, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t pause_cons_t[] = {{0, "Server"}, {1, "All"}, {0, NULL}};
 
-consvar_t cv_showinputjoy = {"showinputjoy", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_showinputjoy = CVAR_INIT ("showinputjoy", "Off", 0, CV_OnOff, NULL);
 
 #ifdef NETGAME_DEVMODE
-static consvar_t cv_fishcake = {"fishcake", "Off", CV_CALL|CV_NOSHOWHELP|CV_RESTRICT, CV_OnOff, Fishcake_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_fishcake = CVAR_INIT ("fishcake", "Off", CV_CALL|CV_NOSHOWHELP|CV_RESTRICT, CV_OnOff, Fishcake_OnChange);
 #endif
-static consvar_t cv_dummyconsvar = {"dummyconsvar", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff,
-	DummyConsvar_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_dummyconsvar = CVAR_INIT ("dummyconsvar", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, DummyConsvar_OnChange);
 
-consvar_t cv_restrictskinchange = {"restrictskinchange", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_allowteamchange = {"allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
+consvar_t cv_allowteamchange = CVAR_INIT ("allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL);
 
-consvar_t cv_startinglives = {"startinglives", "3", CV_NETVAR|CV_CHEAT, startingliveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_startinglives = CVAR_INIT ("startinglives", "3", CV_NETVAR|CV_CHEAT, startingliveslimit_cons_t, NULL);
 
 static CV_PossibleValue_t respawntime_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "Off"}, {0, NULL}};
-consvar_t cv_respawntime = {"respawndelay", "3", CV_NETVAR|CV_CHEAT, respawntime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_respawntime = CVAR_INIT ("respawndelay", "3", CV_NETVAR|CV_CHEAT, respawntime_cons_t, NULL);
 
-consvar_t cv_competitionboxes = {"competitionboxes", "Mystery", CV_NETVAR|CV_CHEAT, competitionboxes_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_competitionboxes = CVAR_INIT ("competitionboxes", "Mystery", CV_NETVAR|CV_CHEAT, competitionboxes_cons_t, NULL);
 
 #ifdef SEENAMES
 static CV_PossibleValue_t seenames_cons_t[] = {{0, "Off"}, {1, "Colorless"}, {2, "Team"}, {3, "Ally/Foe"}, {0, NULL}};
-consvar_t cv_seenames = {"seenames", "Ally/Foe", CV_SAVE, seenames_cons_t, 0, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_allowseenames = {"allowseenames", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_seenames = CVAR_INIT ("seenames", "Ally/Foe", CV_SAVE, seenames_cons_t, 0);
+consvar_t cv_allowseenames = CVAR_INIT ("allowseenames", "Yes", CV_NETVAR, CV_YesNo, NULL);
 #endif
 
 // names
-consvar_t cv_playername = {"name", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_playername2 = {"name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_playername = CVAR_INIT ("name", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange);
+consvar_t cv_playername2 = CVAR_INIT ("name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange);
 // player colors
 UINT16 lastgoodcolor = SKINCOLOR_BLUE, lastgoodcolor2 = SKINCOLOR_BLUE;
-consvar_t cv_playercolor = {"color", "Blue", CV_CALL|CV_NOINIT, Color_cons_t, Color_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_playercolor2 = {"color2", "Orange", CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_playercolor = CVAR_INIT ("color", "Blue", CV_CALL|CV_NOINIT, Color_cons_t, Color_OnChange);
+consvar_t cv_playercolor2 = CVAR_INIT ("color2", "Orange", CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange);
 // player's skin, saved for commodity, when using a favorite skins wad..
-consvar_t cv_skin = {"skin", DEFAULTSKIN, CV_CALL|CV_NOINIT, NULL, Skin_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_skin2 = {"skin2", DEFAULTSKIN2, CV_CALL|CV_NOINIT, NULL, Skin2_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_skin = CVAR_INIT ("skin", DEFAULTSKIN, CV_CALL|CV_NOINIT, NULL, Skin_OnChange);
+consvar_t cv_skin2 = CVAR_INIT ("skin2", DEFAULTSKIN2, CV_CALL|CV_NOINIT, NULL, Skin2_OnChange);
 
 // saved versions of the above six
-consvar_t cv_defaultplayercolor = {"defaultcolor", "Blue", CV_SAVE, Color_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_defaultplayercolor2 = {"defaultcolor2", "Orange", CV_SAVE, Color_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_defaultskin = {"defaultskin", DEFAULTSKIN, CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_defaultskin2 = {"defaultskin2", DEFAULTSKIN2, CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_defaultplayercolor = CVAR_INIT ("defaultcolor", "Blue", CV_SAVE, Color_cons_t, NULL);
+consvar_t cv_defaultplayercolor2 = CVAR_INIT ("defaultcolor2", "Orange", CV_SAVE, Color_cons_t, NULL);
+consvar_t cv_defaultskin = CVAR_INIT ("defaultskin", DEFAULTSKIN, CV_SAVE, NULL, NULL);
+consvar_t cv_defaultskin2 = CVAR_INIT ("defaultskin2", DEFAULTSKIN2, CV_SAVE, NULL, NULL);
 
-consvar_t cv_skipmapcheck = {"skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_skipmapcheck = CVAR_INIT ("skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL);
 
 INT32 cv_debug;
 
-consvar_t cv_usemouse = {"use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse);
+consvar_t cv_usemouse2 = CVAR_INIT ("use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2);
 
-consvar_t cv_usejoystick = {"use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t,
-	I_InitJoystick, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_usejoystick2 = {"use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t,
-	I_InitJoystick2, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_usejoystick = CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick);
+consvar_t cv_usejoystick2 = CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2);
 #if (defined (LJOYSTICK) || defined (HAVE_SDL))
 #ifdef LJOYSTICK
-consvar_t cv_joyport = {"padport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_joyport2 = {"padport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: for later
+consvar_t cv_joyport = CVAR_INIT ("padport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL);
+consvar_t cv_joyport2 = CVAR_INIT ("padport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL); //Alam: for later
 #endif
-consvar_t cv_joyscale = {"padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_joyscale2 = {"padscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale);
+consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2);
 #else
-consvar_t cv_joyscale = {"padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save
-consvar_t cv_joyscale2 = {"padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save
+consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save
+consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save
 #endif
 #if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)
-consvar_t cv_mouse2port = {"mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mouse2opt = {"mouse2opt", "0", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mouse2port = CVAR_INIT ("mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL);
+consvar_t cv_mouse2opt = CVAR_INIT ("mouse2opt", "0", CV_SAVE, NULL, NULL);
 #else
-consvar_t cv_mouse2port = {"mouse2port", "COM2", CV_SAVE, mouse2port_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mouse2port = CVAR_INIT ("mouse2port", "COM2", CV_SAVE, mouse2port_cons_t, NULL);
 #endif
 
-consvar_t cv_matchboxes = {"matchboxes", "Normal", CV_NETVAR|CV_CHEAT, matchboxes_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_specialrings = {"specialrings", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_powerstones = {"powerstones", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_recycler =      {"tv_recycler",      "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_teleporters =   {"tv_teleporter",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_superring =     {"tv_superring",     "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_supersneakers = {"tv_supersneaker",  "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_invincibility = {"tv_invincibility", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_jumpshield =    {"tv_jumpshield",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_watershield =   {"tv_watershield",   "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ringshield =    {"tv_ringshield",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_forceshield =   {"tv_forceshield",   "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_bombshield =    {"tv_bombshield",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_1up =           {"tv_1up",           "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_eggmanbox =     {"tv_eggman",        "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_ringslinger = {"ringslinger", "No", CV_NETVAR|CV_NOSHOWHELP|CV_CALL|CV_CHEAT, CV_YesNo,
-	Ringslinger_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gravity = {"gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_soundtest = {"soundtest", "0", CV_CALL, NULL, SoundTest_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_matchboxes = CVAR_INIT ("matchboxes", "Normal", CV_NETVAR|CV_CHEAT, matchboxes_cons_t, NULL);
+consvar_t cv_specialrings = CVAR_INIT ("specialrings", "On", CV_NETVAR, CV_OnOff, NULL);
+consvar_t cv_powerstones = CVAR_INIT ("powerstones", "On", CV_NETVAR, CV_OnOff, NULL);
+
+consvar_t cv_recycler =      CVAR_INIT ("tv_recycler",      "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_teleporters =   CVAR_INIT ("tv_teleporter",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_superring =     CVAR_INIT ("tv_superring",     "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_supersneakers = CVAR_INIT ("tv_supersneaker",  "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_invincibility = CVAR_INIT ("tv_invincibility", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_jumpshield =    CVAR_INIT ("tv_jumpshield",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_watershield =   CVAR_INIT ("tv_watershield",   "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_ringshield =    CVAR_INIT ("tv_ringshield",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_forceshield =   CVAR_INIT ("tv_forceshield",   "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_bombshield =    CVAR_INIT ("tv_bombshield",    "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_1up =           CVAR_INIT ("tv_1up",           "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+consvar_t cv_eggmanbox =     CVAR_INIT ("tv_eggman",        "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL);
+
+consvar_t cv_ringslinger = CVAR_INIT ("ringslinger", "No", CV_NETVAR|CV_NOSHOWHELP|CV_CALL|CV_CHEAT, CV_YesNo, Ringslinger_OnChange);
+consvar_t cv_gravity = CVAR_INIT ("gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange);
+
+consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange);
 
 static CV_PossibleValue_t minitimelimit_cons_t[] = {{15, "MIN"}, {9999, "MAX"}, {0, NULL}};
-consvar_t cv_countdowntime = {"countdowntime", "60", CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "60", CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL);
 
-consvar_t cv_touchtag = {"touchtag", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_hidetime = {"hidetime", "30", CV_NETVAR|CV_CALL, minitimelimit_cons_t, Hidetime_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_touchtag = CVAR_INIT ("touchtag", "Off", CV_NETVAR, CV_OnOff, NULL);
+consvar_t cv_hidetime = CVAR_INIT ("hidetime", "30", CV_NETVAR|CV_CALL, minitimelimit_cons_t, Hidetime_OnChange);
 
-consvar_t cv_autobalance = {"autobalance", "Off", CV_NETVAR|CV_CALL, CV_OnOff, AutoBalance_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_teamscramble = {"teamscramble", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, teamscramble_cons_t, TeamScramble_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_scrambleonchange = {"scrambleonchange", "Off", CV_NETVAR, teamscramble_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_autobalance = CVAR_INIT ("autobalance", "Off", CV_NETVAR|CV_CALL, CV_OnOff, AutoBalance_OnChange);
+consvar_t cv_teamscramble = CVAR_INIT ("teamscramble", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, teamscramble_cons_t, TeamScramble_OnChange);
+consvar_t cv_scrambleonchange = CVAR_INIT ("scrambleonchange", "Off", CV_NETVAR, teamscramble_cons_t, NULL);
 
-consvar_t cv_friendlyfire = {"friendlyfire", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_friendlyfire = CVAR_INIT ("friendlyfire", "Off", CV_NETVAR, CV_OnOff, NULL);
+consvar_t cv_itemfinder = CVAR_INIT ("itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_OnChange);
 
 // Scoring type options
-consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR, CV_YesNo, NULL);
 
-consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_rollingdemos = CVAR_INIT ("rollingdemos", "On", CV_SAVE, CV_OnOff, NULL);
 
 static CV_PossibleValue_t timetic_cons_t[] = {{0, "Classic"}, {1, "Centiseconds"}, {2, "Mania"}, {3, "Tics"}, {0, NULL}};
-consvar_t cv_timetic = {"timerres", "Classic", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_timetic = CVAR_INIT ("timerres", "Classic", CV_SAVE, timetic_cons_t, NULL);
 
 static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}};
-consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_powerupdisplay = CVAR_INIT ("powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL);
 
 static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, {0, "None"}, {0, NULL}};
-consvar_t cv_pointlimit = {"pointlimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t,
-	PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange);
 static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}};
-consvar_t cv_timelimit = {"timelimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t,
-	TimeLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange);
 static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, NULL}};
-consvar_t cv_numlaps = {"numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t,
-	NumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_numlaps = CVAR_INIT ("numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange);
 static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
-consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange);
 
 // Point and time limits for every gametype
 INT32 pointlimits[NUMGAMETYPES];
 INT32 timelimits[NUMGAMETYPES];
 
 // log elemental hazards -- not a netvar, is local to current player
-consvar_t cv_hazardlog = {"hazardlog", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_hazardlog = CVAR_INIT ("hazardlog", "Yes", 0, CV_YesNo, NULL);
 
-consvar_t cv_forceskin = {"forceskin", "None", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_downloading = {"downloading", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_allowexitlevel = {"allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_forceskin = CVAR_INIT ("forceskin", "None", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange);
+consvar_t cv_downloading = CVAR_INIT ("downloading", "On", 0, CV_OnOff, NULL);
+consvar_t cv_allowexitlevel = CVAR_INIT ("allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL);
 
-consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_killingdead = CVAR_INIT ("killingdead", "Off", CV_NETVAR, CV_OnOff, NULL);
 
-consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
+consvar_t cv_netstat = CVAR_INIT ("netstat", "Off", 0, CV_OnOff, NULL); // show bandwidth statistics
 static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
-consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange);
 static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
-consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange);
+consvar_t cv_maxping = CVAR_INIT ("maxping", "0", CV_SAVE, CV_Unsigned, NULL);
 
 static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
-consvar_t cv_pingtimeout = {"pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_pingtimeout = CVAR_INIT ("pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL);
 
 // show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping)
 static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
-consvar_t cv_showping = {"showping", "Warning", CV_SAVE, showping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_showping = CVAR_INIT ("showping", "Warning", CV_SAVE, showping_cons_t, NULL);
 
 // Intermission time Tails 04-19-2002
 static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
-consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_inttime = CVAR_INIT ("inttime", "10", CV_NETVAR, inttime_cons_t, NULL);
 
 static CV_PossibleValue_t coopstarposts_cons_t[] = {{0, "Per-player"}, {1, "Shared"}, {2, "Teamwork"}, {0, NULL}};
-consvar_t cv_coopstarposts = {"coopstarposts", "Per-player", CV_NETVAR|CV_CALL, coopstarposts_cons_t, CoopStarposts_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_coopstarposts = CVAR_INIT ("coopstarposts", "Per-player", CV_NETVAR|CV_CALL, coopstarposts_cons_t, CoopStarposts_OnChange);
 
 static CV_PossibleValue_t cooplives_cons_t[] = {{0, "Infinite"}, {1, "Per-player"}, {2, "Avoid Game Over"}, {3, "Single pool"}, {0, NULL}};
-consvar_t cv_cooplives = {"cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_CHEAT, cooplives_cons_t, CoopLives_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_cooplives = CVAR_INIT ("cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_CHEAT, cooplives_cons_t, CoopLives_OnChange);
 
 static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
-consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_advancemap = CVAR_INIT ("advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL);
 
 static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}};
-consvar_t cv_playersforexit = {"playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_playersforexit = CVAR_INIT ("playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL);
 
-consvar_t cv_exitmove = {"exitmove", "On", CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_exitmove = CVAR_INIT ("exitmove", "On", CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange);
 
-consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_runscripts = CVAR_INIT ("runscripts", "Yes", 0, CV_YesNo, NULL);
 
-consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_pause = CVAR_INIT ("pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL);
+consvar_t cv_mute = CVAR_INIT ("mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange);
 
-consvar_t cv_sleep = {"cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL};
+consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL);
 
 char timedemo_name[256];
 boolean timedemo_csv;
@@ -861,17 +854,10 @@ void D_RegisterClientCommands(void)
 	CV_RegisterVar(&cv_midimusicvolume);
 	CV_RegisterVar(&cv_numChannels);
 
-	// i_cdmus.c
-	CV_RegisterVar(&cd_volume);
-	CV_RegisterVar(&cdUpdate);
-
 	// screen.c
 	CV_RegisterVar(&cv_fullscreen);
 	CV_RegisterVar(&cv_renderview);
 	CV_RegisterVar(&cv_renderer);
-#ifdef HWRENDER
-	CV_RegisterVar(&cv_newrenderer);
-#endif
 	CV_RegisterVar(&cv_scr_depth);
 	CV_RegisterVar(&cv_scr_width);
 	CV_RegisterVar(&cv_scr_height);
@@ -1130,6 +1116,8 @@ static void SetPlayerName(INT32 playernum, char *newname)
 			if (netgame)
 				HU_AddChatText(va("\x82*%s renamed to %s", player_names[playernum], newname), false);
 
+			player_name_changes[playernum]++;
+
 			strcpy(player_names[playernum], newname);
 		}
 	}
@@ -1306,7 +1294,12 @@ static void SendNameAndColor(void)
 	snacpending++;
 
 	// Don't change name if muted
-	if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
+	if (player_name_changes[consoleplayer] >= MAXNAMECHANGES)
+	{
+		CV_StealthSet(&cv_playername, player_names[consoleplayer]);
+		HU_AddChatText("\x85*You must wait to change your name again", false);
+	}
+	else if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
 		CV_StealthSet(&cv_playername, player_names[consoleplayer]);
 	else // Cleanup name if changing it
 		CleanupPlayerName(consoleplayer, cv_playername.zstring);
@@ -1467,8 +1460,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 	skin = READUINT8(*cp);
 
 	// set name
-	if (strcasecmp(player_names[playernum], name) != 0)
-		SetPlayerName(playernum, name);
+	if (player_name_changes[playernum] < MAXNAMECHANGES)
+	{
+		if (strcasecmp(player_names[playernum], name) != 0)
+			SetPlayerName(playernum, name);
+	}
 
 	// set color
 	p->skincolor = color % numskincolors;
diff --git a/src/d_player.h b/src/d_player.h
index 26086a331b03c6118251153b143aacb309f6ed50..bd33ebae57666e402b8f81b94a14abb1726f952e 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -115,7 +115,7 @@ typedef enum
 
 	// True if button down last tic.
 	PF_ATTACKDOWN = 1<<7,
-	PF_USEDOWN    = 1<<8,
+	PF_SPINDOWN   = 1<<8,
 	PF_JUMPDOWN   = 1<<9,
 	PF_WPNDOWN    = 1<<10,
 
diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h
index 0a8012bb15820eb3b9b151729b522d0910ab95af..2a5ef09818f05fb001b0b03200ca092e47b77607 100644
--- a/src/d_ticcmd.h
+++ b/src/d_ticcmd.h
@@ -31,7 +31,7 @@ typedef enum
 	BT_WEAPONPREV = 1<<5,
 
 	BT_ATTACK     = 1<<6, // shoot rings
-	BT_USE        = 1<<7, // spin
+	BT_SPIN       = 1<<7,
 	BT_CAMLEFT    = 1<<8, // turn camera left
 	BT_CAMRIGHT   = 1<<9, // turn camera right
 	BT_TOSSFLAG   = 1<<10,
diff --git a/src/dehacked.c b/src/dehacked.c
index bb5e811ff679b8ab0b665061900882db83172737..80a0ad0ff3e77b123ac8c6c0c1c640b89712460b 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -48,12 +48,6 @@
 #include "hardware/hw_light.h"
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-//int	snprintf(char *str, size_t n, const char *fmt, ...);
-int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
 // Free slot names
 // The crazy word-reading stuff uses these.
 static char *FREE_STATES[NUMSTATEFREESLOTS];
@@ -9082,7 +9076,7 @@ static const char *const PLAYERFLAG_LIST[] = {
 
 	// True if button down last tic.
 	"ATTACKDOWN",
-	"USEDOWN",
+	"SPINDOWN",
 	"JUMPDOWN",
 	"WPNDOWN",
 
@@ -9516,6 +9510,7 @@ struct {
 	{"RING_DIST",RING_DIST},
 	{"PUSHACCEL",PUSHACCEL},
 	{"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into.
+	{"MODVERSION",MODVERSION}, // or what version of the mod this is.
 	{"CODEBASE",CODEBASE}, // or what release of SRB2 this is.
 	{"NEWTICRATE",NEWTICRATE}, // TICRATE*NEWTICRATERATIO
 	{"NEWTICRATERATIO",NEWTICRATERATIO},
@@ -9969,7 +9964,7 @@ struct {
 	{"BT_WEAPONNEXT",BT_WEAPONNEXT},
 	{"BT_WEAPONPREV",BT_WEAPONPREV},
 	{"BT_ATTACK",BT_ATTACK}, // shoot rings
-	{"BT_USE",BT_USE}, // spin
+	{"BT_SPIN",BT_SPIN},
 	{"BT_CAMLEFT",BT_CAMLEFT}, // turn camera left
 	{"BT_CAMRIGHT",BT_CAMRIGHT}, // turn camera right
 	{"BT_TOSSFLAG",BT_TOSSFLAG},
@@ -10842,6 +10837,11 @@ static inline int lib_getenum(lua_State *L)
 			lua_pushinteger(L, (lua_Integer)PF_FULLSTASIS);
 			return 1;
 		}
+		else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release...
+		{
+			lua_pushinteger(L, (lua_Integer)PF_SPINDOWN);
+			return 1;
+		}
 		if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
 		return 0;
 	}
@@ -11108,6 +11108,12 @@ static inline int lib_getenum(lua_State *L)
 		return 0;
 	}
 
+	if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release...
+	{
+		lua_pushinteger(L, (lua_Integer)BT_SPIN);
+		return 1;
+	}
+
 	for (i = 0; INT_CONST[i].n; i++)
 		if (fastcmp(word,INT_CONST[i].n)) {
 			lua_pushinteger(L, INT_CONST[i].v);
diff --git a/src/djgppdos/Makefile.cfg b/src/djgppdos/Makefile.cfg
deleted file mode 100644
index 857a7267bc88bfe08038b3c4bb7f575223997412..0000000000000000000000000000000000000000
--- a/src/djgppdos/Makefile.cfg
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# djgppdos/makefile.cfg for SRB2/DOS
-#
-
-#
-#now for the DOS stuff, go DOS!
-#
-
-	# options
-	OPTS=-DPC_DOS
-	WFLAGS+=-Wno-cast-qual
-	NOHW=1
-	NOHS=1
-	PNG_CFLAGS=
-	PNG_LDFLAGS=-lpng -lz
-
-ifdef WATTCP
-	OPTS+=-DWATTCP
-	NOOBJDUMP=1
-endif
-
-#ifdef DEBUGMODE
-	LIBS=-lalld
-#else
-#	LIBS=-lalleg
-#endif
-
-ifndef NONET
-ifdef WATTCP
-	LIBS+=-lwatt
-else
-	LIBS+=-lsocket
-endif
-endif
-
-ifdef RDB
-	LIBS+=-lgdbst -ldzcom
-	OPTS+=-DREMOTE_DEBUGGING
-endif
-
-	OBJS=$(OBJDIR)/i_video.o $(OBJDIR)/vid_vesa.o
-
-	# name of the exefile
-ifdef WATTCP
-	EXENAME?=srb2dos.exe
-else
-	EXENAME?=srb2w16.exe
-endif
diff --git a/src/djgppdos/bcd.c b/src/djgppdos/bcd.c
deleted file mode 100644
index 6a91c707fa4bbc4b8591281bbd3c38214f7a78a6..0000000000000000000000000000000000000000
--- a/src/djgppdos/bcd.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/* bcd.c -- Brennan's CD-ROM Audio Playing Library
-   by Brennan Underwood, http://brennan.home.ml.org/ */
-#include <dos.h>
-#include <dpmi.h>
-#include <go32.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <strings.h>
-#ifdef STANDALONE
-#include <conio.h> /* for getch() */
-#endif
-
-#include "bcd.h"
-
-typedef struct {
-  int is_audio;
-  int start, end, len;
-} Track;
-
-static int mscdex_version;
-static int first_drive;
-static int num_tracks;
-static int lowest_track, highest_track;
-static int audio_length;
-
-#ifdef STATIC_TRACKS
-static Track tracks[99];
-#else
-static Track *tracks;
-#endif
-
-static int dos_mem_segment, dos_mem_selector = -1;
-
-int _status, _error, _error_code;
-const char *_bcd_error = NULL;
-
-#define RESET_ERROR (_error = _error_code = 0)
-#define ERROR_BIT (1 << 15)
-#define BUSY_BIT (1 << 9)
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#pragma pack(1)
-
-/* I know 'typedef struct {} bleh' is a bad habit, but... */
-typedef struct {
-  unsigned char len;
-  unsigned char unit;
-  unsigned char command;
-  unsigned short status;
-  unsigned char reserved[8];
-} ATTRPACK RequestHeader;
-
-typedef struct {
-  RequestHeader request_header;
-  unsigned char descriptor;
-  unsigned long address;
-  unsigned short len;
-  unsigned short secnum;
-  unsigned long ptr;
-} ATTRPACK IOCTLI;
-
-typedef struct {
-  unsigned char control;
-  unsigned char lowest;
-  unsigned char highest;
-  char total[4];
-} ATTRPACK DiskInfo;
-
-typedef struct {
-  unsigned char control;
-  unsigned char track_number;
-  char start[4];
-  unsigned char info;
-} ATTRPACK TrackInfo;
-
-typedef struct {
-  RequestHeader request;
-  unsigned char mode;
-  unsigned long start;
-  unsigned long len;
-} ATTRPACK PlayRequest;
-
-typedef struct {
-  RequestHeader request;
-} ATTRPACK StopRequest;
-
-typedef struct {
-  RequestHeader request;
-} ATTRPACK ResumeRequest;
-
-typedef struct {
-  unsigned char control;
-  unsigned char input0;
-  unsigned char volume0;
-  unsigned char input1;
-  unsigned char volume1;
-  unsigned char input2;
-  unsigned char volume2;
-  unsigned char input3;
-  unsigned char volume3;
-} ATTRPACK VolumeRequest;
-
-typedef struct {
-  unsigned char control;
-  unsigned char fn;
-} ATTRPACK LockRequest;
-
-typedef struct {
-  unsigned char control;
-  unsigned char mbyte;
-} ATTRPACK MediaChangedRequest;
-
-typedef struct {
-  unsigned char control;
-  unsigned long status;
-} ATTRPACK StatusRequest;
-
-typedef struct {
-  unsigned char control;
-  unsigned char mode;
-  unsigned long loc;
-} ATTRPACK PositionRequest;
-
-#pragma pack()
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-const char *bcd_error(void) {
-  static char retstr[132];
-  const char *errorcodes[] = {
-    "Write-protect violation",
-    "Unknown unit",
-    "Drive not ready",
-    "Unknown command",
-    "CRC error",
-    "Bad drive request structure length",
-    "Seek error",
-    "Unknown media",
-    "Sector not found",
-    "Printer out of paper: world coming to an end",/* I mean really, on a CD? */
-    "Write fault",
-    "Read fault",
-    "General failure",
-    "Reserved",
-    "Reserved",
-    "Invalid disk change"
-  };
-  *retstr = 0;
-  if (_error != 0) {
-    strcat(retstr, "Device error: ");
-    if (_error_code < 0 || _error_code > 0xf)
-      strcat(retstr, "Invalid error");
-    else
-      strcat(retstr, errorcodes[_error_code]);
-    strcat(retstr, "  ");
-  }
-  if (_bcd_error != NULL) {
-    if (*retstr) strcat(retstr, ", ");
-    strcat(retstr, "BCD error: ");
-    strcat(retstr, _bcd_error);
-  }
-  return retstr;
-}
-
-/* DOS IOCTL w/ command block */
-static void bcd_ioctl(IOCTLI *ioctli, void *command, int len) {
-  int ioctli_len = sizeof (IOCTLI);
-  unsigned long command_address = dos_mem_segment << 4;
-  __dpmi_regs regs;
-
-  memset(&regs, 0, sizeof regs);
-  regs.x.es = (__tb >> 4) & 0xffff;
-  regs.x.ax = 0x1510;
-  regs.x.bx = __tb & 0xf;
-  regs.x.cx = first_drive;
-  ioctli->address = dos_mem_segment << 16;
-  ioctli->len = len;
-  dosmemput(ioctli, ioctli_len, __tb);		/* put ioctl into dos area */
-  dosmemput(command, len, command_address);	/* and command too */
-  if (__dpmi_int(0x2f, &regs) == -1) {
-    _bcd_error = "__dpmi_int() failed";
-    return;
-  }
-  dosmemget(__tb, ioctli_len, ioctli);		/* retrieve results */
-  dosmemget(command_address, len, command);
-  _status = ioctli->request_header.status;
-  if (_status & ERROR_BIT) {
-    _error = TRUE;
-    _error_code = _status & 0xff;
-  } else {
-    _error = FALSE;
-    _error_code = 0;
-  }
-}
-
-/* no command block */
-FUNCINLINE static ATTRINLINE void bcd_ioctl2(void *cmd, int len) {
-  __dpmi_regs regs;
-  memset(&regs, 0, sizeof regs);
-  regs.x.es = (__tb >> 4) & 0xffff;
-  regs.x.ax = 0x1510;
-  regs.x.bx = __tb & 0xf;
-  regs.x.cx = first_drive;
-  dosmemput(cmd, len, __tb); /* put ioctl block in dos arena */
-  if (__dpmi_int(0x2f, &regs) == -1) {
-    _bcd_error = "__dpmi_int() failed";
-    return;
-  }
-  /* I hate to have no error capability for ioctl2 but the command block
-     doesn't necessarily have a status field */
-  RESET_ERROR;
-}
-
-FUNCINLINE static ATTRINLINE int red2hsg(char *r) {
-  return r[0] + r[1]*75 + r[2]*4500 - 150;
-}
-
-int bcd_now_playing(void) {
-  int i, loc = bcd_audio_position();
-  _bcd_error = NULL;
-  if (!bcd_audio_busy()) {
-    _bcd_error = "Audio not playing";
-    return 0;
-  }
-  if (
-#ifndef STATIC_TRACKS
-  tracks == NULL &&
-#endif
-   !bcd_get_audio_info())
-    return 0;
-  for (i = lowest_track; i <= highest_track; i++) {
-    if (loc >= tracks[i].start && loc <= tracks[i].end) return i;
-  }
-  /* some bizarre location? */
-  _bcd_error = "Head outside of bounds";
-  return 0;
-}
-
-/* handles the setup for CD-ROM audio interface */
-int bcd_open(void) {
-  __dpmi_regs regs;
-  _bcd_error = NULL;
-
-  /* disk I/O wouldn't work anyway if you set sizeof tb this low, but... */
-  if (_go32_info_block.size_of_transfer_buffer < 4096) {
-    _bcd_error = "Transfer buffer too small";
-    return 0;
-  }
-
-  memset(&regs, 0, sizeof regs);
-  regs.x.ax = 0x1500;
-  regs.x.bx = 0x0;
-  __dpmi_int(0x2f, &regs);
-  if (regs.x.bx == 0) {	/* abba no longer lives */
-    _bcd_error = "MSCDEX not found";
-    return 0;
-  }
-
-  first_drive = regs.x.cx; /* use the first drive */
-
-  /* check for mscdex at least 2.0 */
-  memset(&regs, 0, sizeof regs);
-  regs.x.ax = 0x150C;
-  __dpmi_int(0x2f, &regs);
-  if (regs.x.bx == 0) {
-    _bcd_error = "MSCDEX version < 2.0";
-    return 0;
-  }
-  mscdex_version = regs.x.bx;
-
-  /* allocate 256 bytes of dos memory for the command blocks */
-  if ((dos_mem_segment = __dpmi_allocate_dos_memory(16, &dos_mem_selector))<0) {
-    _bcd_error = "Could not allocate 256 bytes of DOS memory";
-    return 0;
-  }
-
-  return mscdex_version;
-}
-
-/* Shuts down CD-ROM audio interface */
-int bcd_close(void) {
-  _bcd_error = NULL;
-  if (dos_mem_selector != -1) {
-    __dpmi_free_dos_memory(dos_mem_selector);
-    dos_mem_selector = -1;
-  }
-#ifndef STATIC_TRACKS
-  if (tracks) free(tracks);
-  tracks = NULL;
-#endif
-  RESET_ERROR;
-  return 1;
-}
-
-int bcd_open_door(void) {
-  IOCTLI ioctli;
-  char eject = 0;
-  _bcd_error = NULL;
-  memset(&ioctli, 0, sizeof ioctli);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 12;
-  ioctli.len = 1;
-  bcd_ioctl(&ioctli, &eject, sizeof eject);
-  if (_error) return 0;
-  return 1;
-}
-
-int bcd_close_door(void) {
-  IOCTLI ioctli;
-  char closeit = 5;
-  _bcd_error = NULL;
-  memset(&ioctli, 0, sizeof ioctli);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 12;
-  ioctli.len = 1;
-  bcd_ioctl(&ioctli, &closeit, sizeof closeit);
-  if (_error) return 0;
-  return 1;
-}
-
-int bcd_lock(int fn) {
-  IOCTLI ioctli;
-  LockRequest req;
-  _bcd_error = NULL;
-  memset(&ioctli, 0, sizeof ioctli);
-  memset(&req, 0, sizeof req);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 12;
-  ioctli.len = sizeof req;
-  req.control = 1;
-  req.fn = fn ? 1 : 0;
-  bcd_ioctl(&ioctli, &req, sizeof req);
-  if (_error) return 0;
-  return 1;
-}
-
-
-int bcd_disc_changed(void) {
-  IOCTLI ioctli;
-  MediaChangedRequest req;
-  _bcd_error = NULL;
-  memset(&ioctli, 0, sizeof ioctli);
-  memset(&req, 0, sizeof req);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 3;
-  ioctli.len = sizeof req;
-  req.control = 9;
-  bcd_ioctl(&ioctli, &req, sizeof req);
-  return req.mbyte;
-}
-
-int bcd_reset(void) {
-  IOCTLI ioctli;
-  char reset = 2;
-  _bcd_error = NULL;
-
-  memset(&ioctli, 0, sizeof ioctli);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 12;
-  ioctli.len = 1;
-  bcd_ioctl(&ioctli, &reset, sizeof reset);
-  if (_error) return 0;
-  return 1;
-}
-
-int bcd_device_status(void) {
-  IOCTLI ioctli;
-  StatusRequest req;
-  _bcd_error = NULL;
-  memset(&ioctli, 0, sizeof ioctli);
-  memset(&req, 0, sizeof req);
-  ioctli.request_header.len = sizeof ioctli; // ok
-  ioctli.request_header.command = 3;
-  ioctli.len = sizeof req;
-  req.control = 6;
-  bcd_ioctl(&ioctli, &req, sizeof req);
-  return req.status;
-}
-
-static inline int bcd_get_status_word(void) {
-  IOCTLI ioctli;
-  DiskInfo disk_info;
-
-  /* get cd info as an excuse to get a look at the status word */
-  memset(&disk_info, 0, sizeof disk_info);
-  memset(&ioctli, 0, sizeof ioctli);
-
-  ioctli.request_header.len = 26;
-  ioctli.request_header.command = 3;
-  ioctli.len = 7;
-  disk_info.control = 10;
-  bcd_ioctl(&ioctli, &disk_info, sizeof disk_info);
-  return _status;
-}
-
-int bcd_audio_busy(void) {
-  _bcd_error = NULL;
-  /* If the door is open, then the head is busy, and so the busy bit is
-     on. It is not, however, playing audio. */
-  if (bcd_device_status() & BCD_DOOR_OPEN)
-    return 0;
-
-  bcd_get_status_word();
-  if (_error) return -1;
-  return (_status & BUSY_BIT) ? 1 : 0;
-}
-
-int bcd_audio_position(void) {
-  IOCTLI ioctli;
-  PositionRequest req;
-  _bcd_error = NULL;
-  memset(&ioctli, 0, sizeof ioctli);
-  memset(&req, 0, sizeof req);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 3;
-  ioctli.len = sizeof req;
-  req.control = 1;
-  bcd_ioctl(&ioctli, &req, sizeof req);
-  return req.loc;
-}
-
-/* Internal function to get track info */
-static inline void bcd_get_track_info(int n, Track *t) {
-  IOCTLI ioctli;
-  TrackInfo info;
-
-  memset(&ioctli, 0, sizeof ioctli);
-  memset(&info, 0, sizeof info);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 3;
-  info.control = 11;
-  info.track_number = n;
-  bcd_ioctl(&ioctli, &info, sizeof info);
-  t->start = red2hsg(info.start);
-  if (info.info & 64)
-    t->is_audio = 0;
-  else
-    t->is_audio = 1;
-}
-
-int bcd_get_audio_info(void) {
-  IOCTLI ioctli;
-  DiskInfo disk_info;
-  int i;
-
-
-  _bcd_error = NULL;
-#ifndef STATIC_TRACKS
-  if (tracks) free(tracks);
-  tracks = NULL;
-#endif
-
-  memset(&disk_info, 0, sizeof disk_info);
-  memset(&ioctli, 0, sizeof ioctli);
-
-  ioctli.request_header.len = 26;
-  ioctli.request_header.command = 3;
-  ioctli.len = 7;
-  disk_info.control = 10;
-  bcd_ioctl(&ioctli, &disk_info, sizeof disk_info);
-  if (_error) return 0;
-
-  lowest_track = disk_info.lowest;
-  highest_track = disk_info.highest;
-  num_tracks = disk_info.highest - disk_info.lowest + 1;
-
-#ifndef STATIC_TRACKS
-  //tracks = calloc(num_tracks, sizeof (Track));
-  /* alloc max space in order to attempt to avoid possible overrun bug */
-  tracks = calloc(highest_track+1, sizeof (Track));
-  if (tracks == NULL) {
-    _bcd_error = "Out of memory allocating tracks\n";
-    return 0;
-  }
-#endif
-
-  /* get track starts */
-  for (i = lowest_track; i <= highest_track; i++)
-    bcd_get_track_info(i, tracks+i);
-
-  /* figure out track ends */
-  for (i = lowest_track; i < highest_track; i++)
-    tracks[i].end = tracks[i+1].start-1;
-  audio_length = red2hsg(disk_info.total);
-  tracks[i].end = audio_length;
-  for (i = lowest_track; i <= highest_track; i++)
-    tracks[i].len = tracks[i].end - tracks[i].start;
-
-  return num_tracks;
-}
-
-int bcd_get_track_address(int trackno, int *start, int *len) {
-  _bcd_error = NULL;
-  //if (trackno >= num_tracks+1 || trackno <= 0) {
-  if (trackno < lowest_track || trackno > highest_track) {
-    _bcd_error  = "Track out of range";
-    *start = *len = 0;
-    return 0;
-  }
-  *start = tracks[trackno].start;
-  *len = tracks[trackno].len;
-  return 1;
-}
-
-int bcd_track_is_audio(int trackno) {
-  //if (trackno >= num_tracks+1 || trackno <= 0) {
-  if (trackno < lowest_track || trackno > highest_track) {
-    _bcd_error = "Track out of range";
-    return 0;
-  }
-  return tracks[trackno].is_audio;
-}
-
-int bcd_set_volume(int volume) {
-  IOCTLI ioctli;
-  VolumeRequest v;
-
-  _bcd_error = NULL;
-  if (volume > 255) volume = 255;
-  else if (volume < 0) volume = 0;
-  memset(&ioctli, 0, sizeof ioctli);
-  ioctli.request_header.len = sizeof ioctli;
-  ioctli.request_header.command = 12;
-  ioctli.len = sizeof v;
-  v.control = 3;
-  v.volume0 = volume;
-  v.input0 = 0;
-  v.volume1 = volume;
-  v.input1 = 1;
-  v.volume2 = volume;
-  v.input2 = 2;
-  v.volume3 = volume;
-  v.input3 = 3;
-
-  bcd_ioctl(&ioctli, &v, sizeof v);
-  if (_error) return 0;
-  return 1;
-}
-
-int bcd_play(int location, int frames) {
-  PlayRequest cmd;
-  memset(&cmd, 0, sizeof cmd);
-
-  _bcd_error = NULL;
-  /* the following should be in user code, but it'll fail otherwise */
-  if (bcd_audio_busy())
-    bcd_stop();
-
-  cmd.request.len = sizeof cmd;
-  cmd.request.command = 132;
-  cmd.start = location;
-  cmd.len = frames;
-  bcd_ioctl2(&cmd, sizeof cmd);
-  if (_error) return 0;
-  return 1;
-}
-
-int bcd_play_track(int trackno) {
-  _bcd_error = NULL;
-  if (!bcd_get_audio_info()) return 0;
-
-  if (trackno < lowest_track || trackno > highest_track) {
-    _bcd_error = "Track out of range";
-    return 0;
-  }
-
-  if (! tracks[trackno].is_audio) {
-    _bcd_error = "Not an audio track";
-    return 0;
-  }
-
-  return bcd_play(tracks[trackno].start, tracks[trackno].len);
-}
-
-int bcd_stop(void) {
-  StopRequest cmd;
-  _bcd_error = NULL;
-  memset(&cmd, 0, sizeof cmd);
-  cmd.request.len = sizeof cmd;
-  cmd.request.command = 133;
-  bcd_ioctl2(&cmd, sizeof cmd);
-  if (_error) return 0;
-  return 1;
-}
-
-int bcd_resume(void) {
-  ResumeRequest cmd;
-  _bcd_error = NULL;
-  memset(&cmd, 0, sizeof cmd);
-  cmd.request.len = sizeof cmd;
-  cmd.request.command = 136;
-  bcd_ioctl2(&cmd, sizeof cmd);
-  if (_error) return 0;
-  return 1;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef STANDALONE
-static char *card(int c) {
-  return c == 1 ? "" : "s";
-}
-
-static void print_hsg(int hsg) {
-  int hours, minutes, seconds;
-  seconds = hsg / 75;
-  minutes = seconds / 60;
-  seconds %= 60;
-  hours = minutes / 60;
-  minutes %= 60;
-  printf("%2d:%02d:%02d", hours, minutes, seconds);
-}
-
-static void print_binary(int v, int len) {
-  for (;len;len--)
-    printf("%d", (v & (1 << len)) ? 1 : 0);
-}
-
-int main(int argc, char *argv[]) {
-  int i, n1, n2, t;
-
-  if (!bcd_open()) {
-    fprintf(stderr, "Couldn't open CD-ROM drive. %s\n", bcd_error());
-    exit(0);
-  }
-
-  for (i = 1; i < argc; i++) {
-    if (*argv[i] == '-') strcpy(argv[i], argv[i]+1);
-    if (!strcmp(argv[i], "open") || !strcmp(argv[i], "eject")) {
-      bcd_open_door();
-    } else if (!strcmp(argv[i], "close")) {
-      bcd_close_door();
-    } else if (!strcmp(argv[i], "sleep")) {
-      if (++i >= argc) break;
-      sleep(atoi(argv[i]));
-    } else if (!strcmp(argv[i], "list")) {
-      int nd = 0, na = 0, audio_time = 0;
-      if (!bcd_get_audio_info()) {
-        printf("Error getting audio info\n");
-      } else if (lowest_track == 0) {
-        printf("No audio tracks\n");
-      } else {
-        for (t = lowest_track; t <= highest_track; t++) {
-          printf("Track %2d: ", t);
-          print_hsg(tracks[t].start);
-          printf(" -> ");
-          print_hsg(tracks[t].end);
-          printf(" (");
-          print_hsg(tracks[t].len);
-          if (tracks[t].is_audio) {
-            na++;
-            printf(") audio");
-            audio_time += tracks[t].len;
-          } else {
-            nd++;
-            printf(") data ");
-          }
-          printf(" (HSG: %06d->%06d)\n", tracks[t].start, tracks[t].end);
-        }
-        printf("%d audio track%s, %d data track%s\n", na, card(na), nd, card(nd));
-        if (audio_time) {
-          printf("Audio time: ");
-          print_hsg(audio_time);
-          printf("\n");
-        }
-      }
-    } else if (!strcmp(argv[i], "lock")) {
-      bcd_lock(1);
-    } else if (!strcmp(argv[i], "pladdr")) {
-      if (++i >= argc) break;
-      n1 = atoi(argv[i]);
-      if (++i >= argc) break;
-      n2 = atoi(argv[i]);
-      printf("Playing frame %d to frame %d\n", n1, n2);
-      bcd_play(n1, n2-n1);
-    } else if (!strcmp(argv[i], "play")) {
-      if (++i >= argc) break;
-      if (bcd_audio_busy()) {
-        bcd_stop();
-        delay(1000);
-      }
-      n1 = atoi(argv[i]);
-      printf("Playing track %d\n", n1);
-      bcd_play_track(n1);
-    } else if (!strcmp(argv[i], "reset")) {
-      bcd_reset();
-    } else if (!strcmp(argv[i], "resume")) {
-      bcd_resume();
-    } else if (!strcmp(argv[i], "status")) {
-      int s;
-      s = bcd_device_status();
-      printf("MSCDEX version %d.%d\n", mscdex_version >> 8,
-             mscdex_version & 0xff);
-      printf("Device status word '");
-      print_binary(s, 16);
-      printf("'\nDoor is %sopen\n", s & BCD_DOOR_OPEN ? "" : "not ");
-      printf("Door is %slocked\n", s & BCD_DOOR_UNLOCKED ? "not " : "");
-      printf("Audio is %sbusy\n", bcd_audio_busy() ? "" : "not ");
-      s = bcd_disc_changed();
-      if (s == BCD_DISC_UNKNOWN) printf("Media change status unknown\n");
-      else printf("Media has %schanged\n",
-           (s == BCD_DISC_CHANGED) ? "" : "not ");
-    } else if (!strcmp(argv[i], "stop")) {
-      bcd_stop();
-    } else if (!strcmp(argv[i], "unlock")) {
-      bcd_lock(0);
-    } else if (!strcmp(argv[i], "volume")) {
-      bcd_set_volume(atoi(argv[++i]));
-    } else if (!strcmp(argv[i], "wait")) {
-      while (bcd_audio_busy()) {
-        int n = bcd_now_playing();
-        if (n == 0) break;
-        printf("%2d: ", n);
-        print_hsg(bcd_audio_position() - tracks[n].start);
-        printf("\r");
-        fflush(stdout);
-        delay(100);
-        if (kbhit() && getch() == 27) break;
-      }
-      printf("\n");
-    } else if (!strcmp(argv[i], "help") || !strcmp(argv[i], "usage")) {
-      printf("BCD version %x.%x\n" \
-             "Usage: BCD {commands}\n" \
-             "Valid commands:\n" \
-             "\tclose		- close door/tray\n" \
-             "\tdelay {n}	- delay {n} seconds\n" \
-             "\tlist		- list track info\n" \
-             "\tlock		- lock door/tray\n" \
-             "\topen		- open door/tray\n" \
-             "\tpladdr {n1} {n2}- play frame {n1} to {n2}\n" \
-             "\tplay {n}	- play track {n}\n" \
-             "\treset		- reset the drive\n" \
-             "\tresume		- resume from last stop\n" \
-             "\tstatus		- show drive status\n" \
-             "\tstop		- stop audio playback\n" \
-             "\tunlock		- unlock door/tray\n" \
-             "\tvolume {n}	- set volume to {n} where 0 <= {n} <= 255\n",
-             BCD_VERSION >> 8, BCD_VERSION & 0xff);
-    } else
-      printf("Unknown command '%s'\n", argv[i]);
-    if (_error || _bcd_error) printf("%s\n", bcd_error());
-  }
-  bcd_close();
-  exit(0);
-}
-#endif
diff --git a/src/djgppdos/bcd.h b/src/djgppdos/bcd.h
deleted file mode 100644
index 3997128a2715e52fc6e284bf93b8a6a0738ebaea..0000000000000000000000000000000000000000
--- a/src/djgppdos/bcd.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* bcd.h -- header file for BCD, a CD-ROM audio playing library for DJGPP
-   by Brennan Underwood, http://brennan.home.ml.org/ */
-#ifndef _BCD_H
-#define _BCD_H
-
-#define BCD_VERSION 0x0103
-
-/* Installation and setup functions */
-/* Call this first! */
-int bcd_open(void);
-/* Call before exit. */
-int bcd_close(void);
-
-/* open door, unlocking first if necessary */
-int bcd_open_door(void);
-/* close door */
-int bcd_close_door(void);
-
-/* pass 1 to lock door, 0 to unlock */
-int bcd_lock(int);
-
-/* returns one of the following 3 #defined symbols */
-int bcd_disc_changed(void);
-#define BCD_DISC_CHANGED	0xff
-#define BCD_DISC_NOT_CHANGED	1
-#define BCD_DISC_UNKNOWN	0
-
-/* perform a device reset */
-int bcd_reset(void);
-
-/* compare the returned status int to the following bits */
-int bcd_device_status(void);
-#define BCD_DOOR_OPEN		1
-#define BCD_DOOR_UNLOCKED	2
-#define BCD_SUPPORT_COOKED	4
-#define BCD_READ_ONLY		8
-#define BCD_DATA_READ_ONLY	16
-#define BCD_SUPPORT_INTERLEAVE	32
-
-/* returns 1 if audio is currently playing, 0 otherwise. -1 on error */
-int bcd_audio_busy(void);
-/* current head position in frames */
-int bcd_audio_position(void);
-/* convenience function, if audio busy, returns track# playing now */
-int bcd_now_playing(void);
-
-/* query MSCDEX for track list when disc changed or just starting up */
-int bcd_get_audio_info(void);
-/* get a particular track's info */
-int bcd_get_track_address(int trackno, int *start, int *len);
-/* check for track's audio/data status */
-int bcd_track_is_audio(int trackno);
-/* play a particular track from beginning to end */
-int bcd_play_track(int tracknum);
-/* play an arbitrary section of audio for an arbitrary length of time */
-int bcd_play(int start, int len);
-/* set the output volume. pass a parameter from 0-255 */
-int bcd_set_volume(int);
-/* stop and pause are equivalent */
-int bcd_stop(void);
-#define bcd_pause bcd_stop
-int bcd_resume(void);
-
-/* Troubleshooting */
-/* Returns a human readable description of the last error encountered */
-const char *bcd_error(void);
-extern int _error_code;
-/* If you are mad enough play the Rach 3, I mean parse _error_code yourself */
-#define BCD_DE_WRITE_PROTECT	0
-#define BCD_DE_UNKNOWN_UNIT	1
-#define BCD_DE_DRIVE_NOT_READY	2
-#define BCD_DE_UNKNOWN_COMMAND	3
-#define BCD_DE_CRC_ERROR	4
-#define BCD_DE_STRUCT_LEN	5
-#define BCD_DE_SEEK_ERROR	6
-#define BCD_DE_UNKNOWN_MEDIA	7
-#define BCD_DE_SECTOR_NOT_FOUND	8
-#define BCD_DE_OUT_OF_PAPER	9
-#define BCD_DE_WRITE_FAULT	10
-#define BCD_DE_READ_FAULT	11
-#define BCD_DE_GENERAL_FAILURE	12
-#define BCD_DE_INVALID_DISK_CHANGE	15
-/* set by BCD itself, for stuff like "Out of memory" */
-extern const char *_bcd_error;
-
-/* uncomment this line to force BCD to use a statically allocated
-   Track array instead of using malloc */
-#define STATIC_TRACKS
-
-#endif
diff --git a/src/djgppdos/i_cdmus.c b/src/djgppdos/i_cdmus.c
deleted file mode 100644
index 2a629ca1738a1ad7e5d36ae6c83a16fdcd2c22e8..0000000000000000000000000000000000000000
--- a/src/djgppdos/i_cdmus.c
+++ /dev/null
@@ -1,445 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief cd music interface (uses bcd library)
-
-// Alam_GBC: I hate you, Brennan Underwood :)
-#include "../doomtype.h"
-#include "bcd.c"
-//#include "bcd.h"                // CD-Audio library by Brennan Underwood
-
-#include "../doomdef.h"
-#include "../i_sound.h"
-#include "../command.h"
-#include "../i_system.h"
-#include "../s_sound.h"
-
-// ------
-// protos
-// ------
-static void Command_Cd_f (void);
-
-
-//======================================================================
-//                   CD AUDIO MUSIC SUBSYSTEM
-//======================================================================
-
-UINT8  cdaudio_started=0;   // for system startup/shutdown
-
-#define MAX_CD_TRACKS 256
-static boolean cdPlaying = false;
-static int     cdPlayTrack;         // when cdPlaying is true
-static boolean cdLooping = false;
-static UINT8   cdRemap[MAX_CD_TRACKS];
-static boolean cdEnabled=true;      // cd info available
-static boolean cdValid;             // true when last cd audio info was ok
-static boolean wasPlaying;
-static int     cdVolume=0;          // current cd volume (0-31)
-
-// 0-31 like Music & Sfx, though CD hardware volume is 0-255.
-consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-// allow Update for next/loop track
-// some crap cd drivers take up to
-// a second for a simple 'busy' check..
-// (on those Update can be disabled)
-consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-
-// hour,minutes,seconds
-FUNCINLINE static ATTRINLINE char *hms(int hsg)
-{
-	int hours, minutes, seconds;
-	static char s[9];
-
-	seconds = hsg / 75;
-	minutes = seconds / 60;
-	seconds %= 60;
-	hours = minutes / 60;
-	minutes %= 60;
-	if (hours>0)
-		sprintf (s, "%d:%02d:%02d", hours, minutes, seconds);
-	else
-		sprintf (s, "%2d:%02d", minutes, seconds);
-	return s;
-}
-
-static void Command_Cd_f (void)
-{
-	const char *    s;
-	int       i,j;
-
-	if (!cdaudio_started)
-		return;
-
-	if (COM_Argc()<2)
-	{
-		CONS_Printf ("cd [on] [off] [remap] [reset] [open]\n"
-		             "   [info] [play <track>] [loop <track>]\n"
-		             "   [stop] [resume]\n");
-		return;
-	}
-
-	s = COM_Argv(1);
-
-	// activate cd music
-	if (!strncmp(s,"on",2))
-	{
-		cdEnabled = true;
-		return;
-	}
-
-	// stop/deactivate cd music
-	if (!strncmp(s,"off",3))
-	{
-		if (cdPlaying)
-			I_StopCD ();
-		cdEnabled = false;
-		return;
-	}
-
-	// remap tracks
-	if (!strncmp(s,"remap",5))
-	{
-		i = COM_Argc() - 2;
-		if (i <= 0)
-		{
-			CONS_Printf ("CD tracks remapped in that order :\n");
-			for (j = 1; j < MAX_CD_TRACKS; j++)
-				if (cdRemap[j] != j)
-					CONS_Printf (" %2d -> %2d\n", j, cdRemap[j]);
-			return;
-		}
-		for (j = 1; j <= i; j++)
-			cdRemap[j] = atoi (COM_Argv (j+1));
-		return;
-	}
-
-	// reset the CD driver, useful on some odd cd's
-	if (!strncmp(s,"reset",5))
-	{
-		cdEnabled = true;
-		if (cdPlaying)
-			I_StopCD ();
-		for (i = 0; i < MAX_CD_TRACKS; i++)
-			cdRemap[i] = i;
-		bcd_reset ();
-		cdValid = bcd_get_audio_info ();
-		return;
-	}
-
-	// any other command is not allowed until we could retrieve cd information
-	if (!cdValid)
-	{
-		CONS_Printf ("CD is not ready.\n");
-		return;
-	}
-
-	if (!strncmp(s,"open",4))
-	{
-		if (cdPlaying)
-			I_StopCD ();
-		bcd_open_door();
-		cdValid = false;
-		return;
-	}
-
-	if (!strncmp(s,"info",4))
-	{
-		int totaltime = 0;
-
-		if (!bcd_get_audio_info())
-		{
-			CONS_Printf ("Error getting audio info: %s\n",bcd_error());
-			cdValid = false;
-			return;
-		}
-
-		cdValid = true;
-
-		if (lowest_track == 0)
-			CONS_Printf ("No audio tracks\n");
-		else
-		{
-			// display list of tracks
-			// highlight current playing track
-			for (i=lowest_track; i <= highest_track; i++)
-			{
-				CONS_Printf    ("%s%2d. %s  %s\n",
-								cdPlaying && (cdPlayTrack == i) ? "\2 " : " ",
-								i, tracks[i].is_audio ? "audio" : "data ",
-								hms(tracks[i].len));
-				if (tracks[i].is_audio)
-					totaltime += tracks[i].len;
-			}
-
-			if (totaltime)
-				CONS_Printf ("\2Total time : %s\n", hms(totaltime));
-		}
-		if (cdPlaying)
-		{
-			CONS_Printf ("%s track : %d\n", cdLooping ? "looping" : "playing",
-			             cdPlayTrack);
-		}
-		return;
-	}
-
-	if (!strncmp(s,"play",4))
-	{
-		I_PlayCD ((UINT8)atoi (COM_Argv (2)), false);
-		return;
-	}
-
-	if (!strncmp(s,"stop",4))
-	{
-		I_StopCD ();
-		return;
-	}
-
-	if (!strncmp(s,"loop",4))
-	{
-		I_PlayCD ((UINT8)atoi (COM_Argv (2)), true);
-		return;
-	}
-
-	if (!strncmp(s,"resume",4))
-	{
-		I_ResumeCD ();
-		return;
-	}
-
-	CONS_Printf ("cd command '%s' unknown\n", s);
-}
-
-
-// pause cd music
-void I_StopCD (void)
-{
-	if (!cdaudio_started || !cdEnabled)
-		return;
-
-	bcd_stop();
-
-	wasPlaying = cdPlaying;
-	cdPlaying = false;
-}
-
-// continue after a pause
-void I_ResumeCD (void)
-{
-	if (!cdaudio_started || !cdEnabled)
-		return;
-
-	if (!cdValid)
-		return;
-
-	if (!wasPlaying)
-		return;
-
-	bcd_resume ();
-	cdPlaying = true;
-}
-
-
-void I_ShutdownCD (void)
-{
-	int rc;
-
-	if (!cdaudio_started)
-		return;
-
-	I_StopCD ();
-
-	rc = bcd_close ();
-	if (!rc)
-		CONS_Printf ("Error shuting down cd\n");
-}
-
-void I_InitCD (void)
-{
-	int rc;
-	int i;
-
-	rc = bcd_open ();
-
-	if (rc>=0x200)
-	{
-		CONS_Printf ("MSCDEX version %d.%d\n", rc>>8, rc&255);
-
-		I_AddExitFunc (I_ShutdownCD);
-		cdaudio_started = true;
-	}
-	else
-	{
-		if (!rc)
-			CONS_Printf ("%s\n", bcd_error() );
-
-		cdaudio_started = false;
-		return;
-	}
-
-	// last saved in config.cfg
-	i = cd_volume.value;
-	I_SetVolumeCD (0);   // initialize to 0 for some odd cd drivers
-	I_SetVolumeCD (i);   // now set the last saved volume
-
-	for (i = 0; i < MAX_CD_TRACKS; i++)
-		cdRemap[i] = i;
-
-	if (!bcd_get_audio_info())
-	{
-		CONS_Printf("\2CD Init: No CD in player.\n");
-		cdEnabled = false;
-		cdValid = false;
-	}
-	else
-	{
-		cdEnabled = true;
-		cdValid = true;
-	}
-
-	COM_AddCommand ("cd", Command_Cd_f);
-}
-
-
-
-// loop/go to next track when track is finished (if cd_update var is true)
-// update the volume when it has changed (from console/menu)
-/// \todo check for cd change and restart music ?
-
-void I_UpdateCD (void)
-{
-	int     newVolume;
-	int     now;
-	static  int last;     //game tics (35th of second)
-
-	if (!cdaudio_started)
-		return;
-
-	now = I_GetTime ();
-	if ((now - last) < 10)        // about 1/4 second
-		return;
-	last = now;
-
-	// update cd volume changed at console/menu
-	newVolume = cd_volume.value & 31;
-
-	if (cdVolume != newVolume)
-		I_SetVolumeCD (newVolume);
-
-	// slow drivers exit here
-	if (!cdUpdate.value)
-		return;
-
-	if (cdPlaying)
-	{
-		if (!bcd_audio_busy())
-		{
-			cdPlaying = false;
-			if (cdLooping)
-				I_PlayCD (cdPlayTrack, true);
-			else
-			{
-				// play the next cd track, or restart the first
-				cdPlayTrack++;
-				if (cdPlayTrack > highest_track)
-					cdPlayTrack = lowest_track;
-				while (!tracks[cdPlayTrack].is_audio && cdPlayTrack<highest_track)
-					cdPlayTrack++;
-				I_PlayCD (cdPlayTrack, true);
-			}
-		}
-	}
-
-}
-
-
-//
-void I_PlayCD (UINT8 track, UINT8 looping)
-{
-	if (!cdaudio_started || !cdEnabled)
-		return;
-
-	if (!cdValid)
-		return;
-
-	track = cdRemap[track];
-
-	if (cdPlaying)
-	{
-		if (cdPlayTrack == track)
-			return;
-		I_StopCD ();
-	}
-
-	if (track < lowest_track || track > highest_track)
-	{
-		//CONS_Printf ("\2CD Audio: wrong track number %d\n", track);
-		// suppose there are not enough tracks for game levels..
-		// then do a modulo so we always get something to hear
-		track = (track % (highest_track-lowest_track+1)) + 1;
-		//return;
-	}
-
-	cdPlayTrack = track;
-
-	if (!tracks[track].is_audio)
-	{
-		CONS_Printf ("\2CD Play: not an audio track\n");
-		return;
-	}
-
-	cdLooping = looping;
-
-	if (!bcd_play_track (track))
-	{
-		CONS_Printf ("CD Play: could not play track %d\n", track);
-		cdValid = false;
-		cdPlaying = false;
-		return;
-	}
-
-	cdPlaying = true;
-
-}
-
-
-// volume : logical cd audio volume 0-31 (hardware is 0-255)
-boolean I_SetVolumeCD (INT32 volume)
-{
-	int  hardvol;
-
-	if (!cdaudio_started || !cdEnabled)
-		return false;
-
-	// translate to hardware volume
-	volume &= 31;
-
-	hardvol = ((volume+1)<<3)-1;  //highest volume is 255
-	if (hardvol<=8)
-		hardvol=0;                //lowest volume is ZERO
-
-	cdVolume = volume;
-
-	if (bcd_set_volume (hardvol))
-	{
-		CV_SetValue (&cd_volume, volume);
-
-		return true;
-	}
-	else
-		return false;
-}
diff --git a/src/djgppdos/i_main.c b/src/djgppdos/i_main.c
deleted file mode 100644
index 1b8894470d30219dfa63dfc5fb0162323fd64131..0000000000000000000000000000000000000000
--- a/src/djgppdos/i_main.c
+++ /dev/null
@@ -1,78 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief Main program, simply calls D_SRB2Main high level loop.
-
-#include "../doomdef.h"
-
-#include "../m_argv.h"
-#include "../d_main.h"
-
-#include "../i_system.h"
-
-#ifdef REMOTE_DEBUGGING
-#include <i386-stub.h>
-#include "rdb.h"
-#endif
-
-//### let's try with Allegro ###
-#define  alleg_mouse_unused
-#define  alleg_timer_unused
-#define  ALLEGRO_NO_KEY_DEFINES
-#define  alleg_keyboard_unused
-#define  alleg_joystick_unused
-#define  alleg_gfx_driver_unused
-#define  alleg_palette_unused
-#define  alleg_graphics_unused
-#define  alleg_vidmem_unused
-#define  alleg_flic_unused
-#define  alleg_sound_unused
-#define  alleg_file_unused
-#define  alleg_datafile_unused
-#define  alleg_math_unused
-#define  alleg_gui_unused
-#include <allegro.h>
-//### end of Allegro include ###
-
-int main (int argc, char **argv)
-{
-	myargc = argc;
-	myargv = argv;
-
-	{
-		//added:03-01-98:
-		//       Setup signal handlers and other stuff BEFORE ANYTHING ELSE!
-		I_StartupSystem();
-#ifdef REMOTE_DEBUGGING
-		/* Only setup if remote debugging  is to be done, Muhahahaha!*/
-		gdb_serial_init(DEBUG_COM_PORT,DEBUG_COM_PORT_SPEED);
-		gdb_target_init();
-		breakpoint();
-#endif
-
-		D_SRB2Main();
-		D_SRB2Loop();
-
-	}
-	//added:03-01-98:
-	//       hmmm... it will never go here.
-
-	return 0;
-}
-#if ALLEGRO_VERSION == 4
-END_OF_MAIN()
-#endif
diff --git a/src/djgppdos/i_net.c b/src/djgppdos/i_net.c
deleted file mode 100644
index 866aa8d8b9ed821fe8f4677d41628b3c01b539f5..0000000000000000000000000000000000000000
--- a/src/djgppdos/i_net.c
+++ /dev/null
@@ -1,113 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief doomcom network interface
-
-
-#include <netinet/in.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <go32.h>
-#include <pc.h>
-#include <dpmi.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-
-#include "../doomdef.h"
-
-#include "../i_system.h"
-#include "../d_event.h"
-#include "../d_net.h"
-#include "../m_argv.h"
-
-#include "../doomstat.h"
-#include "../z_zone.h"
-#include "../i_net.h"
-#include "../i_tcp.h"
-
-//
-// NETWORKING
-//
-
-typedef enum
-{
-	CMD_SEND     = 1,
-	CMD_GET      = 2,
-} command_t;
-
-static void External_Driver_Get(void);
-static void External_Driver_Send(void);
-static void External_Driver_FreeNode(INT32 nodenum);
-
-static inline boolean External_Driver_OpenSocket(void)
-{
-	I_NetGet  = External_Driver_Get;
-	I_NetSend = External_Driver_Send;
-	I_NetCloseSocket = NULL;
-	I_NetFreeNodenum = External_Driver_FreeNode;
-
-	return true;
-}
-
-//
-// I_InitNetwork
-//
-boolean I_InitNetwork (void)
-{
-	int netgamepar;
-
-	netgamepar = M_CheckParm ("-net");
-	if (!netgamepar)
-		return false;
-
-	// externals drivers specific
-
-	__djgpp_nearptr_enable();
-
-	// set up for network
-	doomcom=(doomcom_t *)(__djgpp_conventional_base+atoi(myargv[netgamepar+1]));
-	CONS_Printf("I_DosNet : Using int 0x%x for communication\n",doomcom->intnum);
-
-	server = (doomcom->consoleplayer == 0);
-	if (!server)
-		COM_BufAddText("connect any\n");
-
-	// ipx + time + 4 (padding)
-	packetheaderlength=30+4+4;
-
-	hardware_MAXPACKETLENGTH = 512;
-
-	I_NetOpenSocket = External_Driver_OpenSocket;
-	return true;
-}
-
-FUNCNORETURN static ATTRNORETURN void External_Driver_Get(void)
-{
-	I_Error("External_Driver_Get not supported at this time");
-}
-
-FUNCNORETURN static ATTRNORETURN void External_Driver_Send(void)
-{
-	I_Error("External_Driver_Send not supported at this time");
-}
-
-FUNCNORETURN static ATTRNORETURN void External_Driver_FreeNode(INT32 nodenum)
-{
-	nodenum = 0;
-	I_Error("External_Driver_FreeNode not supported at this time");
-}
diff --git a/src/djgppdos/i_sound.c b/src/djgppdos/i_sound.c
deleted file mode 100644
index 847853a89a5af711e3f58e2230bedacf416b8912..0000000000000000000000000000000000000000
--- a/src/djgppdos/i_sound.c
+++ /dev/null
@@ -1,620 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief interface level code for sound
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include <math.h>
-
-#include "../doomdef.h"
-#include "../doomstat.h"
-#include "../i_system.h"
-#include "../i_sound.h"
-#include "../z_zone.h"
-#include "../m_argv.h"
-#include "../m_misc.h"
-#include "../w_wad.h"
-#include "../s_sound.h"
-#include "../console.h"
-
-//### let's try with Allegro ###
-#define  alleg_mouse_unused
-#define  alleg_timer_unused
-#define  ALLEGRO_NO_KEY_DEFINES
-#define  alleg_keyboard_unused
-#define  alleg_joystick_unused
-#define  alleg_gfx_driver_unused
-#define  alleg_palette_unused
-#define  alleg_graphics_unused
-#define  alleg_vidmem_unused
-#define  alleg_flic_unused
-//#define  alleg_sound_unused    we use it
-#define  alleg_file_unused
-#define  alleg_datafile_unused
-#define  alleg_math_unused
-#define  alleg_gui_unused
-#include <allegro.h>
-//### end of Allegro include ###
-
-//allegro has 256 virtual voices
-// warning should by a power of 2
-#define VIRTUAL_VOICES 256
-#define VOICESSHIFT 8
-
-// Needed for calling the actual sound output.
-#define SAMPLECOUNT    512
-
-
-
-//
-// this function converts raw 11khz, 8-bit data to a SAMPLE* that allegro uses
-// it is need cuz allegro only loads samples from wavs and vocs
-//added:11-01-98: now reads the frequency from the rawdata header.
-//   dsdata points a 4 UINT16 header:
-//    +0 : value 3 what does it mean?
-//    +2 : sample rate, either 11025 or 22050.
-//    +4 : number of samples, each sample is a single byte since it's 8bit
-//    +6 : value 0
-static inline SAMPLE *raw2SAMPLE(UINT8 *dsdata, size_t len)
-{
-	SAMPLE *spl;
-
-	spl=Z_Malloc(sizeof (SAMPLE),PU_SOUND,NULL);
-	if (spl==NULL)
-		I_Error("Raw2Sample : no more free mem");
-	spl->bits = 8;
-	spl->stereo = 0;
-	spl->freq = *((UINT16 *)dsdata+1);   //mostly 11025, but some at 22050.
-	spl->len = len-8;
-	spl->priority = 255;                //priority;
-	spl->loop_start = 0;
-	spl->loop_end = len-8;
-	spl->param = -1;
-	spl->data=(void *)(dsdata+8);       //skip the 8bytes header
-
-	return spl;
-}
-
-
-//  This function loads the sound data from the WAD lump,
-//  for single sound.
-//
-void *I_GetSfx (sfxinfo_t * sfx)
-{
-	UINT8 *dssfx;
-
-	if (sfx->lumpnum == LUMPERROR)
-		sfx->lumpnum = S_GetSfxLumpNum (sfx);
-
-	sfx->length = W_LumpLength (sfx->lumpnum);
-
-	dssfx = (UINT8 *) W_CacheLumpNum (sfx->lumpnum, PU_SOUND);
-	//_go32_dpmi_lock_data(dssfx,size);
-
-	// convert raw data and header from Doom sfx to a SAMPLE for Allegro
-	return (void *)raw2SAMPLE (dssfx, sfx->length);
-}
-
-
-void I_FreeSfx (sfxinfo_t *sfx)
-{
-	if (sfx->lumpnum == LUMPERROR)
-		return;
-
-	// free sample data
-	if ( sfx->data )
-		Z_Free((UINT8 *) ((SAMPLE *)sfx->data)->data - 8);
-	Z_Free(sfx->data); // Allegro SAMPLE structure
-	sfx->data = NULL;
-	sfx->lumpnum = LUMPERROR;
-}
-
-FUNCINLINE static ATTRINLINE int Volset(int vol)
-{
-	return (vol*255/31);
-}
-
-
-void I_SetSfxVolume(INT32 volume)
-{
-	if (sound_disabled)
-		return;
-
-	set_volume (Volset(volume),-1);
-}
-
-//
-// Starting a sound means adding it
-//  to the current list of active sounds
-//  in the internal channels.
-// As the SFX info struct contains
-//  e.g. a pointer to the raw data,
-//  it is ignored.
-// As our sound handling does not handle
-//  priority, it is ignored.
-// Pitching (that is, increased speed of playback)
-//  is set, but currently not used by mixing.
-//
-INT32 I_StartSound ( sfxenum_t     id,
-                   INT32         vol,
-                   INT32         sep,
-                   INT32         pitch,
-                   INT32         priority,
-				   INT32         channel)
-{
-	int voice;
-	(void)channel;
-
-	if (sound_disabled)
-	return 0;
-
-	// UNUSED
-	priority = 0;
-
-	pitch = (pitch-128)/2+128;
-	voice = play_sample(S_sfx[id].data,vol,sep,(pitch*1000)/128,0);
-
-	// Returns a handle
-	return (id<<VOICESSHIFT)+voice;
-}
-
-void I_StopSound (INT32 handle)
-{
-	// You need the handle returned by StartSound.
-	// Would be looping all channels,
-	//  tracking down the handle,
-	//  an setting the channel to zero.
-	int voice=handle & (VIRTUAL_VOICES-1);
-
-	if (sound_disabled)
-		return;
-
-	if (voice_check(voice)==S_sfx[handle>>VOICESSHIFT].data)
-		deallocate_voice(voice);
-}
-
-INT32 I_SoundIsPlaying(INT32 handle)
-{
-	if (sound_disabled)
-		return FALSE;
-
-	if (voice_check(handle & (VIRTUAL_VOICES-1))==S_sfx[handle>>VOICESSHIFT].data)
-		return TRUE;
-
-	return FALSE;
-}
-
-// cut and past from ALLEGRO he don't share it :(
-static inline int absolute_freq(int freq, SAMPLE *spl)
-{
-	if (freq == 1000)
-		return spl->freq;
-	else
-		return (spl->freq * freq) / 1000;
-}
-
-void I_UpdateSoundParams( INT32 handle,
-                          INT32 vol,
-                          INT32 sep,
-                          INT32 pitch)
-{
-	// I fail too see that this is used.
-	// Would be using the handle to identify
-	//  on which channel the sound might be active,
-	//  and resetting the channel parameters.
-	int voice=handle & (VIRTUAL_VOICES-1);
-	int numsfx=handle>>VOICESSHIFT;
-
-	if (sound_disabled)
-		return;
-
-	if (voice_check(voice)==S_sfx[numsfx].data)
-	{
-		voice_set_volume(voice, vol);
-		voice_set_pan(voice, sep);
-		voice_set_frequency(voice, absolute_freq(pitch*1000/128,
-		                    S_sfx[numsfx].data));
-	}
-}
-
-
-void I_ShutdownSound(void)
-{
-	// Wait till all pending sounds are finished.
-
-	//added:03-01-98:
-	if ( !sound_started )
-		return;
-
-	//added:08-01-98: remove_sound() explicitly because we don't use
-	//                Allegro's allegro_exit();
-	remove_sound();
-	sound_started = false;
-}
-
-static char soundheader[] = "sound";
-#if ALLEGRO_VERSION == 3
-static char soundvar[] = "sb_freq";
-#else
-static char soundvar[] = "sound_freq";
-#endif
-
-void I_StartupSound(void)
-{
-	int    sfxcard,midicard;
-#if ALLEGRO_VERSION == 3
-	char   err[255];
-#endif
-
-	if (sound_disabled)
-		sfxcard=DIGI_NONE;
-	else
-		sfxcard=DIGI_AUTODETECT;
-
-	if (midi_disabled)
-		midicard=MIDI_NONE;
-	else
-		midicard=MIDI_AUTODETECT; //DetectMusicCard();
-
-	digital_disabled=true; //Alam: No OGG/MP3/IT/MOD support
-
-	// Secure and configure sound device first.
-	CONS_Printf("I_StartupSound: ");
-
-	//Fab:25-04-98:note:install_sound will check for sound settings
-	//    in the sound.cfg or allegro.cfg, in the current directory,
-	//    or the directory pointed by 'ALLEGRO' env var.
-#if ALLEGRO_VERSION == 3
-	if (install_sound(sfxcard,midicard,NULL)!=0)
-	{
-		sprintf (err,"Sound init error : %s\n",allegro_error);
-		CONS_Error (err);
-		sound_disabled=true;
-		midi_disabled=true;
-	}
-	else
-	{
-		CONS_Printf(" configured audio device\n" );
-	}
-
-	//added:08-01-98:we use a similar startup/shutdown scheme as Allegro.
-	I_AddExitFunc(I_ShutdownSound);
-#endif
-	sound_started = true;
-	CV_SetValue(&cv_samplerate,get_config_int(soundheader,soundvar,cv_samplerate.value));
-}
-
-
-
-
-//
-// MUSIC API.
-// Still no music done.
-// Remains. Dummies.
-//
-
-static MIDI* currsong;   //im assuming only 1 song will be played at once
-static int      islooping=0;
-static int      musicdies=-1;
-UINT8           music_started=0;
-boolean         songpaused=false;
-
-/// ------------------------
-//  MUSIC SYSTEM
-/// ------------------------
-
-/* load_midi_mem:
- *  Loads a standard MIDI file from memory, returning a pointer to
- *  a MIDI structure, *  or NULL on error.
- *  It is the load_midi from Allegro modified to load it from memory
- */
-static MIDI *load_midi_mem(char *mempointer,int *e)
-{
-	int c = *e;
-	long data=0;
-	unsigned char *fp;
-	MIDI *midi;
-	int num_tracks=0;
-
-	fp = (void *)mempointer;
-	if (!fp)
-		return NULL;
-
-	midi = malloc(sizeof (MIDI));              /* get some memory */
-	if (!midi)
-		return NULL;
-
-	for (c=0; c<MIDI_TRACKS; c++)
-	{
-		midi->track[c].data = NULL;
-		midi->track[c].len = 0;
-	}
-
-	fp+=4+4;   // header size + 'chunk' size
-
-	swab(fp,&data,2);     // convert to intel-endian
-	fp+=2;                                      /* MIDI file type */
-	if ((data != 0) && (data != 1)) // only type 0 and 1 are suported
-		return NULL;
-
-	swab(fp,&num_tracks,2);                     /* number of tracks */
-	fp+=2;
-	if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
-		return NULL;
-
-	swab(fp,&data,2);                          /* beat divisions */
-	fp+=2;
-	midi->divisions = ABS(data);
-
-	for (c=0; c<num_tracks; c++)
-	{            /* read each track */
-		if (memcmp(fp, "MTrk", 4))
-			return NULL;
-		fp+=4;
-
-		//swab(fp,&data,4);       don't work !!!!??
-		((char *)&data)[0]=fp[3];
-		((char *)&data)[1]=fp[2];
-		((char *)&data)[2]=fp[1];
-		((char *)&data)[3]=fp[0];
-		fp+=4;
-
-		midi->track[c].len = data;
-
-		midi->track[c].data = fp;
-		fp+=data;
-	}
-
-	lock_midi(midi);
-	return midi;
-}
-
-void I_InitMusic(void)
-{
-	if (midi_disabled)
-		return;
-
-	I_AddExitFunc(I_ShutdownMusic);
-	music_started = true;
-	songpaused = false;
-}
-
-void I_ShutdownMusic(void)
-{
-	if ( !music_started )
-		return;
-
-	I_StopSong();
-
-	music_started=false;
-}
-
-/// ------------------------
-//  MUSIC PROPERTIES
-/// ------------------------
-
-musictype_t I_SongType(void)
-{
-	if (currsong)
-		return MU_MID;
-	else
-		return MU_NONE;
-}
-
-boolean I_SongPlaying()
-{
-	return (boolean)currsong;
-}
-
-boolean I_SongPaused()
-{
-	return songpaused;
-}
-
-/// ------------------------
-//  MUSIC EFFECTS
-/// ------------------------
-
-boolean I_SetSongSpeed(float speed)
-{
-	(void)speed;
-	return false;
-}
-
-/// ------------------------
-// MUSIC SEEKING
-/// ------------------------
-
-UINT32 I_GetSongLength(void)
-{
-	return 0;
-}
-
-boolean I_SetSongLoopPoint(UINT32 looppoint)
-{
-        (void)looppoint;
-        return false;
-}
-
-UINT32 I_GetSongLoopPoint(void)
-{
-	return 0;
-}
-
-boolean I_SetSongPosition(UINT32 position)
-{
-    (void)position;
-    return false;
-}
-
-UINT32 I_GetSongPosition(void)
-{
-    return 0;
-}
-
-/// ------------------------
-//  MUSIC PLAYBACK
-/// ------------------------
-
-boolean I_LoadSong(char *data, size_t len)
-{
-	int e = len; //Alam: For error
-	if (midi_disabled)
-		return 0;
-
-	if (memcmp(data,"MThd",4)==0) // support mid file in WAD !!!
-	{
-		currsong=load_midi_mem(data,&e);
-	}
-	else
-	{
-		CONS_Printf("Music Lump is not a MIDI lump\n");
-		return 0;
-	}
-
-	if (currsong==NULL)
-	{
-		CONS_Printf("Not a valid mid file : %d\n",e);
-		return 0;
-	}
-
-	return 1;
-}
-
-void I_UnloadSong(void)
-{
-	handle = 0;
-	if (midi_disabled)
-		return;
-
-	//destroy_midi(currsong);
-}
-
-boolean I_PlaySong(boolean looping)
-{
-	handle = 0;
-	if (midi_disabled)
-		return false;
-
-	islooping = looping;
-	musicdies = gametic + NEWTICRATE*30;
-	if (play_midi(currsong,looping)==0)
-		return true;
-	return false;
-}
-
-void I_StopSong(void)
-{
-	handle = 0;
-	if (midi_disabled)
-		return;
-
-	islooping = 0;
-	musicdies = 0;
-	stop_midi();
-	songpaused = false;
-}
-
-void I_PauseSong (INT32 handle)
-{
-	handle = 0;
-	if (midi_disabled)
-		return;
-	midi_pause();
-	songpaused = true;
-}
-
-void I_ResumeSong (INT32 handle)
-{
-	handle = 0;
-	if (midi_disabled)
-		return;
-	midi_resume();
-	songpaused = false;
-}
-
-
-void I_SetMusicVolume(INT32 volume)
-{
-	if (midi_disabled)
-		return;
-
-	// Now set volume on output device.
-	set_volume (-1, Volset(volume));
-}
-
-boolean I_SetSongTrack(INT32 track)
-{
-	(void)track;
-	return false;
-}
-
-// Is the song playing?
-#if 0
-int I_QrySongPlaying(int handle)
-{
-	if (midi_disabled)
-		return 0;
-
-	//return islooping || musicdies > gametic;
-	return (midi_pos==-1);
-}
-#endif
-
-/// ------------------------
-// MUSIC FADING
-/// ------------------------
-
-void I_SetInternalMusicVolume(UINT8 volume)
-{
-	(void)volume;
-}
-
-void I_StopFadingSong(void)
-{
-}
-
-boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
-{
-	(void)target_volume;
-	(void)source_volume;
-	(void)ms;
-	return false;
-}
-
-boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
-{
-	(void)target_volume;
-	(void)ms;
-	return false;
-}
-
-boolean I_FadeOutStopSong(UINT32 ms)
-{
-	(void)ms;
-	return false;
-}
-
-boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
-{
-        (void)ms;
-        (void)looping;
-        return false;
-}
diff --git a/src/djgppdos/i_system.c b/src/djgppdos/i_system.c
deleted file mode 100644
index 9f6972fa67663065e65fb29973d99ee60711d1aa..0000000000000000000000000000000000000000
--- a/src/djgppdos/i_system.c
+++ /dev/null
@@ -1,1772 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief Misc. stuff
-///
-///	Startup & Shutdown routines for music,sound,timer,keyboard,
-///	Signal handler to trap errors and exit cleanly.
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <io.h>
-#include <stdarg.h>
-#include <sys/time.h>
-#include <fcntl.h>
-
-#ifdef DJGPP
- #include <dpmi.h>
- #include <go32.h>
- #include <pc.h>
- #include <dos.h>
- #include <crt0.h>
- #include <sys/segments.h>
- #include <sys/nearptr.h>
-
- #include <keys.h>
-#endif
-
-
-#include "../doomdef.h"
-#include "../m_misc.h"
-#include "../i_video.h"
-#include "../i_sound.h"
-#include "../i_system.h"
-#include "../d_net.h"
-#include "../g_game.h"
-
-#include "../d_main.h"
-
-#include "../m_argv.h"
-
-#include "../w_wad.h"
-#include "../z_zone.h"
-#include "../g_input.h"
-
-#include "../console.h"
-
-#include "../m_menu.h"
-
-#ifdef __GNUG__
- #pragma implementation "../i_system.h"
-#endif
-
-#include "../i_joy.h"
-
-//### let's try with Allegro ###
-#define  alleg_mouse_unused
-//#define  alleg_timer_unused
-#define  alleg_keyboard_unused
-#define  ALLEGRO_NO_KEY_DEFINES
-//#define  alleg_joystick_unused
-#define  alleg_gfx_driver_unused
-#define  alleg_palette_unused
-#define  alleg_graphics_unused
-#define  alleg_vidmem_unused
-#define  alleg_flic_unused
-#define  alleg_sound_unused
-#define  alleg_file_unused
-#define  alleg_datafile_unused
-#define  alleg_math_unused
-#define  alleg_gui_unused
-#include <allegro.h>
-//### end of Allegro include ###
-
-#ifndef DOXYGEN
-
-#ifndef MAX_JOYSTICKS
-#define MAX_JOYSTICKS 4
-#endif
-
-#ifndef MAX_JOYSTICK_AXIS
-#define MAX_JOYSTICK_AXIS 3
-#endif
-
-#ifndef MAX_JOYSTICK_STICKS
-#define MAX_JOYSTICK_STICKS 4
-#endif
-
-#ifndef MAX_JOYSTICK_BUTTONS
-#define MAX_JOYSTICK_BUTTONS 12
-#endif
-
-#endif
-
-#if ALLEGRO_VERSION == 4
-static char JOYFILE[] = "allegro4.cfg";
-#elif ALLEGRO_VERSION == 3
-static char JOYFILE[] = "allegro.cfg";
-#endif
-
-/// \brief max number of joystick buttons
-#define JOYBUTTONS_MAX MAX_JOYSTICK_BUTTONS // <allegro/joystick.h>
-/// \brief max number of joystick button events
-#define JOYBUTTONS_MIN min((JOYBUTTONS),(JOYBUTTONS_MAX))
-
-/// \brief max number of joysick axies
-#define JOYAXISSET_MAX MAX_JOYSTICK_STICKS
-// \brief max number ofjoystick axis events
-#define JOYAXISSET_MIN min((JOYAXISSET),(JOYAXISSET_MAX))
-
-/// \brief max number of joystick hats
-#define JOYHATS_MAX MAX_JOYSTICK_STICKS
-/// \brief max number of joystick hat events
-#define JOYHATS_MIN min((JOYHATS),(JOYHATS_MAX))
-
-/// \brief max number of mouse buttons
-#define MOUSEBUTTONS_MAX 16 // 16 bit of BL
-/// \brief max number of muse button events
-#define MOUSEBUTTONS_MIN min((MOUSEBUTTONS),(MOUSEBUTTONS_MAX))
-
-// Do not execute cleanup code more than once. See Shutdown_xxx() routines.
-UINT8 graphics_started = false;
-UINT8 keyboard_started = false;
-UINT8 sound_started    = false;
-static UINT8 timer_started    = false;
-
-/* Mouse stuff */
-static UINT8 mouse_detected   = false;
-static UINT8 wheel_detected   = false;
-
-static volatile tic_t ticcount;   //returned by I_GetTime(), updated by timer interrupt
-
-
-void I_Tactile(FFType Type, const JoyFF_t *Effect)
-{
-	// UNUSED.
-	Type = EvilForce;
-	Effect = NULL;
-}
-
-void I_Tactile2(FFType Type, const JoyFF_t *Effect)
-{
-	// UNUSED.
-	Type = EvilForce;
-	Effect = NULL;
-}
-
-static ticcmd_t        emptycmd;
-ticcmd_t *      I_BaseTiccmd(void)
-{
-	return &emptycmd;
-}
-
-static ticcmd_t        emptycmd2;
-ticcmd_t *      I_BaseTiccmd2(void)
-{
-	return &emptycmd2;
-}
-
-void I_SetupMumble(void)
-{
-}
-
-#ifndef NOMUMBLE
-void I_UpdateMumble(const mobj_t *mobj, const listener_t listener)
-{
-	(void)mobj;
-	(void)listener;
-}
-#endif
-
-//
-//  Allocates the base zone memory,
-//  this function returns a valid pointer and size,
-//  else it should interrupt the program immediately.
-//
-//added:11-02-98: now checks if mem could be allocated, this is still
-//    prehistoric... there's a lot to do here: memory locking, detection
-//    of win95 etc...
-//
-
-#if ALLEGRO_VERSION == 3
-extern int os_type;
-extern int windows_version;
-extern int windows_sub_version;
-extern int i_love_bill;
-#elif ALLEGRO_VERSION == 4
-#endif
-
-static void I_DetectOS (void)
-{
-#if ALLEGRO_VERSION == 3
-	char buf[16];
-	__dpmi_regs r;
-	union REGS regs;
-
-	/* check which OS we are running under */
-	r.x.ax = 0x1600;
-	__dpmi_int(0x2F, &r);
-	if ((r.h.al != 0) && (r.h.al != 1) && (r.h.al != 0x80) && (r.h.al != 0xFF))
-	{
-		/* win 3.1 or 95 */
-		if (r.h.al == 4)
-		{
-			if (r.h.ah < 10)
-			{
-				os_type = OSTYPE_WIN95;
-			}
-			else
-			{
-				os_type = OSTYPE_WIN98;
-			}
-		}
-		else
-		{
-			os_type = OSTYPE_WIN3;
-		}
-
-		windows_version = r.h.al;
-		windows_sub_version = r.h.ah;
-		i_love_bill = TRUE;
-	}
-	else
-	{
-		if (_get_dos_version(1) == 0x0532)
-		{
-			/* win NT */
-			os_type = OSTYPE_WINNT;
-			windows_version = 0x100;
-			windows_sub_version = 0;
-			i_love_bill = TRUE;
-		}
-		else
-		{
-			/* see if OS/2 is present */
-			r.x.ax = 0x4010;
-			__dpmi_int(0x2F, &r);
-			if (r.x.ax != 0x4010)
-			{
-				if (r.x.ax == 0x0000)
-				{
-					/* OS/2 Warp 3 */
-					os_type = OSTYPE_WARP;
-					i_love_bill = TRUE;
-				}
-				else
-				{
-					/* no Warp, but previous OS/2 is available */
-					os_type = OSTYPE_OS2;
-					i_love_bill = TRUE;
-				}
-			}
-			else
-			{
-				/* check if running under Linux DOSEMU */
-				dosmemget(0xFFFF5, 10, buf);
-				buf[8] = 0;
-				if (!strcmp(buf, "02/25/93"))
-				{
-					regs.x.ax = 0;
-					int86(0xE6, &regs, &regs);
-					if (regs.x.ax == 0xAA55)
-					{
-						os_type = OSTYPE_DOSEMU;
-						windows_version = -1;
-						windows_sub_version = -1;
-						i_love_bill = TRUE;     /* (evil chortle) */
-					}
-				}
-				else
-				{
-					/* check if running under OpenDOS */
-					r.x.ax = 0x4452;
-					__dpmi_int(0x21, &r);
-					if ((r.x.ax >= 0x1072) && !(r.x.flags & 1))
-					{
-						os_type = OSTYPE_OPENDOS;
-						/* now check for OpenDOS EMM386.EXE */
-						r.x.ax = 0x12FF;
-						r.x.bx = 0x0106;
-						__dpmi_int(0x2F, &r);
-						if ((r.x.ax == 0x0) && (r.x.bx == 0xEDC0))
-						{
-							i_love_bill = TRUE;
-						}
-					}
-				}
-			}
-		}
-	}
-#elif ALLEGRO_VERSION == 4
-/// \todo: add Allegro 4 version
-#endif
-}
-
-UINT32 I_GetFreeMem(UINT32 *total)
-{
-	__dpmi_free_mem_info     info;
-
-	__dpmi_get_free_memory_information(&info);
-	if ( total )
-		*total = info.total_number_of_physical_pages<<12; // <<12 for convert page to byte
-	return info.total_number_of_free_pages<<12;
-}
-
-
-/*==========================================================================*/
-// I_GetTime ()
-/*==========================================================================*/
-tic_t I_GetTime (void)
-{
-	return ticcount;
-}
-
-
-void I_Sleep(void)
-{
-	if (cv_sleep.value > 0)
-		rest(cv_sleep.value);
-}
-
-
-static UINT8 joystick_detected = false;
-static UINT8 joystick2_detected = false;
-
-//
-// I_Init
-//
-
-
-FUNCINLINE static ATTRINLINE int I_WaitJoyButton (int js)
-{
-	CON_Drawer ();
-	I_FinishUpdate ();        // page flip or blit buffer
-
-	do
-	{
-		if (I_GetKey())
-			return false;
-		poll_joystick();
-	} while (!(joy[js].button[0].b || joy[js].button[1].b));
-
-	return true;
-}
-
-/**	\brief Joystick 1 buttons states
-*/
-static INT64 lastjoybuttons = 0;
-/**	\brief Joystick 1 hats state
-*/
-static INT64 lastjoyhats = 0;
-
-void I_InitJoystick (void)
-{
-	//init the joystick
-	if (joystick_detected && !joystick2_detected)
-		remove_joystick();
-	joystick_detected=0;
-	if (M_CheckParm("-nojoy"))
-		return;
-	load_joystick_data(JOYFILE);
-	if (cv_usejoystick.value)
-	{
-		if (cv_usejoystick.value > MAX_JOYSTICKS)
-			cv_usejoystick.value = MAX_JOYSTICKS;
-		if (install_joystick(JOY_TYPE_AUTODETECT) == 0)
-		{
-			int js = cv_usejoystick.value -1;
-			// only gamepadstyle joysticks
-			if (joy[js].stick[0].flags & JOYFLAG_DIGITAL) Joystick.bGamepadStyle=true;
-
-			while (joy[js].flags & JOYFLAG_CALIBRATE)
-			{
-				const char *msg = calibrate_joystick_name(js);
-				CONS_Printf("%s, and press a button\n", msg);
-				if (I_WaitJoyButton(js))
-					calibrate_joystick(js);
-				else
-				{
-					if (joystick_detected && !joystick2_detected)
-						remove_joystick();
-					joystick_detected=0;
-					CV_SetValue(&cv_usejoystick, 0);
-					return;
-				}
-			}
-			joystick_detected=1;
-			save_joystick_data(JOYFILE);
-		}
-		else
-		{
-			CONS_Printf("\2No Joystick detected.\n");
-		}
-	}
-	else
-	{
-		int i;
-		event_t event;
-		event.type=ev_keyup;
-		event.data2 = 0;
-		event.data3 = 0;
-
-		lastjoybuttons = lastjoyhats = 0;
-
-		// emulate the up of all joystick buttons
-		for (i=0;i<JOYBUTTONS;i++)
-		{
-			event.data1=KEY_JOY1+i;
-			D_PostEvent(&event);
-		}
-
-		// emulate the up of all joystick hats
-		for (i=0;i<JOYHATS*4;i++)
-		{
-			event.data1=KEY_HAT1+i;
-			D_PostEvent(&event);
-		}
-
-		// reset joystick position
-		event.type = ev_joystick;
-		for (i=0;i<JOYAXISSET; i++)
-		{
-			event.data1 = i;
-			D_PostEvent(&event);
-		}
-	}
-}
-
-/**	\brief Joystick 2 buttons states
-*/
-static INT64 lastjoy2buttons = 0;
-/**	\brief Joystick 2 hats state
-*/
-static INT64 lastjoy2hats = 0;
-
-void I_InitJoystick2 (void)
-{
-	//init the joystick
-	if (joystick2_detected && !joystick_detected)
-		remove_joystick();
-	joystick2_detected=0;
-	if (M_CheckParm("-nojoy"))
-		return;
-	if (cv_usejoystick2.value)
-	{
-		if (cv_usejoystick2.value > MAX_JOYSTICKS)
-			cv_usejoystick2.value = MAX_JOYSTICKS;
-		if (install_joystick(JOY_TYPE_AUTODETECT) == 0)
-		{
-			int js = cv_usejoystick2.value -1;
-			// only gamepadstyle joysticks
-			load_joystick_data(JOYFILE);
-			if (joy[js].stick[0].flags & JOYFLAG_DIGITAL) Joystick2.bGamepadStyle=true;
-
-			while (joy[js].flags & JOYFLAG_CALIBRATE)
-			{
-				const char *msg = calibrate_joystick_name(js);
-				CONS_Printf("%s, and press a button\n", msg);
-				if (I_WaitJoyButton(js))
-					calibrate_joystick(js);
-				else
-				{
-					if (joystick2_detected && !joystick_detected)
-						remove_joystick();
-					joystick2_detected=0;
-					CV_SetValue(&cv_usejoystick2, 0);
-					return;
-				}
-			}
-			joystick2_detected=1;
-			save_joystick_data(JOYFILE);
-		}
-		else
-		{
-			CONS_Printf("\2No Joystick detected.\n");
-		}
-	}
-	else
-	{
-		int i;
-		event_t event;
-		event.type=ev_keyup;
-		event.data2 = 0;
-		event.data3 = 0;
-
-		lastjoy2buttons = lastjoy2hats = 0;
-
-		// emulate the up of all joystick buttons
-		for (i=0;i<JOYBUTTONS;i++)
-		{
-			event.data1=KEY_2JOY1+i;
-			D_PostEvent(&event);
-		}
-
-		// emulate the up of all joystick hats
-		for (i=0;i<JOYHATS*4;i++)
-		{
-			event.data1=KEY_2HAT1+i;
-			D_PostEvent(&event);
-		}
-
-		// reset joystick position
-		event.type = ev_joystick2;
-		for (i=0;i<JOYAXISSET; i++)
-		{
-			event.data1 = i;
-			D_PostEvent(&event);
-		}
-	}
-}
-
-//added:18-02-98: put an error message (with format) on stderr
-void I_OutputMsg (const char *error, ...)
-{
-	va_list     argptr;
-
-	va_start (argptr,error);
-	vfprintf (stderr,error,argptr);
-	va_end (argptr);
-
-	// dont flush the message!
-}
-
-static int errorcount=0; // fuck recursive errors
-static int shutdowning=false;
-
-//
-// I_Error
-//
-//added 31-12-97 : display error messy after shutdowngfx
-void I_Error (const char *error, ...)
-{
-	va_list     argptr;
-	// added 11-2-98 recursive error detecting
-
-	M_SaveConfig (NULL);   //save game config, cvars..
-#ifndef NONET
-	D_SaveBan(); // save the ban list
-#endif
-	G_SaveGameData(); // Tails 12-08-2002
-	if (demorecording)
-		G_CheckDemoStatus();
-	D_QuitNetGame ();
-	M_FreePlayerSetupColors();
-
-	if (shutdowning)
-	{
-		errorcount++;
-		if (errorcount==5)
-			I_ShutdownGraphics();
-		if (errorcount==6)
-			I_ShutdownSystem();
-		if (errorcount>7)
-			exit(-1);       // recursive errors detected
-	}
-	shutdowning=true;
-
-	//added:18-02-98: save one time is enough!
-	if (!errorcount)
-	{
-		M_SaveConfig (NULL);   //save game config, cvars..
-		G_SaveGameData(); // Tails 12-08-2002
-	}
-
-	//added:16-02-98: save demo, could be useful for debug
-	//                NOTE: demos are normally not saved here.
-	I_ShutdownMusic();
-	I_ShutdownSound();
-	I_ShutdownCD();
-	I_ShutdownGraphics();
-	I_ShutdownSystem();
-
-	// put message to stderr
-	va_start (argptr,error);
-	fprintf (stderr, "Error: ");
-	vfprintf (stderr,error,argptr);
-#ifdef DEBUGFILE
-	if (debugfile)
-	{
-		fprintf (debugfile,"I_Error :");
-		vfprintf (debugfile,error,argptr);
-	}
-#endif
-
-	va_end (argptr);
-
-	fprintf (stderr, "\nPress ENTER");
-	fflush( stderr );
-	getchar();
-	W_Shutdown();
-	exit(-1);
-}
-
-
-//
-// I_Quit : shutdown everything cleanly, in reverse order of Startup.
-//
-void I_Quit (void)
-{
-	UINT8 *endoom = NULL;
-
-	//added:16-02-98: when recording a demo, should exit using 'q' key,
-	//        but sometimes we forget and use 'F10'.. so save here too.
-	M_SaveConfig (NULL);   //save game config, cvars..
-#ifndef NONET
-	D_SaveBan(); // save the ban list
-#endif
-	G_SaveGameData(); // Tails 12-08-2002
-	if (demorecording)
-		G_CheckDemoStatus();
-	D_QuitNetGame ();
-	M_FreePlayerSetupColors();
-	I_ShutdownMusic();
-	I_ShutdownSound();
-	I_ShutdownCD();
-	I_ShutdownGraphics();
-	I_ShutdownSystem();
-
-	if (W_CheckNumForName("ENDOOM")!=LUMPERROR) endoom = W_CacheLumpName("ENDOOM",PU_CACHE);
-
-
-	//added:03-01-98: maybe it needs that the ticcount continues,
-	// or something else that will be finished by ShutdownSystem()
-	// so I do it before.
-
-	if (endoom)
-	{
-		puttext(1,1,80,25,endoom);
-		gotoxy(1,24);
-		Z_Free(endoom);
-	}
-
-	if (shutdowning || errorcount)
-		I_Error("Error detected (%d)",errorcount);
-
-	fflush(stderr);
-	W_Shutdown();
-	exit(0);
-}
-
-
-//added:12-02-98: does want to work!!!! rhaaahahha
-void I_WaitVBL(INT32 count)
-{
-	while (count-->0);
-	{
-		do { } while (inportb(0x3DA) & 8);
-		do { } while (!(inportb(0x3DA) & 8));
-	}
-}
-
-//  Fab: this is probably to activate the 'loading' disc icon
-//       it should set a flag, that I_FinishUpdate uses to know
-//       whether it draws a small 'loading' disc icon on the screen or not
-//
-//  also it should explicitly draw the disc because the screen is
-//  possibly not refreshed while loading
-//
-void I_BeginRead (void)
-{
-}
-
-//  Fab: see above, end the 'loading' disc icon, set the flag false
-//
-void I_EndRead (void)
-{
-}
-
-#define MOUSE2
-/* Secondary Mouse*/
-#ifdef MOUSE2
-static _go32_dpmi_seginfo oldmouseinfo,newmouseinfo;
-static boolean mouse2_started=0;
-static UINT16  mouse2port;
-static UINT8   mouse2irq;
-static volatile int     handlermouse2buttons;
-static volatile int     handlermouse2x,handlermouse2y;
-// internal use
-static volatile int     bytenum;
-static volatile UINT8   combytes[8];
-
-//
-// support a secondary mouse without mouse driver !
-//
-// take from the PC-GPE by Mark Feldman
-static void I_MicrosoftMouseIntHandler(void)
-{
-	char   dx,dy;
-	UINT8  inbyte;
-
-	// Get the port byte
-	inbyte = inportb(mouse2port);
-
-	// Make sure we are properly "synched"
-	if ((inbyte & 64)== 64 || bytenum>7)
-		bytenum = 0;
-
-	// Store the byte and adjust bytenum
-	combytes[bytenum] = inbyte;
-	bytenum++;
-
-	// Have we received all 3 bytes?
-	if (bytenum==3)
-	{
-		// Yes, so process them
-		dx = ((combytes[0] & 3) << 6) + combytes[1];
-		dy = ((combytes[0] & 12) << 4) + combytes[2];
-		handlermouse2x+= dx;
-		handlermouse2y+= dy;
-		handlermouse2buttons = (combytes[0] & (32+16)) >>4;
-	}
-	else if (bytenum==4) // for logitech 3 buttons
-	{
-		if (combytes[3] & 32)
-			handlermouse2buttons |= 4;
-		else
-			handlermouse2buttons &= ~4;
-	}
-
-	// Acknowledge the interrupt
-	outportb(0x20,0x20);
-}
-#ifndef DOXYGEN
-static END_OF_FUNCTION(I_MicrosoftMouseIntHandler);
-#endif
-
-// wait ms milliseconde
-FUNCINLINE static ATTRINLINE void I_Delay(int ms)
-{
-	tic_t  starttime;
-
-	if (timer_started)
-	{
-		starttime=I_GetTime()+(NEWTICRATE*ms)/1000;
-		while (starttime>=I_GetTime())
-			I_Sleep();
-	}
-	else
-		delay(ms);
-}
-
-//
-//  Removes the mouse2 handler.
-//
-static void I_ShutdownMouse2(void)
-{
-	event_t event;
-	int i;
-
-	if ( !mouse2_started )
-		return;
-
-	outportb(mouse2port+4,0x00);   // shutdown mouse (DTR & RTS = 0)
-	I_Delay(1);
-	outportb(mouse2port+1,0x00);   // disable COM interuption
-
-	asm("cli");
-	_go32_dpmi_set_protected_mode_interrupt_vector(mouse2irq, &oldmouseinfo);
-	_go32_dpmi_free_iret_wrapper(&newmouseinfo);
-	asm("sti");
-
-	handlermouse2x=handlermouse2y=handlermouse2buttons=0;
-	// emulate the up of all mouse buttons
-	for (i=0;i<MOUSEBUTTONS;i++)
-	{
-		event.type=ev_keyup;
-		event.data1=KEY_2MOUSE1+i;
-		D_PostEvent(&event);
-	}
-
-	mouse2_started=false;
-}
-
-static UINT8  ComIrq[4]={0x0c,0x0b,0x0c,0x0b};
-static UINT16 ComPort[4]={0x3F8,0x2F8,0x3E8,0x2E8};
-//
-//  Installs the mouse2 handler.
-//
-void I_StartupMouse2(void)
-{
-	tic_t i;
-	boolean  found;
-	__dpmi_regs r;
-
-	if ( mouse2_started )
-		I_ShutdownMouse2();
-
-	if (!cv_usemouse2.value)
-		return;
-
-	handlermouse2x=handlermouse2y=handlermouse2buttons=0;
-
-	mouse2irq =ComIrq[cv_mouse2port.value-1];
-	mouse2port=ComPort[cv_mouse2port.value-1];
-	CONS_Printf("Using %s (irq %d, port 0x%x)\n",cv_mouse2port.string,mouse2irq-8,mouse2port);
-	r.x.ax=0x24;
-	__dpmi_int(0x33,&r);
-	if (r.h.cl+8==mouse2irq)
-	{
-		CONS_Printf("Irq conflict with mouse 1\n"
-					"Use mouse2port to change the port\n");
-		return;
-	}
-
-	// install irq wrapper
-	asm("cli");
-	_go32_dpmi_get_protected_mode_interrupt_vector(mouse2irq, &oldmouseinfo);
-	newmouseinfo.pm_selector=_go32_my_cs();
-	newmouseinfo.pm_offset=(int)I_MicrosoftMouseIntHandler;
-	_go32_dpmi_allocate_iret_wrapper(&newmouseinfo);
-	_go32_dpmi_set_protected_mode_interrupt_vector(mouse2irq, &newmouseinfo);
-
-	LOCK_VARIABLE(bytenum);
-	LOCK_VARIABLE(handlermouse2x);
-	LOCK_VARIABLE(handlermouse2y);
-	LOCK_VARIABLE(handlermouse2buttons);
-	LOCK_VARIABLE(mouse2port);
-	_go32_dpmi_lock_data(&combytes,sizeof (combytes));
-	LOCK_FUNCTION(I_MicrosoftMouseIntHandler);
-	asm("sti");
-
-	outportb(mouse2port+4,0   );   // shutdown mouse (DTR & RTS = 0)
-	I_Delay(1);
-	outportb(mouse2port+1,0   );   // disable COM interuption
-	I_Delay(1);
-	outportb(mouse2port+3,0x80);   // change status of port +0 et +1
-	I_Delay(1);                    // for baudrate programmation
-	outportb(mouse2port  ,0x60);   // 1200 LSB
-	I_Delay(1);
-	outportb(mouse2port+1,0   );   // 1200 MSB
-	I_Delay(1);
-	outportb(mouse2port+3,0x02);   // set port protocol 7N1
-	I_Delay(1);
-	outportb(mouse2port+1,0x01);   // enable COM interuption
-	I_Delay(1);
-	outportb(0x21,0x0);
-
-	// wait to be sure the mouse have shutdown
-	I_Delay(100);
-
-	outportb(mouse2port+4,0x0b);   // restart mouse
-	i=I_GetTime()+NEWTICRATE;
-	found=cv_usemouse2.value==2;
-	while (I_GetTime()<i || !found)
-		if (combytes[0]!='M')
-			found=true;
-
-	if (found || cv_usemouse2.value==2)
-	{
-		CONS_Printf("Microsoft compatible Secondary Mouse detected\n");
-
-		//register shutdown mouse2 code.
-		I_AddExitFunc(I_ShutdownMouse2);
-		mouse2_started = true;
-	}
-	else
-	{
-		CONS_Printf("Secondary Mouse not found\n");
-		// remove irq wraper
-		I_ShutdownMouse2();
-	}
-}
-#endif
-
-//  Initialise the mouse. Doesnt need to be shutdown.
-//
-void I_StartupMouse (void)
-{
-	__dpmi_regs r;
-
-	// mouse detection may be skipped by setting usemouse false
-	if (cv_usemouse.value == 0)
-	{
-		mouse_detected=false;
-		I_ShutdownMouse2();
-		return;
-	}
-
-	//detect mouse presence
-	r.x.ax=0;
-	__dpmi_int(0x33,&r);
-
-	//added:03-01-98:
-	if ( r.x.ax == 0 && cv_usemouse.value != 2)
-	{
-		mouse_detected=false;
-		CONS_Printf("\2I_StartupMouse: mouse not present.\n");
-	}
-	else
-	{
-		mouse_detected=true;
-
-		// Check for CTMOUSE wheel
-		r.x.ax = 0x11;
-		__dpmi_int(0x33,&r);
-		if ( r.x.ax == 0x574D && r.x.cx & 0x1) // check for "MW" in AX and wheel mouse in CX
-		{
-			wheel_detected=true;
-		}
-
-		//hide cursor
-		r.x.ax=0x02;
-		__dpmi_int(0x33,&r);
-
-		//reset mickey count
-		r.x.ax=0x0b;
-		__dpmi_int(0x33,&r);
-	}
-}
-
-void I_GetJoystickEvents(void)
-{
-	event_t event;
-	INT64 joybuttons = 0;
-	INT64 joyhats = 0;
-	int s = 0, i;
-	int js = cv_usejoystick.value - 1;
-
-	if (!joystick_detected)
-		return;
-
-	// I assume that true is 1
-	for (i = JOYBUTTONS_MIN - 1; i >= 0; i--)
-	{
-		joybuttons <<= 1;
-		if (joy[js].button[i].b)
-			joybuttons |= 1;
-	}
-
-	for (i = JOYHATS_MIN -1; i >=0;)
-	{
-		if (joy[js].stick[s].flags &  JOYFLAG_DIGITAL)
-		{
-			if (joy[js].stick[s].axis[1].d1) joyhats |= 1<<(0 + 4*i);
-			if (joy[js].stick[s].axis[1].d2) joyhats |= 1<<(1 + 4*i);
-			if (joy[js].stick[s].axis[0].d1) joyhats |= 1<<(2 + 4*i);
-			if (joy[js].stick[s].axis[0].d2) joyhats |= 1<<(3 + 4*i);
-			i--;
-		}
-		if (s == JOYHATS_MAX) i = -1;
-		s++;
-	}
-
-	// post key event for buttons
-	if (joybuttons!=lastjoybuttons)
-	{
-		INT64 j = 1; // only changed bit to 1
-		INT64 k = (joybuttons ^ lastjoybuttons);
-		lastjoybuttons=joybuttons;
-
-		for (i=0;i<JOYBUTTONS && i<JOYBUTTONS_MAX;i++,j<<=1)
-			if (k & j)          // test the eatch bit and post the corresponding event
-			{
-				if (joybuttons & j)
-					event.type=ev_keydown;
-				else
-					event.type=ev_keyup;
-				event.data1=KEY_JOY1+i;
-				D_PostEvent(&event);
-			}
-	}
-
-	// post key event for hats
-	if (joyhats!=lastjoyhats)
-	{
-		INT64 j = 1; // only changed bit to 1
-		INT64 k = (joyhats ^ lastjoyhats);
-		lastjoyhats=joyhats;
-
-		for (i=0;i<JOYHATS && i<JOYHATS_MAX;i++,j<<=1)
-			if (k & j)          // test the eatch bit and post the corresponding event
-			{
-				if (joyhats & j)
-					event.type=ev_keydown;
-				else
-					event.type=ev_keyup;
-				event.data1=KEY_HAT1+i;
-				D_PostEvent(&event);
-			}
-	}
-
-	event.type=ev_joystick;
-	s = 0;
-
-	for (i = JOYAXISSET_MIN -1; i >=0;)
-	{
-		event.data1 = i;
-		event.data2 = event.data3 = 0;
-		if (joy[js].stick[s].flags &  JOYFLAG_DIGITAL)
-		{
-			if (joy[js].stick[s].axis[0].d1)
-				event.data2=-1;
-			if (joy[js].stick[s].axis[0].d2)
-				event.data2=1;
-			if (joy[js].stick[s].axis[1].d1)
-				event.data3=-1;
-			if (joy[js].stick[s].axis[1].d2)
-				event.data3=1;
-			D_PostEvent(&event);
-			i++;
-		}
-		else if (joy[js].stick[s].flags &  JOYFLAG_ANALOGUE)
-		{
-			event.data2 = joy[js].stick[s].axis[0].pos*32;
-			event.data3 = joy[js].stick[s].axis[1].pos*32;
-			D_PostEvent(&event);
-			i++;
-		}
-		if (s == JOYAXISSET_MAX*2) i = -1;
-		s++;
-	}
-}
-
-void I_GetJoystick2Events(void)
-{
-	event_t event;
-	INT64 joybuttons= 0;
-	INT64 joyhats = 0;
-	int s = 0, i;
-	int js = cv_usejoystick2.value - 1;
-
-	if (!joystick2_detected)
-		return;
-
-	// I assume that true is 1
-	for (i = JOYBUTTONS_MIN - 1; i >= 0; i--)
-	{
-		joybuttons <<= 1;
-		if (joy[js].button[i].b)
-			joybuttons |= 1;
-	}
-
-	for (i = JOYHATS_MIN -1; i >=0;)
-	{
-		if (joy[js].stick[s].flags &  JOYFLAG_DIGITAL)
-		{
-			if (joy[js].stick[s].axis[1].d1) joyhats |= 1<<(0 + 4*i);
-			if (joy[js].stick[s].axis[1].d2) joyhats |= 1<<(1 + 4*i);
-			if (joy[js].stick[s].axis[0].d1) joyhats |= 1<<(2 + 4*i);
-			if (joy[js].stick[s].axis[0].d2) joyhats |= 1<<(3 + 4*i);
-			i--;
-		}
-		if (s == JOYHATS_MAX) i = -1;
-		s++;
-	}
-
-	// post key event for buttons
-	if (joybuttons!=lastjoy2buttons)
-	{
-		INT64 j = 1; // only changed bit to 1
-		INT64 k = (joybuttons ^ lastjoy2buttons);
-		lastjoy2buttons=joybuttons;
-
-		for (i=0;i<JOYBUTTONS && i<JOYBUTTONS_MAX;i++,j<<=1)
-			if (k & j)          // test the eatch bit and post the corresponding event
-			{
-				if (joybuttons & j)
-					event.type=ev_keydown;
-				else
-					event.type=ev_keyup;
-				event.data1=KEY_2JOY1+i;
-				D_PostEvent(&event);
-			}
-	}
-
-	// post key event for hats
-	if (joyhats!=lastjoy2hats)
-	{
-		INT64 j=1; // only changed bit to 1
-		INT64 k = (joyhats ^ lastjoy2hats);
-		lastjoy2hats=joyhats;
-
-		for (i=0;i<JOYHATS && i<JOYHATS_MAX;i++,j<<=1)
-			if (k & j)          // test the eatch bit and post the corresponding event
-			{
-				if (joyhats & j)
-					event.type=ev_keydown;
-				else
-					event.type=ev_keyup;
-				event.data1=KEY_2HAT1+i;
-				D_PostEvent(&event);
-			}
-	}
-
-	event.type=ev_joystick2;
-	s = 0;
-
-	for (i = JOYAXISSET_MIN - 1; i >=0;)
-	{
-		event.data1 = i;
-		event.data2 = event.data3 = 0;
-		if (joy[js].stick[s].flags &  JOYFLAG_DIGITAL)
-		{
-			if (joy[js].stick[s].axis[0].d1)
-				event.data2=-1;
-			if (joy[js].stick[s].axis[0].d2)
-				event.data2=1;
-			if (joy[js].stick[s].axis[1].d1)
-				event.data3=-1;
-			if (joy[js].stick[s].axis[1].d2)
-				event.data3=1;
-			D_PostEvent(&event);
-			i++;
-		}
-		else if (joy[js].stick[s].flags &  JOYFLAG_ANALOGUE)
-		{
-			event.data2 = joy[js].stick[s].axis[0].pos*32;
-			event.data3 = joy[js].stick[s].axis[1].pos*32;
-			D_PostEvent(&event);
-			i++;
-		}
-		if (s == JOYAXISSET_MAX*2) i = -1;
-		s++;
-	}
-}
-
-void I_GetMouseEvents(void)
-{
-	//mouse movement
-	event_t event;
-	int xmickeys,ymickeys,buttons,wheels = 0;
-	static int lastbuttons=0;
-	__dpmi_regs r;
-
-	if (!mouse_detected)
-		return;
-
-	r.x.ax=0x0b;           // ask the mouvement not the position
-	__dpmi_int(0x33,&r);
-	xmickeys=(INT16)r.x.cx;
-	ymickeys=(INT16)r.x.dx;
-	r.x.ax=0x03;
-	__dpmi_int(0x33,&r);
-	buttons=r.h.bl;
-	if (wheel_detected)
-		wheels=(signed char)r.h.bh;
-
-	// post key event for buttons
-	if (buttons!=lastbuttons)
-	{
-		int j=1,k,i;
-		k=(buttons ^ lastbuttons); // only changed bit to 1
-		lastbuttons=buttons;
-
-		for (i=0;i<MOUSEBUTTONS;i++,j<<=1)
-			if (k & j)
-			{
-				if (buttons & j)
-					event.type=ev_keydown;
-				else
-					event.type=ev_keyup;
-				event.data1=KEY_MOUSE1+i;
-				D_PostEvent(&event);
-			}
-	}
-
-	event.type=ev_keyup;
-	event.data1 = 0;
-	if (wheels > 0)
-		event.data1 = KEY_MOUSEWHEELUP;
-	else if (wheels < 0)
-		event.data1 = KEY_MOUSEWHEELDOWN;
-	if (event.data1)
-			D_PostEvent(&event);
-
-
-	if ((xmickeys!=0)||(ymickeys!=0))
-	{
-		event.type=ev_mouse;
-		event.data1=0;
-		//event.data1=buttons;    // not needed
-		event.data2=xmickeys;
-		event.data3=-ymickeys;
-
-		D_PostEvent(&event);
-	}
-
-	//reset wheel like in win32, I don't understand it but works
-	gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0;
-
-}
-
-void I_GetEvent (void)
-{
-#ifdef MOUSE2
-	// mouse may be disabled during the game by setting usemouse false
-	if (mouse2_started)
-	{
-		event_t event;
-		//mouse movement
-		static UINT8 lastbuttons2=0;
-
-		// post key event for buttons
-		if (handlermouse2buttons!=lastbuttons2)
-		{
-			int j=1,k,i;
-			k=(handlermouse2buttons ^ lastbuttons2); // only changed bit to 1
-			lastbuttons2=handlermouse2buttons;
-
-			for (i=0;i<MOUSEBUTTONS;i++,j<<=1)
-				if (k & j)
-				{
-					if (handlermouse2buttons & j)
-						event.type=ev_keydown;
-					else
-						event.type=ev_keyup;
-					event.data1=KEY_2MOUSE1+i;
-					D_PostEvent(&event);
-				}
-		}
-
-		if ((handlermouse2x!=0)||(handlermouse2y!=0))
-		{
-			event.type=ev_mouse2;
-			event.data1=0;
-			//event.data1=buttons;    // not needed
-			event.data2=handlermouse2x<<1;
-			event.data3=-handlermouse2y<<1;
-
-			D_PostEvent(&event);
-			handlermouse2x=0;
-			handlermouse2y=0;
-		}
-
-	}
-#endif
-
-	//mouse
-	I_GetMouseEvents();
-
-	//joystick
-	if (joystick_detected || joystick2_detected)
-		poll_joystick();
-
-	//joystick1
-	I_GetJoystickEvents();
-
-	//joystick2
-	I_GetJoystick2Events();
-}
-
-INT32 I_NumJoys(void)
-{
-	return MAX_JOYSTICKS;
-}
-
-const char *I_GetJoyName(INT32 joyindex)
-{
-#if MAX_JOYSTICKS > 8
-"More Joystick Names?"
-#endif
-
-	     if (joyindex == 1) return "Joystick A";
-	else if (joyindex == 2) return "Joystick B";
-	else if (joyindex == 3) return "Joystick C";
-	else if (joyindex == 4) return "Joystick D";
-	else if (joyindex == 5) return "Joystick E";
-	else if (joyindex == 6) return "Joystick F";
-	else if (joyindex == 7) return "Joystick G";
-	else if (joyindex == 8) return "Joystick H";
-	else return NULL;
-
-}
-
-//
-//  Timer user routine called at ticrate.
-//
-static void I_TimerISR (void)
-{
-	//  IO_PlayerInput();      // old doom did that
-	ticcount++;
-
-}
-#ifndef DOXYGEN
-static END_OF_FUNCTION(I_TimerISR);
-#endif
-
-
-//added:08-01-98: we don't use allegro_exit() so we have to do it ourselves.
-static inline void I_ShutdownTimer (void)
-{
-	if ( !timer_started )
-		return;
-	remove_timer();
-}
-
-
-//
-//  Installs the timer interrupt handler with timer speed as NEWTICRATE.
-//
-void I_StartupTimer(void)
-{
-	ticcount = 0;
-
-	//lock this from being swapped to disk! BEFORE INSTALLING
-	LOCK_VARIABLE(ticcount);
-	LOCK_FUNCTION(I_TimerISR);
-
-	if ( install_timer() != 0 )
-		I_Error("I_StartupTimer: could not install timer.");
-
-	if ( install_int_ex( I_TimerISR, BPS_TO_TIMER(NEWTICRATE) ) != 0 )
-		//should never happen since we use only one.
-		I_Error("I_StartupTimer: no room for callback routine.");
-
-	//added:08-01-98: remove the timer explicitly because we don't use
-	//                Allegro 's allegro_exit() shutdown code.
-	I_AddExitFunc(I_ShutdownTimer);
-	timer_started = true;
-}
-
-
-//added:07-02-98:
-//
-//
-static UINT8 ASCIINames[128] =
-{
-//        0           1              2            3
-//        4           5              6            7
-//        8           9              A            B
-//        C           D              E            F
-          0,         27,           '1',         '2',
-        '3',        '4',           '5',         '6',
-        '7',        '8',           '9',         '0',
-  KEY_MINUS, KEY_EQUALS, KEY_BACKSPACE,     KEY_TAB,
-        'q',        'w',           'e',        'r',
-        't',        'y',           'u',        'i',
-        'o',        'p',           '[',        ']',
-  KEY_ENTER,  KEY_LCTRL,           'a',        's',
-        'd',        'f',           'g',        'h',
-        'j',        'k',           'l',        ';',
-       '\'',        '`',    KEY_LSHIFT,       '\\',
-        'z',        'x',           'c',        'v',
-        'b',        'n',           'm',        ',',
-        '.',        '/',    KEY_RSHIFT,        '*',
-   KEY_LALT,  KEY_SPACE,  KEY_CAPSLOCK,     KEY_F1,
-     KEY_F2,     KEY_F3,        KEY_F4,     KEY_F5,
-     KEY_F6,     KEY_F7,        KEY_F8,     KEY_F9,
-    KEY_F10,KEY_NUMLOCK,KEY_SCROLLLOCK,KEY_KEYPAD7,
-KEY_KEYPAD8,KEY_KEYPAD9,  KEY_MINUSPAD,KEY_KEYPAD4,
-KEY_KEYPAD5,KEY_KEYPAD6,   KEY_PLUSPAD,KEY_KEYPAD1,
-KEY_KEYPAD2,KEY_KEYPAD3,   KEY_KEYPAD0,KEY_KPADDEL,
-          0,          0,             0,    KEY_F11,
-    KEY_F12,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0,
-          0,          0,             0,          0
-};
-
-static volatile int pausepressed=0;
-static volatile char nextkeyextended;
-
-static void I_KeyboardHandler(void)
-{
-	UINT8 ch;
-	event_t       event;
-
-	ch=inportb(0x60);
-
-	if (pausepressed>0)
-		pausepressed--;
-	else if (ch==0xE1) // pause key
-	{
-		event.type=ev_keydown;
-		event.data1=KEY_PAUSE;
-		D_PostEvent(&event);
-		pausepressed=5;
-	}
-	else if (ch==0xE0) // extended key handled at next call
-	{
-		nextkeyextended=1;
-	}
-	else
-	{
-		if ((ch&0x80)==0)
-			event.type=ev_keydown;
-		else
-			event.type=ev_keyup;
-
-		ch&=0x7f;
-
-		if (nextkeyextended)
-		{
-			nextkeyextended=0;
-
-			if (ch==70)  // crtl-break
-			{
-				asm ("movb $0x79, %%al\ncall ___djgpp_hw_exception"
-				     : : :"%eax","%ebx","%ecx","%edx","%esi","%edi","memory");
-			}
-
-			// remap lonely keypad slash
-			if (ch==53)
-				event.data1 = KEY_KPADSLASH;
-			else if (ch>=91 && ch<=93) // remap the bill gates keys...
-				event.data1 = ch + 0x80;    // leftwin, rightwin, menu
-			else if (ch>=71 && ch<=83) // remap non-keypad extended keys to a value<128, but
-				event.data1 = 0x80 + ch + 30; // make them different than the KEYPAD keys.
-			else if (ch==28)
-				event.data1 = KEY_ENTER;    // keypad enter -> return key
-			else if (ch==29)
-				event.data1 = KEY_RCTRL;     // rctrl -> lctrl
-			else if (ch==56)
-				event.data1 = KEY_RALT;      // ralt -> lalt
-			else
-				ch = 0;
-			if (ch)
-				D_PostEvent(&event);
-		}
-		else
-		{
-			if (ASCIINames[ch]!=0)
-				event.data1=ASCIINames[ch];
-			else
-				event.data1=ch+0x80;
-			D_PostEvent(&event);
-		}
-	}
-
-	outportb(0x20,0x20);
-}
-#ifndef DOXYGEN
-static END_OF_FUNCTION(I_KeyboardHandler);
-#endif
-
-//  Return a key that has been pushed, or 0
-//  (replace getchar() at game startup)
-//
-INT32 I_GetKey (void)
-{
-	int rc=0;
-	if ( keyboard_started )
-	{
-		event_t   *ev;
-
-		// return the first keypress from the event queue
-		for ( ; eventtail != eventhead ; eventtail = (eventtail+1)&(MAXEVENTS-1) )
-		{
-			ev = &events[eventtail];
-			if (ev->type == ev_keydown || ev->type == ev_console)
-			{
-				rc = ev->data1;
-				continue;
-			}
-		}
-		return rc;
-	}
-
-	// keyboard not started use the bios call trouth djgpp
-	if (_conio_kbhit())
-	{
-		rc=getch();
-		if (rc==0) rc=getch()+256;
-	}
-	else
-		rc = 0;
-
-	return rc;
-}
-
-/* Keyboard handler stuff */
-static _go32_dpmi_seginfo oldkeyinfo,newkeyinfo;
-
-//
-//  Removes the keyboard handler.
-//
-static inline void I_ShutdownKeyboard(void)
-{
-	if ( !keyboard_started )
-		return;
-
-	asm("cli");
-	_go32_dpmi_set_protected_mode_interrupt_vector(9, &oldkeyinfo);
-	_go32_dpmi_free_iret_wrapper(&newkeyinfo);
-	asm("sti");
-
-	keyboard_started=false;
-}
-
-//
-//  Installs the keyboard handler.
-//
-void I_StartupKeyboard(void)
-{
-	if (keyboard_started)
-		return;
-
-	nextkeyextended=0;
-
-	asm("cli");
-	_go32_dpmi_get_protected_mode_interrupt_vector(9, &oldkeyinfo);
-	newkeyinfo.pm_offset=(int)I_KeyboardHandler;
-	newkeyinfo.pm_selector=_go32_my_cs();
-	_go32_dpmi_allocate_iret_wrapper(&newkeyinfo);
-	_go32_dpmi_set_protected_mode_interrupt_vector(9, &newkeyinfo);
-
-	LOCK_VARIABLE(nextkeyextended);
-	LOCK_VARIABLE(pausepressed);
-	_go32_dpmi_lock_data(ASCIINames,sizeof (ASCIINames));
-	LOCK_FUNCTION(I_KeyboardHandler);
-
-	_go32_dpmi_lock_data(events,sizeof (events));
-	LOCK_VARIABLE(eventhead);
-	LOCK_FUNCTION(D_PostEvent);
-
-	asm("sti");
-
-	//added:08-01-98:register shutdown keyboard code.
-	I_AddExitFunc(I_ShutdownKeyboard);
-	keyboard_started = true;
-}
-
-
-
-
-//added:08-01-98:
-//
-//  Clean Startup & Shutdown handling, as does Allegro.
-//  We need this services for ourselves too, and we don't want to mix
-//  with Allegro, because someone might not use Allegro.
-//  (all 'exit' was renamed to 'quit')
-//
-#define MAX_QUIT_FUNCS     16
-static quitfuncptr quit_funcs[MAX_QUIT_FUNCS] =
-			{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-			  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
-
-//added:08-01-98:
-//
-//  Adds a function to the list that need to be called by I_SystemShutdown().
-//
-void I_AddExitFunc(void (*func)())
-{
-	int c;
-
-	for (c=0; c<MAX_QUIT_FUNCS; c++)
-	{
-		if (!quit_funcs[c])
-		{
-			quit_funcs[c] = func;
-			break;
-		}
-	}
-}
-
-
-//added:08-01-98:
-//
-//  Removes a function from the list that need to be called by
-//   I_SystemShutdown().
-//
-void I_RemoveExitFunc(void (*func)())
-{
-	int c;
-
-	for (c=0; c<MAX_QUIT_FUNCS; c++)
-	{
-		if (quit_funcs[c] == func)
-		{
-			while (c<MAX_QUIT_FUNCS-1)
-			{
-				quit_funcs[c] = quit_funcs[c+1];
-				c++;
-			}
-			quit_funcs[MAX_QUIT_FUNCS-1] = NULL;
-			break;
-		}
-	}
-}
-
-
-
- //added:03-01-98:
-//
-// signal_handler:
-//  Used to trap various signals, to make sure things get shut down cleanly.
-//
-static inline void exception_handler(int num)
-{
-	static char msg[255];
-	sprintf(msg,"Sonic Robo Blast 2 "VERSIONSTRING"\r\n"
-	        "This is a error of SRB2, try to send the following info to programmers\r\n");
-
-	//D_QuitNetGame ();  //say 'byebye' to other players when your machine
-						// crashes?... hmm... do they have to die with you???
-
-	I_ShutdownSystem();
-
-	_write(STDERR_FILENO, msg, strlen(msg));
-
-	signal(num, SIG_DFL);
-	raise(num);
-	/// \todo write it in a log !!
-}
-
-static inline void break_handler(int num)
-{
-static char msg[] = "Oh no! Back to reality!\r\n";
-
-	//D_QuitNetGame ();  //say 'byebye' to other players when your machine
-						// crashes?... hmm... do they have to die with you???
-
-	I_ShutdownSystem();
-
-	_write(STDERR_FILENO, msg, sizeof (msg)-1);
-
-	signal(num, SIG_DFL);
-	raise(num);
-}
-
-
-//added:08-01-98: now this replaces allegro_init()
-//
-// REMEMBER: THIS ROUTINE MUST BE STARTED IN i_main.c BEFORE D_SRB2Main()
-//
-// This stuff should get rid of the exception and page faults when
-// SRB2 bugs out with an error. Now it should exit cleanly.
-//
-INT32 I_StartupSystem(void)
-{
-	I_DetectOS();
-	check_cpu();
-
-	// some 'more globals than globals' things to initialize here ?
-	graphics_started = false;
-	keyboard_started = false;
-	sound_started = false;
-	timer_started = false;
-	cdaudio_started = false;
-
-	// check for OS type and version here ?
-
-
-	signal(SIGABRT, exception_handler);
-	signal(SIGFPE , exception_handler);
-	signal(SIGILL , exception_handler);
-	signal(SIGSEGV, exception_handler);
-	signal(SIGINT , break_handler);
-	signal(SIGKILL, break_handler);
-	signal(SIGQUIT, break_handler);
-
-	return 0;
-}
-
-
-//added:08-01-98:
-//
-//  Closes down everything. This includes restoring the initial
-//  pallete and video mode, and removing whatever mouse, keyboard, and
-//  timer routines have been installed.
-//
-//  NOTE : Shutdown user funcs. are effectively called in reverse order.
-//
-void I_ShutdownSystem(void)
-{
-	int c;
-
-	for (c=MAX_QUIT_FUNCS-1; c>=0; c--)
-		if (quit_funcs[c])
-			(*quit_funcs[c])();
-}
-
-void I_GetDiskFreeSpace(INT64 *freespace)
-{
-	struct diskfree_t df;
-	if (_dos_getdiskfree(0,&df))
-		*freespace = (unsigned long)df.avail_clusters *
-		             (unsigned long)df.bytes_per_sector *
-		             (unsigned long)df.sectors_per_cluster;
-	else
-		*freespace = INT32_MAX;
-}
-
-char *I_GetUserName(void)
-{
-	static char username[MAXPLAYERNAME];
-	char  *p;
-	if ((p=getenv("USER"))==NULL)
-		if ((p=getenv("user"))==NULL)
-			if ((p=getenv("USERNAME"))==NULL)
-				if ((p=getenv("username"))==NULL)
-					return NULL;
-	strncpy(username,p,MAXPLAYERNAME);
-
-	if (strcmp(username,"")==0 )
-		return NULL;
-	return username;
-}
-
-INT32 I_mkdir(const char *pdirname, INT32 unixright)
-{
-	return mkdir(pdirname, unixright);
-}
-
-char * I_GetEnv(const char *name)
-{
-	return getenv(name);
-}
-
-INT32 I_PutEnv(char *variable)
-{
-	return putenv(variable);
-}
-
-INT32 I_ClipboardCopy(const char *data, size_t size)
-{
-	(void)data;
-	(void)size;
-	return -1;
-}
-
-char *I_ClipboardPaste(void)
-{
-	return NULL;
-}
-
-const CPUInfoFlags *I_CPUInfo(void)
-{
-	static CPUInfoFlags DOS_CPUInfo;
-	memset(&DOS_CPUInfo,0,sizeof (DOS_CPUInfo));
-#if ALLEGRO_VERSION == 3
-	if (!cpu_cpuid) return NULL;
-	DOS_CPUInfo.CPUID       = true;
-	DOS_CPUInfo.MMX         = cpu_mmx;
-	DOS_CPUInfo.AMD3DNow    = cpu_3dnow;
-#else
-	DOS_CPUInfo.CPUID       = ((cpu_capabilities&CPU_ID)       ==       CPU_ID);
-	DOS_CPUInfo.FPU         = ((cpu_capabilities&CPU_FPU)      ==      CPU_FPU);
-#ifdef CPU_IA64
-	DOS_CPUInfo.IA64        = ((cpu_capabilities&CPU_IA64)     ==     CPU_IA64);
-#endif
-#ifdef CPU_AMD64
-	DOS_CPUInfo.AMD64       = ((cpu_capabilities&CPU_AMD64)    ==    CPU_AMD64);
-#endif
-	DOS_CPUInfo.MMX         = ((cpu_capabilities&CPU_MMX)      ==      CPU_MMX);
-	DOS_CPUInfo.MMXExt      = ((cpu_capabilities&CPU_MMXPLUS)  ==  CPU_MMXPLUS);
-	DOS_CPUInfo.SSE         = ((cpu_capabilities&CPU_SSE)      ==      CPU_SSE);
-	DOS_CPUInfo.SSE2        = ((cpu_capabilities&CPU_SSE2)     ==     CPU_SSE2);
-#ifdef CPU_SEE3
-	DOS_CPUInfo.SSE3        = ((cpu_capabilities&CPU_SSE3)     ==     CPU_SSE3);
-#endif
-	DOS_CPUInfo.AMD3DNow    = ((cpu_capabilities&CPU_3DNOW)    ==    CPU_3DNOW);
-	DOS_CPUInfo.AMD3DNowExt = ((cpu_capabilities&CPU_ENH3DNOW) == CPU_ENH3DNOW);
-	DOS_CPUInfo.CMOV        = ((cpu_capabilities&CPU_CMOV)     ==     CPU_CMOV);
-#endif
-	return &DOS_CPUInfo;
-}
-
-void I_RegisterSysCommands(void) {}
diff --git a/src/djgppdos/i_video.c b/src/djgppdos/i_video.c
deleted file mode 100644
index d2483e318654f692d68a5270979c8c11c65326a7..0000000000000000000000000000000000000000
--- a/src/djgppdos/i_video.c
+++ /dev/null
@@ -1,345 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief hardware and software level, screen and video i/o, refresh,
-///	setup ... a big mess. Got to clean that up!
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <sys/time.h>
-#include <sys/types.h>
-//#include <sys/socket.h>
-
-#include <netinet/in.h>
-//#include <errnos.h>
-#include <signal.h>
-
-#include <go32.h>
-#include <pc.h>
-#include <dpmi.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-
-#include "../doomdef.h"
-#include "../i_system.h"
-#include "../v_video.h"
-#include "../m_argv.h"
-#include "vid_vesa.h"
-#include "../i_video.h"
-
-
-//dosstuff -newly added
-static unsigned long dascreen;
-static int gfx_use_vesa1;
-
-boolean    highcolor;
-
-#define SCREENDEPTH   1     // bytes per pixel, do NOT change.
-
-rendermode_t    rendermode=render_soft;
-
-//
-// I_OsPolling
-//
-void I_OsPolling(void)
-{
-	I_GetEvent();
-	//i dont think i have to do anything else here
-}
-
-
-//
-// I_UpdateNoBlit
-//
-void I_UpdateNoBlit (void)
-{
-	// what is this?
-}
-
-
-//profile stuff ---------------------------------------------------------
-//added:16-01-98:wanted to profile the VID_BlitLinearScreen() asm code.
-//#define TIMING      //uncomment this to enable profiling
-#ifdef TIMING
-#include "../p5prof.h"
-static   INT64 mycount;
-static   INT64 mytotal = 0;
-static   unsigned long  nombre = NEWTICRATE*10;
-//static   char runtest[10][80];
-#endif
-//profile stuff ---------------------------------------------------------
-
-//
-// I_FinishUpdate
-//
-static void I_BlitScreenVesa1(void);   //see later
-void I_FinishUpdate (void)
-{
-	if (marathonmode)
-		SCR_DisplayMarathonInfo();
-
-	// draw captions if enabled
-	if (cv_closedcaptioning.value)
-		SCR_ClosedCaptions();
-
-	// draw FPS if enabled
-	if (cv_ticrate.value)
-		SCR_DisplayTicRate();
-
-	if (cv_showping.value && netgame && consoleplayer != serverplayer)
-		SCR_DisplayLocalPing();
-
-	//blast it to the screen
-	// this code sucks
-	//memcpy(dascreen,screens[0],screenwidth*screenheight);
-
-	//added:03-01-98: I tried to I_WaitVBL(1) here, but it slows down
-	//  the game when the view becomes complicated, it looses ticks
-	if (cv_vidwait.value)
-		I_WaitVBL(1);
-
-
-//added:16-01-98:profile screen blit.
-#ifdef TIMING
-	ProfZeroTimer();
-#endif
-	//added:08-01-98: support vesa1 bank change, without Allegro's BITMAP screen.
-	if ( gfx_use_vesa1 )
-	{
-		I_Error("Banked screen update not finished for dynamic res\n");
-		I_BlitScreenVesa1();    //blast virtual to physical screen.
-	}
-	else
-	{
-		//added:16-01-98:use quickie asm routine, last 2 args are
-		//                   src and dest rowbytes
-		//                   (memcpy is as fast as this one...)
-		VID_BlitLinearScreen(screens[0], vid.direct,
-		                     vid.width*vid.bpp, vid.height,
-		                     vid.width*vid.bpp, vid.rowbytes );
-	}
-#ifdef TIMING
-	RDMSR(0x10,&mycount);
-	mytotal += mycount;   //64bit add
-
-	if (nombre--==0)
-		I_Error("ScreenBlit CPU Spy reports: 0x%d %d\n", *((int *)&mytotal+1),
-		        (int)mytotal );
-#endif
-
-}
-
-//
-// I_UpdateNoVsync
-//
-void I_UpdateNoVsync(void)
-{
-	int real_vidwait = cv_vidwait.value;
-	cv_vidwait.value = 0;
-	I_FinishUpdate();
-	cv_vidwait.value = real_vidwait;
-}
-
-//
-// I_ReadScreen
-//
-void I_ReadScreen (UINT8 *scr)
-{
-	VID_BlitLinearScreen(screens[0], scr,
-	                     vid.width*vid.bpp, vid.height,
-	                     vid.width*vid.bpp, vid.rowbytes );
-}
-
-
-void I_SetPalette (RGBA_t *palette)
-{
-	int i;
-
-	outportb(0x3c8,0);
-	for (i=0;i<256;i++,palette++)
-	{
-		outportb(0x3c9,palette->s.red>>2);
-		outportb(0x3c9,palette->s.green>>2);
-		outportb(0x3c9,palette->s.blue>>2);
-	}
-}
-
-
-//added 29-12-1997
-/*==========================================================================*/
-// I_BlastScreen : copy the virtual screen buffer to the physical screen mem
-//                 using bank switching if needed.
-/*==========================================================================*/
-static void I_BlitScreenVesa1(void)
-{
-#define VIDBANKSIZE     (1<<16)
-#define VIDBANKSIZEMASK (VIDBANKSIZE-1)   // defines ahoy!
-
-	__dpmi_regs r;
-	UINT8 *p_src;
-	long     i;
-	long     virtualsize;
-
-	// virtual screen buffer size
-	virtualsize = vid.rowbytes * vid.height * SCREENDEPTH;
-
-	p_src  = screens[0];
-
-	for (i=0; virtualsize > 0; i++ )
-	{
-		r.x.ax = 0x4f05;
-		r.x.bx = 0x0;
-		r.x.cx = 0x0;
-		r.x.dx = i;
-		__dpmi_int(0x10,&r);      //set bank
-
-		M_Memcpy((UINT8 *)dascreen,p_src,(virtualsize < VIDBANKSIZE) ? virtualsize : VIDBANKSIZE );
-
-		p_src += VIDBANKSIZE;
-		virtualsize -= VIDBANKSIZE;
-	}
-
-}
-
-
-//added:08-01-98: now we use Allegro's set_gfx_mode, but we want to
-//                restore the exact text mode that was before.
-static INT16  myOldVideoMode;
-static inline void I_SaveOldVideoMode(void)
-{
-	__dpmi_regs r;
-	r.x.ax = 0x4f03;                 // Return current video mode
-	__dpmi_int(0x10,&r);
-	if ( r.x.ax != 0x4f )
-		myOldVideoMode = -1;
-	else
-		myOldVideoMode = r.x.bx;
-}
-
-
-//
-//  Close the screen, restore previous video mode.
-//
-void I_ShutdownGraphics (void)
-{
-	__dpmi_regs r;
-
-	rendermode = render_none;
-	if ( !graphics_started )
-		return;
-
-	// free the last video mode screen buffers
-	if (vid.buffer)
-		free (vid.buffer);
-
-	/* Restore old video mode */
-	if (myOldVideoMode!=-1)
-	{
-		/* Restore old video mode */
-		r.x.ax = 0x4f02;                 // Set Super VGA video mode
-		r.x.bx = myOldVideoMode;
-		__dpmi_int(0x10,&r);
-
-		// Boris: my s3 don't do a cls because "win95" :<
-		clrscr();
-	}
-	else  // no vesa put the normal video mode
-	{
-		r.x.ax = 0x03;
-		__dpmi_int(0x10,&r);
-	}
-
-	graphics_started = false;
-}
-
-
-//added:08-01-98:
-//  Set VESA1 video mode, coz Allegro set_gfx_mode a larger screenwidth...
-//
-#if 0
-int set_vesa1_mode( int width, int height )
-{
-	__dpmi_regs r;
-
-	// setup video mode.
-	r.x.ax = 0x4f02;
-	if ( ( width==320 )&&( height==200 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x13;                             // 320x 200x1 (256 colors)
-	else
-	if ( ( width==320 )&&( height==240 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x154;                            // 320x 240x1 (256 colors)
-	else
-	if ( ( width==320 )&&( height==400 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x155;                            // 320x 400x1 (256 colors)
-	else
-	if ( ( width==640 )&&( height==400 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x100;                            // 640x 400x1 (256 colors)
-	else
-	if ( ( width==640 )&&( height==480 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x101;                            // 640x 480x1 (256 colors)
-	else
-	if ( ( width==800 )&&( height==600 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x103;                            // 800x 600x1 (256 colors)
-	else
-	if ( ( width==1024)&&( height==768 ) && ( SCREENDEPTH==1 ) )
-		r.x.bx   = 0x105;                            //1024x 768x1 (256 colors)
-	else
-		I_Error("I_SetVesa1Mode: video mode not supported.");
-
-	// enter graphics mode.
-	__dpmi_int(0x10,&r);
-
-	if ( r.x.ax != 0x4f )
-		I_Error("I_SetVesa1Mode: init video mode failed !");
-
-	return 0;
-}
-#endif
-
-
-//added:08-01-98: now uses Allegro to setup Linear Frame Buffer video modes.
-//
-//  Initialize video mode, setup dynamic screen size variables,
-//  and allocate screens.
-//
-void I_StartupGraphics(void)
-{
-	//added:26-01-98: VID_Init() must be done only once,
-	//                use VID_SetMode() to change vid mode while in the game.
-	if ( graphics_started )
-		return;
-
-	// remember the exact screen mode we were...
-	I_SaveOldVideoMode();
-
-	CONS_Printf("Vid_Init...");
-
-	// 0 for 256 color, else use highcolor modes
-	highcolor = M_CheckParm ("-highcolor");
-
-	VID_Init();
-
-	//gfx_use_vesa1 = false;
-
-	//added:03-01-98: register exit code for graphics
-	I_AddExitFunc(I_ShutdownGraphics);
-	graphics_started = true;
-
-}
-
-void VID_StartupOpenGL(void) {}
diff --git a/src/djgppdos/internal.h b/src/djgppdos/internal.h
deleted file mode 100644
index 94c1a052b4f7adc5e3c2c567b233ced12da3919e..0000000000000000000000000000000000000000
--- a/src/djgppdos/internal.h
+++ /dev/null
@@ -1,773 +0,0 @@
-/*         ______   ___    ___ 
- *        /\  _  \ /\_ \  /\_ \ 
- *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
- *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
- *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
- *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
- *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
- *                                           /\____/
- *                                           \_/__/
- *
- *      Some definitions for internal use by the library code.
- *      This should not be included by user programs.
- *
- *      By Shawn Hargreaves.
- *
- *      See readme.txt for copyright information.
- */
-
-
-#ifndef INTERNAL_H
-#define INTERNAL_H
-
-#include "allegro.h"
-
-/*         ______   ___    ___ 
- *        /\  _  \ /\_ \  /\_ \ 
- *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
- *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
- *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
- *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
- *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
- *                                           /\____/
- *                                           \_/__/
- *
- *      Some definitions for internal use by the library code.
- *      This should not be included by user programs.
- *
- *      By Shawn Hargreaves.
- *
- *      See readme.txt for copyright information.
- */
-
-
-#ifndef INTERNDJ_H
-#define INTERNDJ_H
-
-#ifndef DJGPP
-#error This file should only be used by the djgpp version of Allegro
-#endif
-
-
-#include <dos.h>
-
-
-/* file access macros */
-#define FILE_OPEN(filename, handle)             handle = open(filename, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR)
-#define FILE_CREATE(filename, handle)           handle = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)
-#define FILE_CLOSE(handle)                      close(handle)
-#define FILE_READ(handle, buf, size, sz)        sz = read(handle, buf, size)
-#define FILE_WRITE(handle, buf, size, sz)       sz = write(handle, buf, size) 
-#define FILE_SEARCH_STRUCT                      struct ffblk
-#define FILE_FINDFIRST(filename, attrib, dta)   findfirst(filename, dta, attrib)
-#define FILE_FINDNEXT(dta)                      findnext(dta)
-#define FILE_ATTRIB                             ff_attrib
-#define FILE_SIZE                               ff_fsize
-#define FILE_NAME                               ff_name
-#define FILE_TIME                               ff_ftime
-#define FILE_DATE                               ff_fdate
-
-
-/* macros to enable and disable interrupts */
-#define DISABLE()   asm volatile ("cli")
-#define ENABLE()    asm volatile ("sti")
-
-
-__INLINE__ void enter_critical(void) 
-{
-   if (windows_version >= 3) {
-      __dpmi_regs r;
-      r.x.ax = 0x1681; 
-      __dpmi_int(0x2F, &r);
-   }
-
-   DISABLE();
-}
-
-
-__INLINE__ void exit_critical(void) 
-{
-   if (windows_version >= 3) {
-      __dpmi_regs r;
-      r.x.ax = 0x1682; 
-      __dpmi_int(0x2F, &r);
-   }
-
-   ENABLE();
-}
-
-
-/* interrupt hander stuff */
-#define _map_irq(irq)   (((irq)>7) ? ((irq)+104) : ((irq)+8))
-
-int _install_irq(int num, int (*handler)(void));
-void _remove_irq(int num);
-void _restore_irq(int irq);
-void _enable_irq(int irq);
-void _disable_irq(int irq);
-
-#define _eoi(irq) { outportb(0x20, 0x20); if ((irq)>7) outportb(0xA0, 0x20); }
-
-typedef struct _IRQ_HANDLER
-{
-   int (*handler)(void);         /* our C handler */
-   int number;                   /* irq number */
-   __dpmi_paddr old_vector;      /* original protected mode vector */
-} _IRQ_HANDLER;
-
-
-/* DPMI memory mapping routines */
-int _create_physical_mapping(unsigned long *linear, int *segment, unsigned long physaddr, int size);
-void _remove_physical_mapping(unsigned long *linear, int *segment);
-int _create_linear_mapping(unsigned long *linear, unsigned long physaddr, int size);
-void _remove_linear_mapping(unsigned long *linear);
-int _create_selector(int *segment, unsigned long linear, int size);
-void _remove_selector(int *segment);
-void _unlock_dpmi_data(void *addr, int size);
-
-
-/* bank switching routines */
-void _accel_bank_stub(void);
-void _accel_bank_stub_end(void);
-
-void _accel_bank_switch (void);
-void _accel_bank_switch_end(void);
-
-void _vesa_window_1(void);
-void _vesa_window_1_end(void);
-void _vesa_window_2(void);
-void _vesa_window_2_end(void);
-
-void _vesa_pm_window_1(void);
-void _vesa_pm_window_1_end(void);
-void _vesa_pm_window_2(void);
-void _vesa_pm_window_2_end(void);
-
-void _vesa_pm_es_window_1(void);
-void _vesa_pm_es_window_1_end(void);
-void _vesa_pm_es_window_2(void);
-void _vesa_pm_es_window_2_end(void);
-
-
-/* stuff for the VESA and VBE/AF drivers */
-extern __dpmi_regs _dpmi_reg;
-
-extern int _window_2_offset;
-
-extern void (*_pm_vesa_switcher)(void);
-extern void (*_pm_vesa_scroller)(void);
-extern void (*_pm_vesa_pallete)(void);
-
-extern int _mmio_segment;
-
-extern void *_accel_driver;
-
-extern int _accel_active;
-
-extern void *_accel_set_bank;
-extern void *_accel_idle;
-
-void _fill_vbeaf_libc_exports(void *ptr);
-void _fill_vbeaf_pmode_exports(void *ptr);
-
-
-/* sound lib stuff */
-extern int _fm_port;
-extern int _mpu_port;
-extern int _mpu_irq;
-extern int _sb_freq;
-extern int _sb_port; 
-extern int _sb_dma; 
-extern int _sb_irq; 
-
-int _sb_read_dsp_version(void);
-int _sb_reset_dsp(int data);
-void _sb_voice(int state);
-int _sb_set_mixer(int digi_volume, int midi_volume);
-
-void _mpu_poll(void);
-
-int _dma_allocate_mem(int bytes, int *sel, unsigned long *phys);
-void _dma_start(int channel, unsigned long addr, int size, int auto_init, int input);
-void _dma_stop(int channel);
-unsigned long _dma_todo(int channel);
-void _dma_lock_mem(void);
-
-
-#endif          /* ifndef INTERNDJ_H */
-
-
-/* flag for how many times we have been initialised */
-extern int _allegro_count;
-
-
-/* some Allegro functions need a block of scratch memory */
-extern void *_scratch_mem;
-extern int _scratch_mem_size;
-
-__INLINE__ void _grow_scratch_mem(int size)
-{
-   if (size > _scratch_mem_size) {
-      size = (size+1023) & 0xFFFFFC00;
-      _scratch_mem = realloc(_scratch_mem, size);
-      _scratch_mem_size = size;
-   }
-}
-
-
-/* list of functions to call at program cleanup */
-void _add_exit_func(void (*func)(void));
-void _remove_exit_func(void (*func)(void));
-
-
-/* reads a translation file into memory */
-void _load_config_text(void);
-
-
-/* various bits of mouse stuff */
-void _set_mouse_range(void);
-extern BITMAP *_mouse_screen;
-extern BITMAP *_mouse_sprite, *_mouse_pointer;
-extern int _mouse_x_focus, _mouse_y_focus;
-extern int _mouse_width, _mouse_height;
-
-
-/* various bits of timer stuff */
-extern int _timer_use_retrace;
-extern volatile int _retrace_hpp_value;
-
-
-/* caches and tables for svga bank switching */
-extern int _last_bank_1, _last_bank_2; 
-extern int *_gfx_bank; 
-
-
-/* bank switching routines */
-void _stub_bank_switch (void);
-void _stub_bank_switch_end(void);
-
-
-/* stuff for setting up bitmaps */
-void _check_gfx_virginity(void);
-BITMAP *_make_bitmap(int w, int h, unsigned long addr, GFX_DRIVER *driver, int color_depth, int bpl);
-void _sort_out_virtual_width(int *width, GFX_DRIVER *driver);
-
-GFX_VTABLE *_get_vtable(int color_depth);
-
-extern GFX_VTABLE _screen_vtable;
-
-extern int _sub_bitmap_id_count;
-
-extern int _textmode;
-
-#define BYTES_PER_PIXEL(bpp)     (((int)(bpp) + 7) / 8)
-
-int _color_load_depth(int depth);
-
-extern int _color_conv;
-
-BITMAP *_fixup_loaded_bitmap(BITMAP *bmp, PALETTE pal, int bpp);
-
-
-/* VGA register access routines */
-void _vga_vsync(void);
-void _vga_set_pallete_range(PALLETE p, int from, int to, int vsync);
-
-extern int _crtc;
-
-
-/* _read_vga_register:
- *  Reads the contents of a VGA register.
- */
-__INLINE__ int _read_vga_register(int port, int index)
-{
-   if (port==0x3C0)
-      inportb(_crtc+6); 
-
-   outportb(port, index);
-   return inportb(port+1);
-}
-
-
-/* _write_vga_register:
- *  Writes a byte to a VGA register.
- */
-__INLINE__ void _write_vga_register(int port, int index, int v) 
-{
-   if (port==0x3C0) {
-      inportb(_crtc+6);
-      outportb(port, index);
-      outportb(port, v);
-   }
-   else {
-      outportb(port, index);
-      outportb(port+1, v);
-   }
-}
-
-
-/* _alter_vga_register:
- *  Alters specific bits of a VGA register.
- */
-__INLINE__ void _alter_vga_register(int port, int index, int mask, int v)
-{
-   int temp;
-   temp = _read_vga_register(port, index);
-   temp &= (~mask);
-   temp |= (v & mask);
-   _write_vga_register(port, index, temp);
-}
-
-
-/* _vsync_out_h:
- *  Waits until the VGA is not in either a vertical or horizontal retrace.
- */
-__INLINE__ void _vsync_out_h(void)
-{
-   do {
-   } while (inportb(0x3DA) & 1);
-}
-
-
-/* _vsync_out_v:
- *  Waits until the VGA is not in a vertical retrace.
- */
-__INLINE__ void _vsync_out_v(void)
-{
-   do {
-   } while (inportb(0x3DA) & 8);
-}
-
-
-/* _vsync_in:
- *  Waits until the VGA is in the vertical retrace period.
- */
-__INLINE__ void _vsync_in(void)
-{
-   if (_timer_use_retrace) {
-      int t = retrace_count; 
-
-      do {
-      } while (t == retrace_count);
-   }
-   else {
-      do {
-      } while (!(inportb(0x3DA) & 8));
-   }
-}
-
-
-/* _write_hpp:
- *  Writes to the VGA pelpan register.
- */
-__INLINE__ void _write_hpp(int value)
-{
-   if (_timer_use_retrace) {
-      _retrace_hpp_value = value;
-
-      do {
-      } while (_retrace_hpp_value == value);
-   }
-   else {
-      do {
-      } while (!(inportb(0x3DA) & 8));
-
-      _write_vga_register(0x3C0, 0x33, value);
-   }
-}
-
-
-void _set_vga_virtual_width(int old_width, int new_width);
-
-
-/* current drawing mode */
-extern int _drawing_mode;
-extern BITMAP *_drawing_pattern;
-extern int _drawing_x_anchor;
-extern int _drawing_y_anchor;
-extern unsigned int _drawing_x_mask;
-extern unsigned int _drawing_y_mask;
-
-
-/* graphics drawing routines */
-void _normal_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
-void _normal_rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
-
-int  _linear_getpixel8(struct BITMAP *bmp, int x, int y);
-void _linear_putpixel8(struct BITMAP *bmp, int x, int y, int color);
-void _linear_vline8(struct BITMAP *bmp, int x, int y1, int y2, int color);
-void _linear_hline8(struct BITMAP *bmp, int x1, int y, int x2, int color);
-void _linear_draw_sprite8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_v_flip8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_h_flip8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_vh_flip8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_trans_sprite8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_lit_sprite8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_draw_rle_sprite8(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_trans_rle_sprite8(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_lit_rle_sprite8(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color);
-void _linear_draw_character8(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_textout_fixed8(struct BITMAP *bmp, void *f, int h, unsigned char *str, int x, int y, int color);
-void _linear_blit8(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_blit_backward8(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_masked_blit8(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_clear_to_color8(struct BITMAP *bitmap, int color);
-
-#ifdef ALLEGRO_COLOR16
-
-void _linear_putpixel15(struct BITMAP *bmp, int x, int y, int color);
-void _linear_vline15(struct BITMAP *bmp, int x, int y1, int y2, int color);
-void _linear_hline15(struct BITMAP *bmp, int x1, int y, int x2, int color);
-void _linear_draw_trans_sprite15(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_lit_sprite15(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_draw_rle_sprite15(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_trans_rle_sprite15(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_lit_rle_sprite15(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color);
-
-int  _linear_getpixel16(struct BITMAP *bmp, int x, int y);
-void _linear_putpixel16(struct BITMAP *bmp, int x, int y, int color);
-void _linear_vline16(struct BITMAP *bmp, int x, int y1, int y2, int color);
-void _linear_hline16(struct BITMAP *bmp, int x1, int y, int x2, int color);
-void _linear_draw_sprite16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_256_sprite16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_v_flip16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_h_flip16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_vh_flip16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_trans_sprite16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_lit_sprite16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_draw_rle_sprite16(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_trans_rle_sprite16(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_lit_rle_sprite16(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color);
-void _linear_draw_character16(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_textout_fixed16(struct BITMAP *bmp, void *f, int h, unsigned char *str, int x, int y, int color);
-void _linear_blit16(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_blit_backward16(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_masked_blit16(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_clear_to_color16(struct BITMAP *bitmap, int color);
-
-#endif
-
-#ifdef ALLEGRO_COLOR24
-
-int  _linear_getpixel24(struct BITMAP *bmp, int x, int y);
-void _linear_putpixel24(struct BITMAP *bmp, int x, int y, int color);
-void _linear_vline24(struct BITMAP *bmp, int x, int y1, int y2, int color);
-void _linear_hline24(struct BITMAP *bmp, int x1, int y, int x2, int color);
-void _linear_draw_sprite24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_256_sprite24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_v_flip24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_h_flip24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_vh_flip24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_trans_sprite24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_lit_sprite24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_draw_rle_sprite24(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_trans_rle_sprite24(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_lit_rle_sprite24(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color);
-void _linear_draw_character24(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_textout_fixed24(struct BITMAP *bmp, void *f, int h, unsigned char *str, int x, int y, int color);
-void _linear_blit24(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_blit_backward24(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_masked_blit24(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_clear_to_color24(struct BITMAP *bitmap, int color);
-
-#endif
-
-#ifdef ALLEGRO_COLOR32
-
-int  _linear_getpixel32(struct BITMAP *bmp, int x, int y);
-void _linear_putpixel32(struct BITMAP *bmp, int x, int y, int color);
-void _linear_vline32(struct BITMAP *bmp, int x, int y1, int y2, int color);
-void _linear_hline32(struct BITMAP *bmp, int x1, int y, int x2, int color);
-void _linear_draw_sprite32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_256_sprite32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_v_flip32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_h_flip32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_sprite_vh_flip32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_trans_sprite32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _linear_draw_lit_sprite32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_draw_rle_sprite32(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_trans_rle_sprite32(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _linear_draw_lit_rle_sprite32(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color);
-void _linear_draw_character32(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _linear_textout_fixed32(struct BITMAP *bmp, void *f, int h, unsigned char *str, int x, int y, int color);
-void _linear_blit32(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_blit_backward32(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_masked_blit32(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _linear_clear_to_color32(struct BITMAP *bitmap, int color);
-
-#endif
-
-int  _x_getpixel(struct BITMAP *bmp, int x, int y);
-void _x_putpixel(struct BITMAP *bmp, int x, int y, int color);
-void _x_vline(struct BITMAP *bmp, int x, int y1, int y2, int color);
-void _x_hline(struct BITMAP *bmp, int x1, int y, int x2, int color);
-void _x_draw_sprite(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _x_draw_sprite_v_flip(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _x_draw_sprite_h_flip(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _x_draw_sprite_vh_flip(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _x_draw_trans_sprite(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y);
-void _x_draw_lit_sprite(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _x_draw_rle_sprite(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _x_draw_trans_rle_sprite(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y);
-void _x_draw_lit_rle_sprite(struct BITMAP *bmp, struct RLE_SPRITE *sprite, int x, int y, int color);
-void _x_draw_character(struct BITMAP *bmp, struct BITMAP *sprite, int x, int y, int color);
-void _x_textout_fixed(struct BITMAP *bmp, void *f, int h, unsigned char *str, int x, int y, int color);
-void _x_blit_from_memory(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _x_blit_to_memory(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _x_blit(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _x_blit_forward(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _x_blit_backward(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _x_masked_blit(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height);
-void _x_clear_to_color(struct BITMAP *bitmap, int color);
-
-
-/* asm helper for stretch_blit() */
-void _do_stretch(BITMAP *source, BITMAP *dest, void *drawer, int sx, fixed sy, fixed syd, int dx, int dy, int dh, int color_depth);
-
-
-/* number of fractional bits used by the polygon rasteriser */
-#define POLYGON_FIX_SHIFT     18
-
-
-/* bitfield specifying which polygon attributes need interpolating */
-#define INTERP_FLAT           1
-#define INTERP_1COL           2
-#define INTERP_3COL           4
-#define INTERP_FIX_UV         8
-#define INTERP_Z              16
-#define INTERP_FLOAT_UV       32
-#define OPT_FLOAT_UV_TO_FIX   64
-#define COLOR_TO_RGB          128
-
-
-/* information for polygon scanline fillers */
-typedef struct POLYGON_SEGMENT
-{
-   fixed u, v, du, dv;              /* fixed point u/v coordinates */
-   fixed c, dc;                     /* single color gouraud shade values */
-   fixed r, g, b, dr, dg, db;       /* RGB gouraud shade values */
-   float z, dz;                     /* polygon depth (1/z) */
-   float fu, fv, dfu, dfv;          /* floating point u/v coordinates */
-   unsigned char *texture;          /* the texture map */
-   int umask, vmask, vshift;        /* texture map size information */
-   int seg;                         /* destination bitmap selector */
-} POLYGON_SEGMENT;
-
-
-/* an active polygon edge */
-typedef struct POLYGON_EDGE 
-{
-   int top;                         /* top y position */
-   int bottom;                      /* bottom y position */
-   fixed x, dx;                     /* fixed point x position and gradient */
-   fixed w;                         /* width of line segment */
-   POLYGON_SEGMENT dat;             /* texture/gouraud information */
-   struct POLYGON_EDGE *prev;       /* doubly linked list */
-   struct POLYGON_EDGE *next;
-} POLYGON_EDGE;
-
-
-/* prototype for the scanline filler functions */
-typedef void (*SCANLINE_FILLER)(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-
-/* polygon helper functions */
-extern SCANLINE_FILLER _optim_alternative_drawer;
-POLYGON_EDGE *_add_edge(POLYGON_EDGE *list, POLYGON_EDGE *edge, int sort_by_x);
-POLYGON_EDGE *_remove_edge(POLYGON_EDGE *list, POLYGON_EDGE *edge);
-void _fill_3d_edge_structure(POLYGON_EDGE *edge, V3D *v1, V3D *v2, int flags, BITMAP *bmp);
-void _fill_3d_edge_structure_f(POLYGON_EDGE *edge, V3D_f *v1, V3D_f *v2, int flags, BITMAP *bmp);
-SCANLINE_FILLER _get_scanline_filler(int type, int *flags, POLYGON_SEGMENT *info, BITMAP *texture, BITMAP *bmp);
-void _clip_polygon_segment(POLYGON_SEGMENT *info, int gap, int flags);
-
-
-/* polygon scanline filler functions */
-void _poly_scanline_gcol8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_grgb8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit8(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb8x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit15(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb15x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit15x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit15x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit15x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit15x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_ptex_lit15d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit15d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit16(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb16x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit16x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit16x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit16x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit16x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_ptex_lit16d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit16d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit24(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb24x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit24x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit24x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit24x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit24x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_ptex_lit24d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit24d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit32(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_grgb32x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_lit32x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_lit32x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_atex_mask_lit32x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit32x(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-void _poly_scanline_ptex_lit32d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-void _poly_scanline_ptex_mask_lit32d(unsigned long addr, int w, POLYGON_SEGMENT *info);
-
-
-/* sound lib stuff */
-extern int _digi_volume;
-extern int _midi_volume;
-extern int _flip_pan; 
-extern int _sound_hq;
-
-extern int (*_midi_init)(void);
-extern void (*_midi_exit)(void);
-
-int _midi_allocate_voice(int min, int max);
-
-extern volatile long _midi_tick;
-
-int _digmid_find_patches(char *dir, char *file);
-
-#define VIRTUAL_VOICES  256
-
-
-typedef struct          /* a virtual (as seen by the user) soundcard voice */
-{
-   SAMPLE *sample;      /* which sample are we playing? (NULL = free) */
-   int num;             /* physical voice number (-1 = been killed off) */
-   int autokill;        /* set to free the voice when the sample finishes */
-   long time;           /* when we were started (for voice allocation) */
-   int priority;        /* how important are we? */
-} VOICE;
-
-extern VOICE _voice[VIRTUAL_VOICES];
-
-
-typedef struct          /* a physical (as used by hardware) soundcard voice */
-{
-   int num;             /* the virtual voice currently using me (-1 = free) */
-   int playmode;        /* are we looping? */
-   int vol;             /* current volume (fixed point .12) */
-   int dvol;            /* volume delta, for ramping */
-   int target_vol;      /* target volume, for ramping */
-   int pan;             /* current pan (fixed point .12) */
-   int dpan;            /* pan delta, for sweeps */
-   int target_pan;      /* target pan, for sweeps */
-   int freq;            /* current frequency (fixed point .12) */
-   int dfreq;           /* frequency delta, for sweeps */
-   int target_freq;     /* target frequency, for sweeps */
-} PHYS_VOICE;
-
-extern PHYS_VOICE _phys_voice[DIGI_VOICES];
-
-
-#define MIXER_DEF_SFX               8
-#define MIXER_MAX_SFX               64
-
-int _mixer_init(int bufsize, int freq, int stereo, int is16bit, int *voices);
-void _mixer_exit(void);
-void _mix_some_samples(unsigned long buf, unsigned short seg, int issigned);
-
-void _mixer_init_voice(int voice, SAMPLE *sample);
-void _mixer_release_voice(int voice);
-void _mixer_start_voice(int voice);
-void _mixer_stop_voice(int voice);
-void _mixer_loop_voice(int voice, int loopmode);
-int  _mixer_get_position(int voice);
-void _mixer_set_position(int voice, int position);
-int  _mixer_get_volume(int voice);
-void _mixer_set_volume(int voice, int volume);
-void _mixer_ramp_volume(int voice, int time, int endvol);
-void _mixer_stop_volume_ramp(int voice);
-int  _mixer_get_frequency(int voice);
-void _mixer_set_frequency(int voice, int frequency);
-void _mixer_sweep_frequency(int voice, int time, int endfreq);
-void _mixer_stop_frequency_sweep(int voice);
-int  _mixer_get_pan(int voice);
-void _mixer_set_pan(int voice, int pan);
-void _mixer_sweep_pan(int voice, int time, int endpan);
-void _mixer_stop_pan_sweep(int voice);
-void _mixer_set_echo(int voice, int strength, int delay);
-void _mixer_set_tremolo(int voice, int rate, int depth);
-void _mixer_set_vibrato(int voice, int rate, int depth);
-
-/* dummy functions for the NoSound drivers */
-int  _dummy_detect(int input);
-int  _dummy_init(int input, int voices);
-void _dummy_exit(int input);
-int  _dummy_mixer_volume(int volume);
-void _dummy_init_voice(int voice, SAMPLE *sample);
-void _dummy_noop1(int p);
-void _dummy_noop2(int p1, int p2);
-void _dummy_noop3(int p1, int p2, int p3);
-int  _dummy_get_position(int voice);
-int  _dummy_get(int voice);
-void _dummy_raw_midi(unsigned char data);
-int  _dummy_load_patches(char *patches, char *drums);
-void _dummy_adjust_patches(char *patches, char *drums);
-void _dummy_key_on(int inst, int note, int bend, int vol, int pan);
-
-
-/* from djgpp's libc, needed to find which directory we were run from */
-extern int __crt0_argc;
-extern char **__crt0_argv;
-
-
-#endif          /* ifndef INTERNAL_H */
diff --git a/src/djgppdos/rdb-s.h b/src/djgppdos/rdb-s.h
deleted file mode 100644
index 2d460c9357022f8f23c7764cf76803f1091ab525..0000000000000000000000000000000000000000
--- a/src/djgppdos/rdb-s.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2005-2020 by Sonic Team Junior.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief Set Com port and speed for GDBStubs for DJGGP
-///
-///	copy and rename as rdb.h and set the defines below as needed
-
-#define DEBUG_COM_PORT 2
-#define  DEBUG_COM_PORT_SPEED 9600
diff --git a/src/djgppdos/vid_vesa.c b/src/djgppdos/vid_vesa.c
deleted file mode 100644
index 61ed18e4b6858eb8a9374b7edfe957f06975cce0..0000000000000000000000000000000000000000
--- a/src/djgppdos/vid_vesa.c
+++ /dev/null
@@ -1,903 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief extended vesa VESA2.0 video modes i/o
-
-#include <stdlib.h>
-
-#include "../i_system.h"        //I_Error()
-#include "vid_vesa.h"
-#include "../doomdef.h"         //MAXVIDWIDTH, MAXVIDHEIGHT
-#include "../screen.h"
-
-#include <dpmi.h>
-#include <go32.h>
-#include <sys/farptr.h>
-#include <sys/movedata.h>
-#include <sys/segments.h>
-#include <sys/nearptr.h>
-
-#include "../console.h"
-#include "../command.h"            //added:21-03-98: vid_xxx commands
-#include "../i_video.h"
-
-
-// PROTOS
-static vmode_t *VID_GetModePtr (int modenum);
-static int  VID_VesaGetModeInfo (int modenum);
-static void VID_VesaGetExtraModes (void);
-static INT32  VID_VesaInitMode (viddef_t *lvid, vmode_t *pcurrentmode);
-
-static void VID_Command_NumModes_f (void);
-static void VID_Command_ModeInfo_f (void);
-static void VID_Command_ModeList_f (void);
-static void VID_Command_Mode_f (void);
-
-consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_stretch = {"stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-#define VBEVERSION      2       // we need vesa2 or higher
-
-// -----------------------------------------------------
-#define MASK_LINEAR(addr)     (addr & 0x000FFFFF)
-#define RM_TO_LINEAR(addr)    (((addr & 0xFFFF0000) >> 12) + (addr & 0xFFFF))
-#define RM_OFFSET(addr)       (addr & 0xF)
-#define RM_SEGMENT(addr)      ((addr >> 4) & 0xFFFF)
-// -----------------------------------------------------
-
-static int totalvidmem;
-
-static vmode_t      vesa_modes[MAX_VESA_MODES] = {{NULL, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, 0}};
-static vesa_extra_t vesa_extra[MAX_VESA_MODES];
-
-//this is the only supported non-vesa mode : standard 320x200x256c.
-#define NUMVGAVIDMODES  1
-static INT32 VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode);
-static char vgamode1[] ="320x200";
-static vmode_t      vgavidmodes[NUMVGAVIDMODES] = {
-  {
-	NULL,
-	vgamode1,
-	320, 200,  //(200.0/320.0)*(320.0/240.0),
-	320, 1,    // rowbytes, bytes per pixel
-	0, 1,
-	NULL,
-	VGA_InitMode, 0
-  }
-};
-
-static char         names[MAX_VESA_MODES][10];
-
-//----------------------------i_video.c------------------------------------
-// these ones should go to i_video.c, but I prefer keep them away from the
-// doom sources until the vesa stuff is ok.
-static int     numvidmodes;   //total number of video modes, vga, vesa1, vesa2.
-static vmode_t *pvidmodes;    //start of videomodes list.
-static vmode_t *pcurrentmode; // the current active videomode.
-//----------------------------i_video.c------------------------------------
-
-
-
-// table des modes videos.
-// seul le mode 320x200x256c standard VGA est support� sans le VESA.
-// ce mode est le mode num�ro 0 dans la liste.
-typedef struct
-{
-	int modenum;            // vesa vbe2.0 modenum
-	int mode_attributes;
-	int winasegment;
-	int winbsegment;
-	int bytes_per_scanline; // bytes per logical scanline (+16)
-	int win;                // window number (A=0, B=1)
-	int win_size;           // window size (+6)
-	int granularity;        // how finely i can set the window in vid mem (+4)
-	int width, height;      // displayed width and height (+18, +20)
-	int bits_per_pixel;     // er, better be 8, 15, 16, 24, or 32 (+25)
-	int bytes_per_pixel;    // er, better be 1, 2, or 4
-	int memory_model;       // and better be 4 or 6, packed or direct color (+27)
-	int num_pages;          // number of complete frame buffer pages (+29)
-	int red_width;          // the # of bits in the red component (+31)
-	int red_pos;            // the bit position of the red component (+32)
-	int green_width;        // etc.. (+33)
-	int green_pos;          // (+34)
-	int blue_width;         // (+35)
-	int blue_pos;           // (+36)
-	int pptr;
-	int pagesize;
-	int numpages;
-} modeinfo_t;
-
-static vbeinfoblock_t vesainfo;
-static vesamodeinfo_t vesamodeinfo;
-
-// ------------------------------------------------------------------------
-// DOS stuff
-// ------------------------------------------------------------------------
-static unsigned long conventional_memory = (unsigned long)-1;
-
-FUNCINLINE static ATTRINLINE void map_in_conventional_memory(void)
-{
-	if (conventional_memory == (unsigned long)-1)
-	{
-		if (__djgpp_nearptr_enable())
-		{
-			conventional_memory = __djgpp_conventional_base;
-		}
-	}
-}
-
-// Converts a flat 32 bit ptr to a realmode 0x12345 type ptr (seg<<4 + offs)
-#if 0
-unsigned int ptr2real(void *ptr)
-{
-	map_in_conventional_memory();
-	return (int)ptr - conventional_memory;
-}
-#endif
-
-// Converts 0x12345 (seg<<4+offs) realmode ptr to a flat 32bit ptr
-FUNCINLINE static ATTRINLINE void *real2ptr(unsigned int real)
-{
-	map_in_conventional_memory();
-	return (void *) (real + conventional_memory);
-}
-
-// ------------------------------------------------------------------------
-
-
-/* ======================================================================== */
-// Add the standard VGA video modes (only one now) to the video modes list.
-/* ======================================================================== */
-static inline void VGA_Init(void)
-{
-	vgavidmodes[NUMVGAVIDMODES-1].pnext = pvidmodes;
-	pvidmodes = &vgavidmodes[0];
-	numvidmodes += NUMVGAVIDMODES;
-}
-
-
-//added:30-01-98: return number of video modes in pvidmodes list
-INT32 VID_NumModes(void)
-{
-	return numvidmodes;
-}
-
-//added:21-03-98: return info on video mode
-FUNCINLINE static ATTRINLINE const char *VID_ModeInfo (int modenum, char **ppheader)
-{
-	static const char *badmodestr = "Bad video mode number\n";
-	vmode_t     *pv;
-
-	pv = VID_GetModePtr (modenum);
-
-	if (!pv)
-	{
-		if (ppheader)
-			*ppheader = NULL;
-		return badmodestr;
-	}
-	else
-	{
-		//if (ppheader)
-		//    *ppheader = pv->header;
-		return pv->name;
-	}
-}
-
-
-
-//added:03-02-98: return a video mode number from the dimensions
-INT32 VID_GetModeForSize( INT32 w, INT32 h)
-{
-	vmode_t *pv;
-	int modenum;
-
-	pv = pvidmodes;
-	for (modenum=0; pv!=NULL; pv=pv->pnext,modenum++ )
-	{
-		if ( pv->width==(unsigned)w && pv->height==(unsigned)h )
-			return modenum;
-	}
-
-	return 0;
-}
-
-
-/* ======================================================================== */
-//
-/* ======================================================================== */
-void    VID_Init (void)
-{
-	COM_AddCommand ("vid_nummodes", VID_Command_NumModes_f);
-	COM_AddCommand ("vid_modeinfo", VID_Command_ModeInfo_f);
-	COM_AddCommand ("vid_modelist", VID_Command_ModeList_f);
-	COM_AddCommand ("vid_mode", VID_Command_Mode_f);
-	CV_RegisterVar (&cv_vidwait);
-	CV_RegisterVar (&cv_stretch);
-
-	//setup the videmodes list,
-	// note that mode 0 must always be VGA mode 0x13
-	pvidmodes = NULL;
-	pcurrentmode = NULL;
-	numvidmodes = 0;
-	// setup the vesa_modes list
-	VID_VesaGetExtraModes ();
-
-	// the game boots in 320x200 standard VGA, but
-	// we need a highcolor mode to run the game in highcolor
-	if (highcolor && numvidmodes==0)
-		I_Error ("No 15bit highcolor VESA2 video mode found, cannot run in highcolor.\n");
-
-	// add the vga modes at the start of the modes list
-	VGA_Init();
-
-
-#ifdef DEBUG
-	CONS_Printf("VID_SetMode(%d)\n",vid.modenum);
-#endif
-	VID_SetMode (0); //vid.modenum);
-
-
-#ifdef DEBUG
-	CONS_Printf("after VID_SetMode\n");
-	CONS_Printf("vid.width    %d\n",vid.width);
-	CONS_Printf("vid.height   %d\n",vid.height);
-	CONS_Printf("vid.buffer   %x\n",vid.buffer);
-	CONS_Printf("vid.rowbytes %d\n",vid.rowbytes);
-	CONS_Printf("vid.numpages %d\n",vid.numpages);
-	CONS_Printf("vid.recalc   %d\n",vid.recalc);
-	CONS_Printf("vid.direct   %x\n",vid.direct);
-#endif
-
-}
-
-
-// ========================================================================
-// Returns a vmode_t from the video modes list, given a video mode number.
-// ========================================================================
-vmode_t *VID_GetModePtr (int modenum)
-{
-	vmode_t *pv;
-
-	pv = pvidmodes;
-	if (!pv)
-		I_Error ("VID_error 1\n");
-
-	while (modenum--)
-	{
-		pv = pv->pnext;
-		if (!pv)
-			I_Error ("VID_error 2\n");
-	}
-
-	return pv;
-}
-
-
-//added:30-01-98:return the name of a video mode
-const char *VID_GetModeName (INT32 modenum)
-{
-	return (VID_GetModePtr(modenum))->name;
-}
-
-
-// ========================================================================
-// Sets a video mode
-// ========================================================================
-INT32 VID_SetMode (INT32 modenum)  //, UINT8 *palette)
-{
-	int     vstat;
-	vmode_t *pnewmode, *poldmode;
-
-	if ((modenum >= numvidmodes) || (modenum < 0))
-	{
-		if (pcurrentmode == NULL)
-		{
-			modenum = 0;    // mode hasn't been set yet, so initialize to base
-							//  mode since they gave us an invalid initial mode
-		}
-		else
-		{
-			//nomodecheck = true;
-			I_Error ("Unknown video mode: %d\n", modenum);
-			//nomodecheck = false;
-			return 0;
-		}
-	}
-
-	pnewmode = VID_GetModePtr (modenum);
-
-	if (pnewmode == pcurrentmode)
-		return 1;   // already in the desired mode
-
-	// initialize the new mode
-	poldmode = pcurrentmode;
-	pcurrentmode = pnewmode;
-
-	// initialize vidbuffer size for setmode
-	vid.width  = pcurrentmode->width;
-	vid.height = pcurrentmode->height;
-	//vid.aspect = pcurrentmode->aspect;
-	vid.rowbytes = pcurrentmode->rowbytes;
-	vid.bpp      = pcurrentmode->bytesperpixel;
-
-	//debug
-	//if (vid.rowbytes != vid.width)
-	//    I_Error("vidrowbytes (%d) <> vidwidth(%d)\n",vid.rowbytes,vid.width);
-
-	vstat = (*pcurrentmode->setmode) (&vid, pcurrentmode);
-
-	if (vstat < 1)
-	{
-		if (vstat == 0)
-		{
-			// harware could not setup mode
-			//if (!VID_SetMode (vid.modenum))
-			//    I_Error ("VID_SetMode: couldn't set video mode (hard failure)");
-			I_Error("Couldn't set video mode %d\n", modenum);
-		}
-		else
-		if (vstat == -1)
-		{
-			CONS_Printf ("Not enough mem for VID_SetMode...\n");
-
-			// not enough memory; just put things back the way they were
-			pcurrentmode = poldmode;
-			vid.width = pcurrentmode->width;
-			vid.height = pcurrentmode->height;
-			vid.rowbytes = pcurrentmode->rowbytes;
-			vid.bpp      = pcurrentmode->bytesperpixel;
-			return 0;
-		}
-	}
-
-	vid.modenum = modenum;
-
-	//printf ("%s\n", VID_ModeInfo (vid.modenum, NULL));
-
-	//added:20-01-98: recalc all tables and realloc buffers based on
-	//                vid values.
-	vid.recalc = 1;
-
-	if (!cv_stretch.value && (float)vid.width/vid.height != ((float)BASEVIDWIDTH/BASEVIDHEIGHT))
-		vid.height = (int)(vid.width * ((float)BASEVIDHEIGHT/BASEVIDWIDTH));// Adjust the height to match
-
-	return 1;
-}
-
-void VID_CheckRenderer(void) {}
-void VID_CheckGLLoaded(rendermode_t oldrender) {}
-
-
-
-// converts a segm:offs 32bit pair to a 32bit flat ptr
-#if 0
-void *VID_ExtraFarToLinear (void *ptr)
-{
-	int     temp;
-
-	temp = (int)ptr;
-	return real2ptr (((temp & 0xFFFF0000) >> 12) + (temp & 0xFFFF));
-}
-#endif
-
-
-
-// ========================================================================
-// Helper function for VID_VesaGetExtraModes
-// In:  vesa mode number, from the vesa videomodenumbers list
-// Out: false, if no info for given modenum
-// ========================================================================
-int VID_VesaGetModeInfo (int modenum)
-{
-	int     bytes_per_pixel;
-	unsigned int          i;
-	__dpmi_regs regs;
-
-	for (i=0; i<sizeof (vesamodeinfo_t); i++)
-		_farpokeb(_dos_ds, MASK_LINEAR(__tb)+i, 0);
-
-	regs.x.ax = 0x4f01;
-	regs.x.di = RM_OFFSET(__tb);
-	regs.x.es = RM_SEGMENT(__tb);
-	regs.x.cx = modenum;
-	__dpmi_int(0x10, &regs);
-	if (regs.h.ah)
-		return false;
-	else
-	{
-		dosmemget (MASK_LINEAR(__tb), sizeof (vesamodeinfo_t), &vesamodeinfo);
-
-		bytes_per_pixel = (vesamodeinfo.BitsPerPixel+1)/8;
-
-		// we add either highcolor or lowcolor video modes, not the two
-		if (highcolor && (vesamodeinfo.BitsPerPixel != 15))
-			return false;
-		if (!highcolor && (vesamodeinfo.BitsPerPixel != 8))
-			return false;
-
-		if ((bytes_per_pixel > 2) ||
-			(vesamodeinfo.XResolution > MAXVIDWIDTH) ||
-			(vesamodeinfo.YResolution > MAXVIDHEIGHT))
-		{
-			return false;
-		}
-
-		// we only want color graphics modes that are supported by the hardware
-		if ((vesamodeinfo.ModeAttributes &
-			(MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE) ) !=
-			 (MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE))
-		{
-			return false;
-		}
-
-		// we only work with linear frame buffers, except for 320x200,
-		// which is linear when banked at 0xA000
-		if (!(vesamodeinfo.ModeAttributes & LINEAR_FRAME_BUFFER))
-		{
-			if ((vesamodeinfo.XResolution != 320) ||
-				(vesamodeinfo.YResolution != 200))
-			{
-				return false;
-			}
-		}
-
-		// pagesize
-		if ((vesamodeinfo.BytesPerScanLine * vesamodeinfo.YResolution)
-		    > totalvidmem)
-		{
-			return false;
-		}
-
-		vesamodeinfo.NumberOfImagePages = 1;
-
-
-#ifdef DEBUG
-		CONS_Printf("VID: (VESA) info for mode 0x%x\n", modeinfo.modenum);
-		CONS_Printf("  mode attrib = 0x%0x\n", modeinfo.mode_attributes);
-		CONS_Printf("  win a attrib = 0x%0x\n", *(UINT8 *)(infobuf+2));
-		CONS_Printf("  win b attrib = 0x%0x\n", *(UINT8 *)(infobuf+3));
-		CONS_Printf("  win a seg 0x%0x\n", (int) modeinfo.winasegment);
-		CONS_Printf("  win b seg 0x%0x\n", (int) modeinfo.winbsegment);
-		CONS_Printf("  bytes per scanline = %d\n",
-				modeinfo.bytes_per_scanline);
-		CONS_Printf("  width = %d, height = %d\n", modeinfo.width,
-				modeinfo.height);
-		CONS_Printf("  win = %c\n", 'A' + modeinfo.win);
-		CONS_Printf("  win granularity = %d\n", modeinfo.granularity);
-		CONS_Printf("  win size = %d\n", modeinfo.win_size);
-		CONS_Printf("  bits per pixel = %d\n", modeinfo.bits_per_pixel);
-		CONS_Printf("  bytes per pixel = %d\n", modeinfo.bytes_per_pixel);
-		CONS_Printf("  memory model = 0x%x\n", modeinfo.memory_model);
-		CONS_Printf("  num pages = %d\n", modeinfo.num_pages);
-		CONS_Printf("  red width = %d\n", modeinfo.red_width);
-		CONS_Printf("  red pos = %d\n", modeinfo.red_pos);
-		CONS_Printf("  green width = %d\n", modeinfo.green_width);
-		CONS_Printf("  green pos = %d\n", modeinfo.green_pos);
-		CONS_Printf("  blue width = %d\n", modeinfo.blue_width);
-		CONS_Printf("  blue pos = %d\n", modeinfo.blue_pos);
-		CONS_Printf("  phys mem = %x\n", modeinfo.pptr);
-#endif
-	}
-
-	return true;
-}
-
-
-// ========================================================================
-// Get extended VESA modes information, keep the ones that we support,
-// so they'll be available in the game Video menu.
-// ========================================================================
-#define MAXVESADESC 100
-static char vesadesc[MAXVESADESC] = "";
-
-void VID_VesaGetExtraModes (void)
-{
-	unsigned int    i;
-	unsigned long   addr;
-	int             nummodes;
-	__dpmi_meminfo  phys_mem_info;
-	unsigned long   mode_ptr;
-	__dpmi_regs     regs;
-
-	// make a copy of the video modes list! else trash in __tb
-	UINT16          vmode[MAX_VESA_MODES+1];
-	int             numvmodes;
-	UINT16          vesamode;
-
-	// new ugly stuff...
-	for (i=0; i<sizeof (vbeinfoblock_t); i++)
-		_farpokeb(_dos_ds, MASK_LINEAR(__tb)+i, 0);
-
-	dosmemput("VBE2", 4, MASK_LINEAR(__tb));
-
-	// see if VESA support is available
-	regs.x.ax = 0x4f00;
-	regs.x.di = RM_OFFSET(__tb);
-	regs.x.es = RM_SEGMENT(__tb);
-	__dpmi_int(0x10, &regs);
-	if (regs.h.ah)
-		goto no_vesa;
-
-	dosmemget(MASK_LINEAR(__tb), sizeof (vbeinfoblock_t), &vesainfo);
-
-	if (strncmp((void *)vesainfo.VESASignature, "VESA", 4) != 0)
-	{
-no_vesa:
-		CONS_Printf ("No VESA driver\n");
-		return;
-	}
-
-	if (vesainfo.VESAVersion < (VBEVERSION<<8))
-	{
-		CONS_Printf ("VESA VBE %d.0 not available\n", VBEVERSION);
-		return;
-	}
-
-	//
-	// vesa version number
-	//
-	CONS_Printf ("%4.4s %d.%d (", vesainfo.VESASignature,
-	             vesainfo.VESAVersion>>8,
-	             vesainfo.VESAVersion&0xFF);
-
-	//
-	// vesa description string
-	//
-	i = 0;
-	addr = RM_TO_LINEAR(vesainfo.OemStringPtr);
-	_farsetsel(_dos_ds);
-	while (_farnspeekb(addr) != 0)
-	{
-		vesadesc[i++] = _farnspeekb(addr++);
-		if (i == MAXVESADESC-1)
-			break;
-	}
-	vesadesc[i]=0;
-	CONS_Printf ("%s)\n",vesadesc);
-
-	totalvidmem = vesainfo.TotalMemory << 16;
-
-   //
-   // find 8 bit modes
-   //
-	numvmodes = 0;
-	mode_ptr = RM_TO_LINEAR(vesainfo.VideoModePtr);
-	while ((vmode[numvmodes] = _farpeekw(_dos_ds, mode_ptr)) != 0xFFFF)
-	{
-		numvmodes++;
-		if ( numvmodes == MAX_VESA_MODES )
-			break;
-		mode_ptr += 2;
-	}
-	vmode[numvmodes] = 0xffff;
-
-	nummodes = 0;       // number of video modes accepted for the game
-
-	numvmodes=0;  // go again through vmodes table
-	while ( ((vesamode=vmode[numvmodes++]) != 0xFFFF) && (nummodes < MAX_VESA_MODES) )
-	{
-		//fill the modeinfo struct.
-		if (VID_VesaGetModeInfo (vesamode))
-		{
-			vesa_modes[nummodes].pnext = &vesa_modes[nummodes+1];
-			if (vesamodeinfo.XResolution > 999)
-			{
-				if (vesamodeinfo.YResolution > 999)
-				{
-					sprintf (&names[nummodes][0], "%4dx%4d", vesamodeinfo.XResolution,
-					         vesamodeinfo.YResolution);
-					names[nummodes][9] = 0;
-				}
-				else
-				{
-					sprintf (&names[nummodes][0], "%4dx%3d", vesamodeinfo.XResolution,
-					         vesamodeinfo.YResolution);
-					names[nummodes][8] = 0;
-				}
-			}
-			else
-			{
-				if (vesamodeinfo.YResolution > 999)
-				{
-					sprintf (&names[nummodes][0], "%3dx%4d", vesamodeinfo.XResolution,
-					         vesamodeinfo.YResolution);
-					names[nummodes][8] = 0;
-				}
-				else
-				{
-					sprintf (&names[nummodes][0], "%3dx%3d", vesamodeinfo.XResolution,
-					         vesamodeinfo.YResolution);
-					names[nummodes][7] = 0;
-				}
-			}
-
-			vesa_modes[nummodes].name = &names[nummodes][0];
-			vesa_modes[nummodes].width = vesamodeinfo.XResolution;
-			vesa_modes[nummodes].height = vesamodeinfo.YResolution;
-
-			//added:20-01-98:aspect ratio to be implemented...
-			vesa_modes[nummodes].rowbytes = vesamodeinfo.BytesPerScanLine;
-			vesa_modes[nummodes].windowed = 0;
-			vesa_modes[nummodes].pextradata = &vesa_extra[nummodes];
-			vesa_modes[nummodes].setmode = VID_VesaInitMode;
-
-			if (vesamodeinfo.ModeAttributes & LINEAR_FRAME_BUFFER)
-			{
-			// add linear bit to mode for linear modes
-				vesa_extra[nummodes].vesamode = vesamode | LINEAR_MODE;
-				vesa_modes[nummodes].numpages = 1; //vesamodeinfo.NumberOfImagePages;
-
-				phys_mem_info.address = (int)vesamodeinfo.PhysBasePtr;
-				phys_mem_info.size = 0x400000;
-
-				// returns -1 on error
-				if (__dpmi_physical_address_mapping(&phys_mem_info))
-				{
-					//skip this mode, it doesnt work
-					continue;
-				}
-
-				// if physical mapping was ok... convert the selector:offset
-				vesa_extra[nummodes].plinearmem =
-				 real2ptr (phys_mem_info.address);
-
-				// lock the region
-				__dpmi_lock_linear_region (&phys_mem_info);
-			}
-			else
-			{
-			// banked at 0xA0000
-				vesa_extra[nummodes].vesamode = vesamode;
-				//vesa_extra[nummodes].pages[0] = 0;
-				vesa_extra[nummodes].plinearmem =
-				 real2ptr (vesamodeinfo.WinASegment<<4);
-
-				vesa_modes[nummodes].numpages = 1; //modeinfo.numpages;
-			}
-
-			vesa_modes[nummodes].bytesperpixel = (vesamodeinfo.BitsPerPixel+1)/8;
-
-			nummodes++;
-		}
-	}
-
-// add the VESA modes at the start of the mode list (if there are any)
-	if (nummodes)
-	{
-		vesa_modes[nummodes-1].pnext = NULL; //pvidmodes;
-		pvidmodes = &vesa_modes[0];
-		numvidmodes += nummodes;
-	}
-
-}
-
-
-// ========================================================================
-// Free the video buffer of the last video mode,
-// allocate a new buffer for the video mode to set.
-// ========================================================================
-static boolean VID_FreeAndAllocVidbuffer (viddef_t *lvid)
-{
-	int  vidbuffersize;
-
-	vidbuffersize = (lvid->width * lvid->height * lvid->bpp * NUMSCREENS);  //status bar
-
-	// free allocated buffer for previous video mode
-	if (lvid->buffer!=NULL)
-	{
-		free(lvid->buffer);
-	}
-
-	// allocate the new screen buffer
-	if ( (lvid->buffer = (UINT8 *) malloc(vidbuffersize))==NULL )
-		return false;
-
-	// initially clear the video buffer
-	memset (lvid->buffer, 0x00, vidbuffersize);
-
-#ifdef DEBUG
-	CONS_Printf("VID_FreeAndAllocVidbuffer done, vidbuffersize: %x\n",vidbuffersize);
-#endif
-	return true;
-}
-
-
-// ========================================================================
-// Set video mode routine for STANDARD VGA MODES (NO HIGHCOLOR)
-// Out: 1 ok,
-//      0 hardware could not set mode,
-//     -1 no mem
-// ========================================================================
-static INT32 VGA_InitMode (viddef_t *lvid, vmode_t *currentmodep)
-{
-	__dpmi_regs   regs;
-
-	if (!VID_FreeAndAllocVidbuffer (lvid))
-		return -1;                  //no mem
-
-	//added:26-01-98: should clear video mem here
-
-	//set mode 0x13
-	regs.h.ah = 0;
-	regs.h.al = 0x13;
-	__dpmi_int(0x10, &regs);
-
-	// here it is the standard VGA 64k window, not an LFB
-	// (you could have 320x200x256c with LFB in the vesa modes)
-	lvid->direct = (UINT8 *) real2ptr (0xa0000);
-	lvid->u.numpages = 1;
-	lvid->bpp = currentmodep->bytesperpixel;
-
-	return 1;
-}
-
-
-// ========================================================================
-// Set video mode routine for VESA video modes, see VID_SetMode()
-// Out: 1 ok,
-//      0 hardware could not set mode,
-//     -1 no mem
-// ========================================================================
-INT32 VID_VesaInitMode (viddef_t *lvid, vmode_t *currentmodep)
-{
-	vesa_extra_t    *pextra;
-	__dpmi_regs     regs;
-
-	pextra = currentmodep->pextradata;
-
-#ifdef DEBUG
-	CONS_Printf("VID_VesaInitMode...\n");
-	CONS_Printf(" currentmodep->name %s\n",currentmodep->name);
-	CONS_Printf("               width %d\n",currentmodep->width);
-	CONS_Printf("               height %d\n",currentmodep->height);
-	CONS_Printf("               rowbytes %d\n",currentmodep->rowbytes);
-	CONS_Printf("               windowed %d\n",currentmodep->windowed);
-	CONS_Printf("               numpages %d\n",currentmodep->numpages);
-	CONS_Printf(" currentmodep->pextradata :\n");
-	CONS_Printf("                ->vesamode %x\n",pextra->vesamode);
-	CONS_Printf("                ->plinearmem %x\n\n",pextra->plinearmem);
-#endif
-
-	//added:20-01-98:no page flipping now... TO DO!!!
-	lvid->u.numpages = 1;
-
-	// clean up any old vid buffer lying around, alloc new if needed
-	if (!VID_FreeAndAllocVidbuffer (lvid))
-		return -1;                  //no mem
-
-
-	//added:20-01-98: should clear video mem here
-
-
-	// set the mode
-	regs.x.ax = 0x4f02;
-	regs.x.bx = pextra->vesamode;
-	__dpmi_int (0x10, &regs);
-
-	if (regs.x.ax != 0x4f)
-		return 0;               // could not set mode
-
-//added:20-01-98: should setup wait_vsync flag, currentpage here...
-//                plus check for display_enable bit
-
-//added:20-01-98: here we should set the page if page flipping...
-
-	// points to LFB, or the start of VGA mem.
-	lvid->direct = pextra->plinearmem;
-	lvid->bpp    = currentmodep->bytesperpixel;
-
-	return 1;
-}
-
-// ========================================================================
-//                     VIDEO MODE CONSOLE COMMANDS
-// ========================================================================
-
-
-//  vid_nummodes
-//
-//added:21-03-98:
-void VID_Command_NumModes_f (void)
-{
-	int     nummodes;
-
-	nummodes = VID_NumModes ();
-	CONS_Printf ("%d video mode(s) available(s)\n", nummodes);
-}
-
-
-//  vid_modeinfo <modenum>
-//
-void VID_Command_ModeInfo_f (void)
-{
-	vmode_t     *pv;
-	int         modenum;
-
-	if (COM_Argc()!=2)
-		modenum = vid.modenum;          // describe the current mode
-	else
-		modenum = atoi (COM_Argv(1));   //    .. the given mode number
-
-	if (modenum >= VID_NumModes())
-	{
-		CONS_Printf ("No such video mode\n");
-		return;
-	}
-
-	pv = VID_GetModePtr (modenum);
-
-	CONS_Printf ("%s\n", VID_ModeInfo (modenum, NULL));
-	CONS_Printf ("width : %d\n"
-	             "height: %d\n"
-	             "bytes per scanline: %d\n"
-	             "bytes per pixel: %d\n"
-	             "numpages: %d\n",
-	             pv->width,
-	             pv->height,
-	             pv->rowbytes,
-	             pv->bytesperpixel,
-	             pv->numpages );
-}
-
-
-//  vid_modelist
-//
-void VID_Command_ModeList_f (void)
-{
-	int         i, nummodes;
-	const char  *pinfo;
-	char        *pheader;
-	vmode_t     *pv;
-	boolean     na;
-
-	na = false;
-
-	nummodes = VID_NumModes ();
-	for (i=0 ; i<nummodes ; i++)
-	{
-		pv = VID_GetModePtr (i);
-		pinfo = VID_ModeInfo (i, &pheader);
-
-		if (i==0 || pv->bytesperpixel==1)
-			CONS_Printf ("%d: %s\n", i, pinfo);
-		else
-			CONS_Printf ("%d: %s (hicolor)\n", i, pinfo);
-	}
-
-}
-
-
-//  vid_mode <modenum>
-//
-void VID_Command_Mode_f (void)
-{
-	int         modenum;
-
-	if (COM_Argc()!=2)
-	{
-		CONS_Printf ("vid_mode <modenum> : set video mode\n");
-		return;
-	}
-
-	modenum = atoi(COM_Argv(1));
-
-	if (modenum >= VID_NumModes())
-		CONS_Printf ("No such video mode\n");
-	else
-		// request vid mode change
-		setmodeneeded = modenum+1;
-}
diff --git a/src/djgppdos/vid_vesa.h b/src/djgppdos/vid_vesa.h
deleted file mode 100644
index b704336e8f121e0ffd345710fcca08fdc07becac..0000000000000000000000000000000000000000
--- a/src/djgppdos/vid_vesa.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief VESA extra modes.
-
-#include "../doomdef.h"
-#include "../screen.h"
-
-
-
-#define MODE_SUPPORTED_IN_HW    0x0001
-#define COLOR_MODE              0x0008
-#define GRAPHICS_MODE           0x0010
-#define VGA_INCOMPATIBLE        0x0020
-#define LINEAR_FRAME_BUFFER     0x0080
-#define LINEAR_MODE             0x4000
-
-#define MAX_VESA_MODES          30  // we'll just take the first 30 if there
-
-
-// VESA information block structure
-typedef struct vbeinfoblock_s
-{
-	UINT8          VESASignature[4];
-	UINT16         VESAVersion;
-	unsigned long  OemStringPtr;
-	UINT8          Capabilities[4];
-	unsigned long  VideoModePtr;
-	UINT16         TotalMemory;
-	UINT8          OemSoftwareRev[2];
-	UINT8          OemVendorNamePtr[4];
-	UINT8          OemProductNamePtr[4];
-	UINT8          OemProductRevPtr[4];
-	UINT8          Reserved[222];
-	UINT8          OemData[256];
-}  ATTRPACK vbeinfoblock_t;
-
-
-// VESA information for a specific mode
-typedef struct vesamodeinfo_s
-{
-	UINT16         ModeAttributes;
-	UINT8          WinAAttributes;
-	UINT8          WinBAttributes;
-	UINT16         WinGranularity;
-	UINT16         WinSize;
-	UINT16         WinASegment;
-	UINT16         WinBSegment;
-	unsigned long  WinFuncPtr;
-	UINT16         BytesPerScanLine;
-	UINT16         XResolution;
-	UINT16         YResolution;
-	UINT8          XCharSize;
-	UINT8          YCharSize;
-	UINT8          NumberOfPlanes;
-	UINT8          BitsPerPixel;
-	UINT8          NumberOfBanks;
-	UINT8          MemoryModel;
-	UINT8          BankSize;
-	UINT8          NumberOfImagePages;
-	UINT8          Reserved_page;
-	UINT8          RedMaskSize;
-	UINT8          RedMaskPos;
-	UINT8          GreenMaskSize;
-	UINT8          GreenMaskPos;
-	UINT8          BlueMaskSize;
-	UINT8          BlueMaskPos;
-	UINT8          ReservedMaskSize;
-	UINT8          ReservedMaskPos;
-	UINT8          DirectColorModeInfo;
-
-	/* VBE 2.0 extensions */
-	unsigned long  PhysBasePtr;
-	unsigned long  OffScreenMemOffset;
-	UINT16         OffScreenMemSize;
-
-	/* VBE 3.0 extensions */
-	UINT16         LinBytesPerScanLine;
-	UINT8          BnkNumberOfPages;
-	UINT8          LinNumberOfPages;
-	UINT8          LinRedMaskSize;
-	UINT8          LinRedFieldPos;
-	UINT8          LinGreenMaskSize;
-	UINT8          LinGreenFieldPos;
-	UINT8          LinBlueMaskSize;
-	UINT8          LinBlueFieldPos;
-	UINT8          LinRsvdMaskSize;
-	UINT8          LinRsvdFieldPos;
-	unsigned long  MaxPixelClock;
-
-	UINT8          Reserved[190];
-} ATTRPACK vesamodeinfo_t;
-
-
-// setup standard VGA + VESA modes list, activate the default video mode.
-void VID_Init (void);
diff --git a/src/doomdef.h b/src/doomdef.h
index d45bd3fad52c256961d2b693e961718d0e911dcb..d0b7ea0c2391334c703051d02e0dae693dfdfe19 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -29,7 +29,6 @@
 // Use Mixer interface?
 #ifdef HAVE_MIXER
     #define SOUND SOUND_MIXER
-    #define NOHS // No HW3SOUND
     #ifdef HW3SOUND
     #undef HW3SOUND
     #endif
@@ -45,7 +44,6 @@
 // Use FMOD?
 #ifdef HAVE_FMOD
     #define SOUND SOUND_FMOD
-    #define NOHS // No HW3SOUND
     #ifdef HW3SOUND
     #undef HW3SOUND
     #endif
@@ -62,10 +60,6 @@
 #if !defined (HWRENDER) && !defined (NOHW)
 #define HWRENDER
 #endif
-// judgecutor: 3D sound support
-#if !defined(HW3SOUND) && !defined (NOHS)
-#define HW3SOUND
-#endif
 #endif
 
 #ifdef _WIN32
@@ -110,10 +104,6 @@
 #include <io.h>
 #endif
 
-#ifdef PC_DOS
-#include <conio.h>
-#endif
-
 //#define NOMD5
 
 // Uncheck this to compile debugging code
@@ -139,8 +129,15 @@ extern char logfilename[1024];
 #define VERSIONSTRING "Development EXE"
 // most interface strings are ignored in development mode.
 // we use comprevision and compbranch instead.
+// VERSIONSTRING_RC is for the resource-definition script used by windows builds
+#else
+#ifdef BETAVERSION
+#define VERSIONSTRING "v"SRB2VERSION" "BETAVERSION
+#define VERSIONSTRING_RC SRB2VERSION " " BETAVERSION "\0"
 #else
 #define VERSIONSTRING "v"SRB2VERSION
+#define VERSIONSTRING_RC SRB2VERSION "\0"
+#endif
 // Hey! If you change this, add 1 to the MODVERSION below!
 // Otherwise we can't force updates!
 #endif
@@ -163,7 +160,9 @@ extern char logfilename[1024];
 // the other options the same.
 
 // Comment out this line to completely disable update alerts (recommended for testing, but not for release)
+#ifndef BETAVERSION
 #define UPDATE_ALERT
+#endif
 
 // The string used in the alert that pops up in the event of an update being available.
 // Please change to apply to your modification (we don't want everyone asking where your mod is on SRB2.org!).
@@ -558,8 +557,8 @@ INT32 I_GetKey(void);
 #endif
 
 // The character that separates pathnames. Forward slash on
-// most systems, but reverse solidus (\) on Windows and DOS.
-#if defined (PC_DOS) || defined (_WIN32)
+// most systems, but reverse solidus (\) on Windows.
+#if defined (_WIN32)
 	#define PATHSEP "\\"
 #else
 	#define PATHSEP "/"
@@ -645,4 +644,10 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 /// Maintain compatibility with older 2.2 demos
 #define OLD22DEMOCOMPAT
 
+#if defined (HAVE_CURL) && ! defined (NONET)
+#define MASTERSERVER
+#else
+#undef UPDATE_ALERT
+#endif
+
 #endif // __DOOMDEF__
diff --git a/src/dummy/i_cdmus.c b/src/dummy/i_cdmus.c
index fc35eb9cf0bec5ac8532c6ae6ec4f685592b51ab..94b8fa30ed150ca99e2e8d320d77c7322af39697 100644
--- a/src/dummy/i_cdmus.c
+++ b/src/dummy/i_cdmus.c
@@ -8,8 +8,8 @@
 
 UINT8 cdaudio_started = 0;
 
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = CVAR_INIT ("cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL);
+consvar_t cdUpdate  = CVAR_INIT ("cd_update","1",CV_SAVE, NULL, NULL);
 
 
 void I_InitCD(void){}
diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c
index 38a67ef3715cb7dceecc196b45e564417b96b5cf..3b0a12a328df587e1cd20d0312cf96ce6c8df847 100644
--- a/src/dummy/i_video.c
+++ b/src/dummy/i_video.c
@@ -9,7 +9,7 @@ boolean highcolor = false;
 
 boolean allow_fullscreen = false;
 
-consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
 
 void I_StartupGraphics(void){}
 void I_ShutdownGraphics(void){}
diff --git a/src/f_finale.c b/src/f_finale.c
index 2a5e0b3c66f4edc7c810adee6041fd11b2093c4c..4322d898d3ac7989b5f1258f784efe0d9cf51672 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -25,6 +25,7 @@
 #include "w_wad.h"
 #include "z_zone.h"
 #include "i_system.h"
+#include "i_threads.h"
 #include "m_menu.h"
 #include "dehacked.h"
 #include "g_input.h"
@@ -224,6 +225,9 @@ static INT32 cutscene_textspeed = 0;
 static UINT8 cutscene_boostspeed = 0;
 static tic_t cutscene_lasttextwrite = 0;
 
+// STJR Intro
+char stjrintro[9] = "STJRI000";
+
 //
 // This alters the text string cutscene_disptext.
 // Use the typical string drawing functions to display it.
@@ -311,7 +315,7 @@ const char *introtext[NUMINTROSCENES];
 
 static tic_t introscenetime[NUMINTROSCENES] =
 {
-	 7*TICRATE + (TICRATE/2),	// STJr Presents
+	5*TICRATE,	// STJr Presents
 	11*TICRATE + (TICRATE/2),	// Two months had passed since...
 	15*TICRATE + (TICRATE/2),	// As it was about to drain the rings...
 	14*TICRATE,					// What Sonic, Tails, and Knuckles...
@@ -526,6 +530,7 @@ static void F_IntroDrawScene(void)
 	switch (intro_scenenum)
 	{
 		case 0:
+			bgxoffs = 28;
 			break;
 		case 1:
 			background = W_CachePatchName("INTRO1", PU_PATCH_LOWPRIORITY);
@@ -616,97 +621,34 @@ static void F_IntroDrawScene(void)
 	}
 	else if (intro_scenenum == 0) // STJr presents
 	{
-		// "Waaaaaaah" intro
-		if (finalecount-TICRATE/2 < 4*TICRATE+23) {
-			// aspect is FRACUNIT/2 for 4:3 (source) resolutions, smaller for 16:10 (SRB2) resolutions
-			fixed_t aspect = (FRACUNIT + (FRACUNIT*4/3 - FRACUNIT*vid.width/vid.height)/2)>>1;
-			fixed_t x,y;
-			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 2);
-			if (finalecount < 30) { // Cry!
-				if (finalecount < 4)
-					S_StopMusic();
-				if (finalecount == 4)
-					S_ChangeMusicInternal("_stjr", false);
-				x = (BASEVIDWIDTH<<FRACBITS)/2 - FixedMul(334<<FRACBITS, aspect)/2;
-				y = (BASEVIDHEIGHT<<FRACBITS)/2 - FixedMul(358<<FRACBITS, aspect)/2;
-				V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH1", PU_PATCH_LOWPRIORITY)), aspect);
-				W_UnlockCachedPatch(patch);
-				if (finalecount > 6) {
-					V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH2", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-				}
-				if (finalecount > 10) {
-					V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH3", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-				}
-				if (finalecount > 14) {
-					V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH4", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-				}
-			}
-			else if (finalecount-30 < 20) { // Big eggy
-				background = W_CachePatchName("FEEDIN", PU_PATCH_LOWPRIORITY);
-				x = (BASEVIDWIDTH<<FRACBITS)/2 - FixedMul(560<<FRACBITS, aspect)/2;
-				y = (BASEVIDHEIGHT<<FRACBITS) - FixedMul(477<<FRACBITS, aspect);
-				V_DrawSciencePatch(x, y, V_SNAPTOBOTTOM, background, aspect);
-			}
-			else if (finalecount-50 < 30) { // Zoom out
-				fixed_t scale = FixedDiv(aspect, FixedDiv((finalecount-50)<<FRACBITS, (15<<FRACBITS))+FRACUNIT);
-				background = W_CachePatchName("FEEDIN", PU_PATCH_LOWPRIORITY);
-				x = (BASEVIDWIDTH<<FRACBITS)/2 - FixedMul(560<<FRACBITS, aspect)/2 + (FixedMul(560<<FRACBITS, aspect) - FixedMul(560<<FRACBITS, scale));
-				y = (BASEVIDHEIGHT<<FRACBITS) - FixedMul(477<<FRACBITS, scale);
-				V_DrawSciencePatch(x, y, V_SNAPTOBOTTOM, background, scale);
-			}
-			else
+		if (intro_curtime > 1 && intro_curtime < (INT32)introscenetime[intro_scenenum])
+		{
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
+			if (intro_curtime < TICRATE-5) // Make the text shine!
+				sprintf(stjrintro, "STJRI%03u", intro_curtime-1);
+			else if (intro_curtime >= TICRATE-6 && intro_curtime < 2*TICRATE-20) // Pause on black screen for just a second
+				return;
+			else if (intro_curtime == 2*TICRATE-19)
 			{
-				{
-					// Draw tiny eggy
-					fixed_t scale = FixedMul(FRACUNIT/3, aspect);
-					background = W_CachePatchName("FEEDIN", PU_PATCH_LOWPRIORITY);
-					x = (BASEVIDWIDTH<<FRACBITS)/2 - FixedMul(560<<FRACBITS, aspect)/2 + (FixedMul(560<<FRACBITS, aspect) - FixedMul(560<<FRACBITS, scale));
-					y = (BASEVIDHEIGHT<<FRACBITS) - FixedMul(477<<FRACBITS, scale);
-					V_DrawSciencePatch(x, y, V_SNAPTOBOTTOM, background, scale);
-				}
+				// Fade in the text
+				// The text fade out is automatically handled when switching to a new intro scene
+				strncpy(stjrintro, "STJRI029", 9);
+				S_ChangeMusicInternal("_stjr", false);
 
-				if (finalecount-84 < 58) { // Pure Fat is driving up!
-					int ftime = (finalecount-84);
-					x = (-189*FRACUNIT) + (FixedMul((6<<FRACBITS)+FRACUNIT/3, ftime<<FRACBITS) - FixedMul((6<<FRACBITS)+FRACUNIT/3, FixedDiv(FixedMul(ftime<<FRACBITS, ftime<<FRACBITS), 120<<FRACBITS)));
-					y = (BASEVIDHEIGHT<<FRACBITS) - FixedMul(417<<FRACBITS, aspect);
-					// Draw the body
-					V_DrawSciencePatch(x, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT1", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-					// Draw the door
-					V_DrawSciencePatch(x+FixedMul(344<<FRACBITS, aspect), y+FixedMul(292<<FRACBITS, aspect), V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT2", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-					// Draw the wheel
-					V_DrawSciencePatch(x+FixedMul(178<<FRACBITS, aspect), y+FixedMul(344<<FRACBITS, aspect), V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName(va("TYRE%02u",(abs(finalecount-144)/3)%16), PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-					// Draw the wheel cover
-					V_DrawSciencePatch(x+FixedMul(88<<FRACBITS, aspect), y+FixedMul(238<<FRACBITS, aspect), V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT3", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-				} else { // Pure Fat has stopped!
-					y = (BASEVIDHEIGHT<<FRACBITS) - FixedMul(417<<FRACBITS, aspect);
-					// Draw the body
-					V_DrawSciencePatch(0, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT1", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-					// Draw the wheel
-					V_DrawSciencePatch(FixedMul(178<<FRACBITS, aspect), y+FixedMul(344<<FRACBITS, aspect), V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("TYRE00", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-					// Draw the wheel cover
-					V_DrawSciencePatch(FixedMul(88<<FRACBITS, aspect), y+FixedMul(238<<FRACBITS, aspect), V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT3", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-					// Draw the door
-					if (finalecount-TICRATE/2 > 4*TICRATE) { // Door is being raised!
-						int ftime = (finalecount-TICRATE/2-4*TICRATE);
-						y -= FixedDiv((ftime*ftime)<<FRACBITS, 23<<FRACBITS);
-					}
-					V_DrawSciencePatch(FixedMul(344<<FRACBITS, aspect), y+FixedMul(292<<FRACBITS, aspect), V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT2", PU_PATCH_LOWPRIORITY)), aspect);
-					W_UnlockCachedPatch(patch);
-				}
+				background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY);
+				wipestyleflags = WSF_FADEIN;
+				F_WipeStartScreen();
+				F_TryColormapFade(31);
+				V_DrawSmallScaledPatch(bgxoffs, 84, 0, background);
+				F_WipeEndScreen();
+				F_RunWipe(0,true);
+			}
+
+			if (!WipeInAction) // Draw the patch if not in a wipe
+			{
+				background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY);
+				V_DrawSmallScaledPatch(bgxoffs, 84, 0, background);
 			}
-		} else {
-			V_DrawCreditString((160 - V_CreditStringWidth("SONIC TEAM JR")/2)<<FRACBITS, 80<<FRACBITS, 0, "SONIC TEAM JR");
-			V_DrawCreditString((160 - V_CreditStringWidth("PRESENTS")/2)<<FRACBITS, 96<<FRACBITS, 0, "PRESENTS");
 		}
 	}
 	else if (intro_scenenum == 10) // Sky Runner
@@ -959,7 +901,13 @@ void F_IntroDrawer(void)
 
 					I_OsPolling();
 					I_UpdateNoBlit();
+#ifdef HAVE_THREADS
+					I_lock_mutex(&m_menu_mutex);
+#endif
 					M_Drawer(); // menu is drawn even on top of wipes
+#ifdef HAVE_THREADS
+					I_unlock_mutex(m_menu_mutex);
+#endif
 					I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
 
 					if (moviemode) // make sure we save frames for the white hold too
@@ -1010,7 +958,7 @@ void F_IntroDrawer(void)
 			F_WipeEndScreen();
 			F_RunWipe(99,true);
 		}
-		/*else if (intro_scenenum == 12 && intro_curtime == 7*TICRATE)
+		/*else if (intro_scenenum == 11 && intro_curtime == 7*TICRATE)
 		{
 			patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY);
 
@@ -1119,61 +1067,58 @@ static const char *credits[] = {
 	"\1Credits",
 	"",
 	"\1Game Design",
-	"Ben \"Mystic\" Geyer",
+	"Sonic Team Junior",
 	"\"SSNTails\"",
 	"Johnny \"Sonikku\" Wallbank",
 	"",
 	"\1Programming",
 	"Alam \"GBC\" Arias",
 	"Logan \"GBA\" Arias",
+	"Colette \"fickleheart\" Bordelon",
+	"Andrew \"orospakr\" Clunis",
+	"Sally \"TehRealSalt\" Cochenour",
+	"Gregor \"Oogaland\" Dick",
 	"Callum Dickinson",
 	"Scott \"Graue\" Feeney",
 	"Victor \"SteelT\" Fuentes",
 	"Nathan \"Jazz\" Giroux",
+	"\"Golden\"",
 	"Vivian \"toaster\" Grannell",
+	"Julio \"Chaos Zero 64\" Guir",
+	"\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
 	"Kepa \"Nev3r\" Iceta",
 	"Thomas \"Shadow Hog\" Igoe",
 	"\"james\"",
 	"Iestyn \"Monster Iestyn\" Jealous",
 	"\"Jimita\"",
-	"Ronald \"Furyhunter\" Kinard", // The SDL2 port
-	"Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol
-	"John \"JTE\" Muniz",
-	"Ehab \"Wolfy\" Saeed",
-	"Jonas \"MascaraSnake\" Sauer",
 	"\"Kaito Sinclaire\"",
-	"\"SSNTails\"",
-	"Lachlan \"Lach\" Wright",
-	"Marco \"mazmazz\" Zafra",
-	"",
-	"\1Programming",
-	"\1Assistance",
-	"Colette \"fickleheart\" Bordelon",
-	"\"chi.miru\"", // helped port slope drawing code from ZDoom
-	"Andrew \"orospakr\" Clunis",
-	"Sally \"TehRealSalt\" Cochenour",
-	"Gregor \"Oogaland\" Dick",
-	"Julio \"Chaos Zero 64\" Guir",
-	"\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
 	"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
+	"Ronald \"Furyhunter\" Kinard", // The SDL2 port
 	"\"Lat'\"", // SRB2-CHAT, the chat window from Kart
 	"Matthew \"Shuffle\" Marsalko",
 	"Steven \"StroggOnMeth\" McGranahan",
 	"\"Morph\"", // For SRB2Morphed stuff
+	"Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol
+	"John \"JTE\" Muniz",
 	"Colin \"Sonict\" Pfaff",
 	"Sean \"Sryder13\" Ryder",
+	"Ehab \"Wolfy\" Saeed",
 	"Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible
+	"Jonas \"MascaraSnake\" Sauer",
 	"Wessel \"sphere\" Smit",
-	"Ben \"Cue\" Woodford",
+	"\"SSNTails\"",
+	"\"Varren\"",
 	"\"VelocitOni\"", // Wrote the original dashmode script
 	"Ikaro \"Tatsuru\" Vinhas",
-	// Git contributors with 5+ approved merges of substantive quality,
-	// or contributors with at least one groundbreaking merge, may be named.
-	// Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors".
+	"Ben \"Cue\" Woodford",
+	"Lachlan \"Lach\" Wright",
+	"Marco \"mazmazz\" Zafra",
 	"",
 	"\1Art",
 	"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
+	"\"Arrietty\"",
 	"Ryan \"Blaze Hedgehog\" Bloom",
+	"Graeme P. \"SuperPhanto\" Caldwell", // for the new brak render
 	"\"ChrispyPixels\"",
 	"Paul \"Boinciel\" Clempson",
 	"Sally \"TehRealSalt\" Cochenour",
@@ -1181,6 +1126,7 @@ static const char *credits[] = {
 	"Desmond \"Blade\" DesJardins",
 	"Sherman \"CoatRack\" DesJardins",
 	"\"DirkTheHusky\"",
+	"Jesse \"Jeck Jims\" Emerick",
 	"Buddy \"KinkaJoy\" Fischer",
 	"Vivian \"toaster\" Grannell",
 	"James \"SwitchKaze\" Hale",
@@ -1193,6 +1139,7 @@ static const char *credits[] = {
 	"Andrew \"Senku Niola\" Moran",
 	"\"MotorRoach\"",
 	"Phillip \"TelosTurntable\" Robinson",
+	"\"Scizor300\"",
 	"Wessel \"sphere\" Smit",
 	"David \"Instant Sonic\" Spencer Jr.",
 	"\"SSNTails\"",
@@ -1206,9 +1153,9 @@ static const char *credits[] = {
 	"Malcolm \"RedXVI\" Brown",
 	"Dave \"DemonTomatoDave\" Bulmer",
 	"Paul \"Boinciel\" Clempson",
+	"\"Cyan Helkaraxe\"",
 	"Shane \"CobaltBW\" Ellis",
 	"James \"SeventhSentinel\" Hall",
-	"Cyan Helkaraxe",
 	"Kepa \"Nev3r\" Iceta",
 	"Iestyn \"Monster Iestyn\" Jealous",
 	"Jarel \"Arrow\" Jones",
@@ -1235,8 +1182,9 @@ static const char *credits[] = {
 	"James \"SeventhSentinel\" Hall",
 	"Kepa \"Nev3r\" Iceta",
 	"Thomas \"Shadow Hog\" Igoe",
-	"Alexander \"DrTapeworm\" Moench-Ford",
 	"\"Kaito Sinclaire\"",
+	"Alexander \"DrTapeworm\" Moench-Ford",
+	"\"Revan\"",
 	"Anna \"QueenDelta\" Sandlin",
 	"Wessel \"sphere\" Smit",
 	"\"Spazzo\"",
@@ -1276,13 +1224,6 @@ static const char *credits[] = {
 	"Pascal \"CodeImp\" vd Heiden", // Doom Builder developer
 	"Randi Heit (<!>)", // For their MSPaint <!> sprite that we nicked
 	"Simon \"sirjuddington\" Judd", // SLADE developer
-	// Acknowledged here are the following:
-	// Minor merge request authors, see guideline above
-	// - Golden - Expanded thin font
-	// Creators of small quantities of sprite/texture assets
-	// - Arietty - New Green Hill-styled textures
-	// - Scizor300 - the only other contributor to the 2.0 SRB2 Asset Pack
-	// - Revan/Icefox - the new Nimbus Ruins skybox
 	"SRB2 Community Contributors",
 	"",
 	"\1Produced By",
@@ -4082,7 +4023,7 @@ void F_CutsceneTicker(void)
 		if (netgame && i != serverplayer && !IsPlayerAdmin(i))
 			continue;
 
-		if (players[i].cmd.buttons & BT_USE)
+		if (players[i].cmd.buttons & BT_SPIN)
 		{
 			keypressed = false;
 			cutscene_boostspeed = 1;
@@ -4422,11 +4363,11 @@ static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length)
 	else if (!strncmp(tag, "TAJ", 3)) // Jump
 		gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
 	else if (!strncmp(tag, "TAS", 3)) // Spin
-		gcs = G_GetControlScheme(gamecontrol, gcl_use, num_gcl_use);
+		gcs = G_GetControlScheme(gamecontrol, gcl_spin, num_gcl_spin);
 	else if (!strncmp(tag, "TAA", 3)) // Char ability
 		gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
 	else if (!strncmp(tag, "TAW", 3)) // Shield ability
-		gcs = G_GetControlScheme(gamecontrol, gcl_jump_use, num_gcl_jump_use);
+		gcs = G_GetControlScheme(gamecontrol, gcl_jump_spin, num_gcl_jump_spin);
 	else
 		gcs = G_GetControlScheme(gamecontrol, gcl_tutorial_used, num_gcl_tutorial_used);
 
@@ -4683,7 +4624,7 @@ void F_TextPromptTicker(void)
 				else
 					continue;
 
-				if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP))
+				if ((players[i].cmd.buttons & BT_SPIN) || (players[i].cmd.buttons & BT_JUMP))
 				{
 					if (timetonext > 1)
 						timetonext--;
@@ -4706,7 +4647,7 @@ void F_TextPromptTicker(void)
 					}
 					keypressed = true; // prevent repeat events
 				}
-				else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP))
+				else if (!(players[i].cmd.buttons & BT_SPIN) && !(players[i].cmd.buttons & BT_JUMP))
 					keypressed = false;
 
 				if (!splitscreen)
diff --git a/src/f_wipe.c b/src/f_wipe.c
index 01b45b0c2927e6fe6e1f054c156bd0e016a0ed48..f5b9bd72230ae7f5763b7fdc97cbbca9398d0ff5 100644
--- a/src/f_wipe.c
+++ b/src/f_wipe.c
@@ -25,6 +25,7 @@
 #include "z_zone.h"
 
 #include "i_system.h"
+#include "i_threads.h"
 #include "m_menu.h"
 #include "console.h"
 #include "d_main.h"
@@ -595,7 +596,15 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
 		I_UpdateNoBlit();
 
 		if (drawMenu)
+		{
+#ifdef HAVE_THREADS
+			I_lock_mutex(&m_menu_mutex);
+#endif
 			M_Drawer(); // menu is drawn even on top of wipes
+#ifdef HAVE_THREADS
+			I_unlock_mutex(m_menu_mutex);
+#endif
+		}
 
 		I_FinishUpdate(); // page flip or blit buffer
 
diff --git a/src/filesrch.c b/src/filesrch.c
index 13d73b6f49845b5b693ff69080b2a779e1364b9d..cb53d07be958fe1ab7ad42ffac3efc0ee768e44f 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -312,18 +312,18 @@ static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"},
 #endif
 													{3, "CUSTOM"}, {0, NULL}};
 
-consvar_t cv_addons_option = {"addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_addons_folder = {"addons_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_addons_option = CVAR_INIT ("addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange);
+consvar_t cv_addons_folder = CVAR_INIT ("addons_folder", "", CV_SAVE, NULL, NULL);
 
 static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}};
-consvar_t cv_addons_md5 = {"addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_addons_md5 = CVAR_INIT ("addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL);
 
-consvar_t cv_addons_showall = {"addons_showall", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_addons_showall = CVAR_INIT ("addons_showall", "No", CV_SAVE, CV_YesNo, NULL);
 
-consvar_t cv_addons_search_case = {"addons_search_case", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_addons_search_case = CVAR_INIT ("addons_search_case", "No", CV_SAVE, CV_YesNo, NULL);
 
 static CV_PossibleValue_t addons_search_type_cons_t[] = {{0, "Start"}, {1, "Anywhere"}, {0, NULL}};
-consvar_t cv_addons_search_type = {"addons_search_type", "Anywhere", CV_SAVE, addons_search_type_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_addons_search_type = CVAR_INIT ("addons_search_type", "Anywhere", CV_SAVE, addons_search_type_cons_t, NULL);
 
 char menupath[1024];
 size_t menupathindex[menudepth];
diff --git a/src/g_demo.c b/src/g_demo.c
index 57a955cb130a3dfa886ab73ad408bfd0b5fce68e..e45f23b62446d280883f6d36816214dab696a381 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -94,7 +94,7 @@ demoghost *ghosts = NULL;
 // DEMO RECORDING
 //
 
-#define DEMOVERSION 0x000d
+#define DEMOVERSION 0x000e
 #define DEMOHEADER  "\xF0" "SRB2Replay" "\x0F"
 
 #define DF_GHOST        0x01 // This demo contains ghost data too!
@@ -345,32 +345,29 @@ void G_WriteGhostTic(mobj_t *ghost)
 	else
 	{
 		// For moving normally:
-		// Store one full byte of movement, plus one byte of fractional movement.
-		INT16 momx = (INT16)((ghost->x-oldghost.x)>>8);
-		INT16 momy = (INT16)((ghost->y-oldghost.y)>>8);
+		fixed_t momx = ghost->x-oldghost.x;
+		fixed_t momy = ghost->y-oldghost.y;
 		if (momx != oldghost.momx
 		|| momy != oldghost.momy)
 		{
 			oldghost.momx = momx;
 			oldghost.momy = momy;
 			ziptic |= GZT_MOMXY;
-			WRITEINT16(demo_p,momx);
-			WRITEINT16(demo_p,momy);
+			WRITEFIXED(demo_p,momx);
+			WRITEFIXED(demo_p,momy);
 		}
-		momx = (INT16)((ghost->z-oldghost.z)>>8);
+		momx = ghost->z-oldghost.z;
 		if (momx != oldghost.momz)
 		{
 			oldghost.momz = momx;
 			ziptic |= GZT_MOMZ;
-			WRITEINT16(demo_p,momx);
+			WRITEFIXED(demo_p,momx);
 		}
 
 		// This SHOULD set oldghost.x/y/z to match ghost->x/y/z
-		// but it keeps the fractional loss of one byte,
-		// so it will hopefully be made up for in future tics.
-		oldghost.x += oldghost.momx<<8;
-		oldghost.y += oldghost.momy<<8;
-		oldghost.z += oldghost.momz<<8;
+		oldghost.x += oldghost.momx;
+		oldghost.y += oldghost.momy;
+		oldghost.z += oldghost.momz;
 	}
 
 	#undef MAXMOM
@@ -464,7 +461,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 
 	if (ghost->player && ghost->player->followmobj && !(ghost->player->followmobj->sprite == SPR_NULL || (ghost->player->followmobj->flags2 & MF2_DONTDRAW))) // bloats tails runs but what can ya do
 	{
-		INT16 temp;
+		fixed_t temp;
 		UINT8 *followtic_p = demo_p++;
 		UINT8 followtic = 0;
 
@@ -492,12 +489,12 @@ void G_WriteGhostTic(mobj_t *ghost)
 			WRITEFIXED(demo_p,ghost->player->followmobj->scale);
 		}
 
-		temp = (INT16)((ghost->player->followmobj->x-ghost->x)>>8);
-		WRITEINT16(demo_p,temp);
-		temp = (INT16)((ghost->player->followmobj->y-ghost->y)>>8);
-		WRITEINT16(demo_p,temp);
-		temp = (INT16)((ghost->player->followmobj->z-ghost->z)>>8);
-		WRITEINT16(demo_p,temp);
+		temp = ghost->player->followmobj->x-ghost->x;
+		WRITEFIXED(demo_p,temp);
+		temp = ghost->player->followmobj->y-ghost->y;
+		WRITEFIXED(demo_p,temp);
+		temp = ghost->player->followmobj->z-ghost->z;
+		WRITEFIXED(demo_p,temp);
 		if (followtic & FZT_SKIN)
 			WRITEUINT8(demo_p,ghost->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
@@ -547,11 +544,11 @@ void G_ConsGhostTic(void)
 	{
 		if (ziptic & GZT_MOMXY)
 		{
-			oldghost.momx = READINT16(demo_p)<<8;
-			oldghost.momy = READINT16(demo_p)<<8;
+			oldghost.momx = (demoversion < 0x000e) ? READINT16(demo_p)<<8 : READFIXED(demo_p);
+			oldghost.momy = (demoversion < 0x000e) ? READINT16(demo_p)<<8 : READFIXED(demo_p);
 		}
 		if (ziptic & GZT_MOMZ)
-			oldghost.momz = READINT16(demo_p)<<8;
+			oldghost.momz = (demoversion < 0x000e) ? READINT16(demo_p)<<8 : READFIXED(demo_p);
 		oldghost.x += oldghost.momx;
 		oldghost.y += oldghost.momy;
 		oldghost.z += oldghost.momz;
@@ -627,9 +624,8 @@ void G_ConsGhostTic(void)
 		}
 		if (followtic & FZT_SCALE)
 			demo_p += sizeof(fixed_t);
-		demo_p += sizeof(INT16);
-		demo_p += sizeof(INT16);
-		demo_p += sizeof(INT16);
+		// momx, momy and momz
+		demo_p += (demoversion < 0x000e) ? sizeof(UINT16) * 3 : sizeof(fixed_t) * 3;
 		if (followtic & FZT_SKIN)
 			demo_p++;
 		demo_p += sizeof(UINT16);
@@ -697,11 +693,11 @@ void G_GhostTicker(void)
 		{
 			if (ziptic & GZT_MOMXY)
 			{
-				g->oldmo.momx = READINT16(g->p)<<8;
-				g->oldmo.momy = READINT16(g->p)<<8;
+				g->oldmo.momx = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
+				g->oldmo.momy = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
 			}
 			if (ziptic & GZT_MOMZ)
-				g->oldmo.momz = READINT16(g->p)<<8;
+				g->oldmo.momz = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
 			g->oldmo.x += g->oldmo.momx;
 			g->oldmo.y += g->oldmo.momy;
 			g->oldmo.z += g->oldmo.momz;
@@ -905,11 +901,11 @@ void G_GhostTicker(void)
 					P_SetScale(follow, follow->destscale);
 
 				P_UnsetThingPosition(follow);
-				temp = READINT16(g->p)<<8;
+				temp = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
 				follow->x = g->mo->x + temp;
-				temp = READINT16(g->p)<<8;
+				temp = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
 				follow->y = g->mo->y + temp;
-				temp = READINT16(g->p)<<8;
+				temp = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
 				follow->z = g->mo->z + temp;
 				P_SetThingPosition(follow);
 				if (followtic & FZT_SKIN)
@@ -1010,11 +1006,11 @@ void G_ReadMetalTic(mobj_t *metal)
 	{
 		if (ziptic & GZT_MOMXY)
 		{
-			oldmetal.momx = READINT16(metal_p)<<8;
-			oldmetal.momy = READINT16(metal_p)<<8;
+			oldmetal.momx = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
+			oldmetal.momy = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
 		}
 		if (ziptic & GZT_MOMZ)
-			oldmetal.momz = READINT16(metal_p)<<8;
+			oldmetal.momz = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
 		oldmetal.x += oldmetal.momx;
 		oldmetal.y += oldmetal.momy;
 		oldmetal.z += oldmetal.momz;
@@ -1149,11 +1145,11 @@ void G_ReadMetalTic(mobj_t *metal)
 					P_SetScale(follow, follow->destscale);
 
 				P_UnsetThingPosition(follow);
-				temp = READINT16(metal_p)<<8;
+				temp = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
 				follow->x = metal->x + temp;
-				temp = READINT16(metal_p)<<8;
+				temp = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
 				follow->y = metal->y + temp;
-				temp = READINT16(metal_p)<<8;
+				temp = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
 				follow->z = metal->z + temp;
 				P_SetThingPosition(follow);
 				if (followtic & FZT_SKIN)
@@ -1213,32 +1209,30 @@ void G_WriteMetalTic(mobj_t *metal)
 	else
 	{
 		// For moving normally:
-		// Store one full byte of movement, plus one byte of fractional movement.
-		INT16 momx = (INT16)((metal->x-oldmetal.x)>>8);
-		INT16 momy = (INT16)((metal->y-oldmetal.y)>>8);
+		// Store movement as a fixed value
+		fixed_t momx = metal->x-oldmetal.x;
+		fixed_t momy = metal->y-oldmetal.y;
 		if (momx != oldmetal.momx
 		|| momy != oldmetal.momy)
 		{
 			oldmetal.momx = momx;
 			oldmetal.momy = momy;
 			ziptic |= GZT_MOMXY;
-			WRITEINT16(demo_p,momx);
-			WRITEINT16(demo_p,momy);
+			WRITEFIXED(demo_p,momx);
+			WRITEFIXED(demo_p,momy);
 		}
-		momx = (INT16)((metal->z-oldmetal.z)>>8);
+		momx = metal->z-oldmetal.z;
 		if (momx != oldmetal.momz)
 		{
 			oldmetal.momz = momx;
 			ziptic |= GZT_MOMZ;
-			WRITEINT16(demo_p,momx);
+			WRITEFIXED(demo_p,momx);
 		}
 
 		// This SHOULD set oldmetal.x/y/z to match metal->x/y/z
-		// but it keeps the fractional loss of one byte,
-		// so it will hopefully be made up for in future tics.
-		oldmetal.x += oldmetal.momx<<8;
-		oldmetal.y += oldmetal.momy<<8;
-		oldmetal.z += oldmetal.momz<<8;
+		oldmetal.x += oldmetal.momx;
+		oldmetal.y += oldmetal.momy;
+		oldmetal.z += oldmetal.momz;
 	}
 
 	#undef MAXMOM
@@ -1307,7 +1301,7 @@ void G_WriteMetalTic(mobj_t *metal)
 
 	if (metal->player && metal->player->followmobj && !(metal->player->followmobj->sprite == SPR_NULL || (metal->player->followmobj->flags2 & MF2_DONTDRAW)))
 	{
-		INT16 temp;
+		fixed_t temp;
 		UINT8 *followtic_p = demo_p++;
 		UINT8 followtic = 0;
 
@@ -1335,12 +1329,12 @@ void G_WriteMetalTic(mobj_t *metal)
 			WRITEFIXED(demo_p,metal->player->followmobj->scale);
 		}
 
-		temp = (INT16)((metal->player->followmobj->x-metal->x)>>8);
-		WRITEINT16(demo_p,temp);
-		temp = (INT16)((metal->player->followmobj->y-metal->y)>>8);
-		WRITEINT16(demo_p,temp);
-		temp = (INT16)((metal->player->followmobj->z-metal->z)>>8);
-		WRITEINT16(demo_p,temp);
+		temp = metal->player->followmobj->x-metal->x;
+		WRITEFIXED(demo_p,temp);
+		temp = metal->player->followmobj->y-metal->y;
+		WRITEFIXED(demo_p,temp);
+		temp = metal->player->followmobj->z-metal->z;
+		WRITEFIXED(demo_p,temp);
 		if (followtic & FZT_SKIN)
 			WRITEUINT8(demo_p,metal->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,metal->player->followmobj->sprite);
@@ -1818,6 +1812,7 @@ void G_DoPlayDemo(char *defdemoname)
 	demoversion = READUINT16(demo_p);
 	switch(demoversion)
 	{
+	case 0x000d:
 	case DEMOVERSION: // latest always supported
 		cnamelen = MAXCOLORNAME;
 		break;
@@ -1933,9 +1928,8 @@ void G_DoPlayDemo(char *defdemoname)
 	if (use_old_demo_vars)
 		CV_LoadOldDemoVars(&demo_p);
 	else
-#else
-		CV_LoadDemoVars(&demo_p);
 #endif
+		CV_LoadDemoVars(&demo_p);
 
 	// Sigh ... it's an empty demo.
 	if (*demo_p == DEMOMARKER)
@@ -2073,6 +2067,7 @@ void G_AddGhost(char *defdemoname)
 	ghostversion = READUINT16(p);
 	switch(ghostversion)
 	{
+	case 0x000d:
 	case DEMOVERSION: // latest always supported
 		cnamelen = MAXCOLORNAME;
 		break;
@@ -2324,6 +2319,7 @@ void G_DoPlayMetal(void)
 	switch(metalversion)
 	{
 	case DEMOVERSION: // latest always supported
+	case 0x000d: // There are checks wheter the momentum is from older demo versions or not
 	case 0x000c: // all that changed between then and now was longer color name
 		break;
 	// too old, cannot support.
diff --git a/src/g_game.c b/src/g_game.c
index e165d5415a0f6085b069259263a100cf1d22c104..f7c798b4bd1209fc22e45d5186b27bcb2aebfa94 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -297,100 +297,100 @@ static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
 // don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler.
 
 // it automatically becomes compact with 20+ players, but if you like it, I guess you can turn that on!
-consvar_t cv_compactscoreboard= {"compactscoreboard", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_compactscoreboard= CVAR_INIT ("compactscoreboard", "Off", CV_SAVE, CV_OnOff, NULL);
 
 // chat timer thingy
 static CV_PossibleValue_t chattime_cons_t[] = {{5, "MIN"}, {999, "MAX"}, {0, NULL}};
-consvar_t cv_chattime = {"chattime", "8", CV_SAVE, chattime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chattime = CVAR_INIT ("chattime", "8", CV_SAVE, chattime_cons_t, NULL);
 
 // chatwidth
 static CV_PossibleValue_t chatwidth_cons_t[] = {{64, "MIN"}, {300, "MAX"}, {0, NULL}};
-consvar_t cv_chatwidth = {"chatwidth", "150", CV_SAVE, chatwidth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chatwidth = CVAR_INIT ("chatwidth", "150", CV_SAVE, chatwidth_cons_t, NULL);
 
 // chatheight
 static CV_PossibleValue_t chatheight_cons_t[] = {{6, "MIN"}, {22, "MAX"}, {0, NULL}};
-consvar_t cv_chatheight= {"chatheight", "8", CV_SAVE, chatheight_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chatheight= CVAR_INIT ("chatheight", "8", CV_SAVE, chatheight_cons_t, NULL);
 
 // chat notifications (do you want to hear beeps? I'd understand if you didn't.)
-consvar_t cv_chatnotifications= {"chatnotifications", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chatnotifications= CVAR_INIT ("chatnotifications", "On", CV_SAVE, CV_OnOff, NULL);
 
 // chat spam protection (why would you want to disable that???)
-consvar_t cv_chatspamprotection= {"chatspamprotection", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chatspamprotection= CVAR_INIT ("chatspamprotection", "On", CV_SAVE, CV_OnOff, NULL);
 
 // minichat text background
-consvar_t cv_chatbacktint = {"chatbacktint", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chatbacktint = CVAR_INIT ("chatbacktint", "On", CV_SAVE, CV_OnOff, NULL);
 
 // old shit console chat. (mostly exists for stuff like terminal, not because I cared if anyone liked the old chat.)
 static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}};
-consvar_t cv_consolechat = {"chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_consolechat = CVAR_INIT ("chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL);
 
 // Pause game upon window losing focus
-consvar_t cv_pauseifunfocused = {"pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_crosshair = {"crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_crosshair2 = {"crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_invertmouse = {"invertmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_invertmouse2 = {"invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chasefreelook = {"chasemlook", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chasefreelook2 = {"chasemlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mousemove = {"mousemove", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mousemove2 = {"mousemove2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL);
+
+consvar_t cv_crosshair = CVAR_INIT ("crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL);
+consvar_t cv_crosshair2 = CVAR_INIT ("crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL);
+consvar_t cv_invertmouse = CVAR_INIT ("invertmouse", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_alwaysfreelook = CVAR_INIT ("alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_invertmouse2 = CVAR_INIT ("invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_alwaysfreelook2 = CVAR_INIT ("alwaysmlook2", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_chasefreelook = CVAR_INIT ("chasemlook", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_chasefreelook2 = CVAR_INIT ("chasemlook2", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_mousemove = CVAR_INIT ("mousemove", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_mousemove2 = CVAR_INIT ("mousemove2", "Off", CV_SAVE, CV_OnOff, NULL);
 
 // previously "analog", "analog2", "useranalog", and "useranalog2", invalidating 2.1-era copies of config.cfg
 // changed because it'd be nice to see people try out our actually good controls with gamepads now autobrake exists
 consvar_t cv_analog[2] = {
-	{"sessionanalog", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog_OnChange, 0, NULL, NULL, 0, 0, NULL},
-	{"sessionanalog2", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog2_OnChange, 0, NULL, NULL, 0, 0, NULL}
+	CVAR_INIT ("sessionanalog", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog_OnChange),
+	CVAR_INIT ("sessionanalog2", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog2_OnChange),
 };
 consvar_t cv_useranalog[2] = {
-	{"configanalog", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog_OnChange, 0, NULL, NULL, 0, 0, NULL},
-	{"configanalog2", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog2_OnChange, 0, NULL, NULL, 0, 0, NULL}
+	CVAR_INIT ("configanalog", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog_OnChange),
+	CVAR_INIT ("configanalog2", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog2_OnChange),
 };
 
 // deez New User eXperiences
 static CV_PossibleValue_t directionchar_cons_t[] = {{0, "Camera"}, {1, "Movement"}, {2, "Simple Locked"}, {0, NULL}};
 consvar_t cv_directionchar[2] = {
-	{"directionchar", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar_OnChange, 0, NULL, NULL, 0, 0, NULL},
-	{"directionchar2", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar2_OnChange, 0, NULL, NULL, 0, 0, NULL}
+	CVAR_INIT ("directionchar", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar_OnChange),
+	CVAR_INIT ("directionchar2", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar2_OnChange),
 };
-consvar_t cv_autobrake = {"autobrake", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_autobrake2 = {"autobrake2", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake2_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_autobrake = CVAR_INIT ("autobrake", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake_OnChange);
+consvar_t cv_autobrake2 = CVAR_INIT ("autobrake2", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake2_OnChange);
 
 // hi here's some new controls
 static CV_PossibleValue_t zerotoone_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}};
 consvar_t cv_cam_shiftfacing[2] = {
-	{"cam_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
+	CVAR_INIT ("cam2_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
 };
 consvar_t cv_cam_turnfacing[2] = {
-	{"cam_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
+	CVAR_INIT ("cam2_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
 };
 consvar_t cv_cam_turnfacingability[2] = {
-	{"cam_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
+	CVAR_INIT ("cam2_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
 };
 consvar_t cv_cam_turnfacingspindash[2] = {
-	{"cam_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
+	CVAR_INIT ("cam2_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
 };
 consvar_t cv_cam_turnfacinginput[2] = {
-	{"cam_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
+	CVAR_INIT ("cam2_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
 };
 
 static CV_PossibleValue_t centertoggle_cons_t[] = {{0, "Hold"}, {1, "Toggle"}, {2, "Sticky Hold"}, {0, NULL}};
 consvar_t cv_cam_centertoggle[2] = {
-	{"cam_centertoggle", "Hold", CV_SAVE, centertoggle_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_centertoggle", "Hold", CV_SAVE, centertoggle_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_centertoggle", "Hold", CV_SAVE, centertoggle_cons_t, NULL),
+	CVAR_INIT ("cam2_centertoggle", "Hold", CV_SAVE, centertoggle_cons_t, NULL),
 };
 
 static CV_PossibleValue_t lockedinput_cons_t[] = {{0, "Strafe"}, {1, "Turn"}, {0, NULL}};
 consvar_t cv_cam_lockedinput[2] = {
-	{"cam_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL),
+	CVAR_INIT ("cam2_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL),
 };
 
 static CV_PossibleValue_t lockedassist_cons_t[] = {
@@ -402,8 +402,8 @@ static CV_PossibleValue_t lockedassist_cons_t[] = {
 	{0, NULL}
 };
 consvar_t cv_cam_lockonboss[2] = {
-	{"cam_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
-	{"cam2_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
+	CVAR_INIT ("cam_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL),
+	CVAR_INIT ("cam2_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL),
 };
 
 typedef enum
@@ -422,27 +422,27 @@ typedef enum
 	AXISFIRENORMAL,
 } axis_input_e;
 
-consvar_t cv_turnaxis = {"joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_moveaxis = {"joyaxis_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_sideaxis = {"joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_jumpaxis = {"joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_spinaxis = {"joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_deadzone = {"joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_digitaldeadzone = {"joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_moveaxis2 = {"joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_sideaxis2 = {"joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_lookaxis2 = {"joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_jumpaxis2 = {"joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_spinaxis2 = {"joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_deadzone2 = {"joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_digitaldeadzone2 = {"joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_turnaxis = CVAR_INIT ("joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_moveaxis = CVAR_INIT ("joyaxis_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_sideaxis = CVAR_INIT ("joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_lookaxis = CVAR_INIT ("joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_jumpaxis = CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_spinaxis = CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_fireaxis = CVAR_INIT ("joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_firenaxis = CVAR_INIT ("joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_deadzone = CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+consvar_t cv_digitaldeadzone = CVAR_INIT ("joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+
+consvar_t cv_turnaxis2 = CVAR_INIT ("joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_moveaxis2 = CVAR_INIT ("joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_sideaxis2 = CVAR_INIT ("joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_lookaxis2 = CVAR_INIT ("joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_jumpaxis2 = CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_spinaxis2 = CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_fireaxis2 = CVAR_INIT ("joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_firenaxis2 = CVAR_INIT ("joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL);
+consvar_t cv_deadzone2 = CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
+consvar_t cv_digitaldeadzone2 = CVAR_INIT ("joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL);
 
 #ifdef SEENAMES
 player_t *seenplayer; // player we're aiming at right now
@@ -452,6 +452,8 @@ player_t *seenplayer; // player we're aiming at right now
 // so that it doesn't have to be updated depending on the value of MAXPLAYERS
 char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
 
+INT32 player_name_changes[MAXPLAYERS];
+
 INT16 rw_maximums[NUM_WEAPONS] =
 {
 	800, // MAX_INFINITY
@@ -1340,8 +1342,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 
 	// use with any button/key
 	axis = PlayerJoyAxis(ssplayer, AXISSPIN);
-	if (PLAYERINPUTDOWN(ssplayer, gc_use) || (usejoystick && axis > 0))
-		cmd->buttons |= BT_USE;
+	if (PLAYERINPUTDOWN(ssplayer, gc_spin) || (usejoystick && axis > 0))
+		cmd->buttons |= BT_SPIN;
 
 	// Centerview can be a toggle in simple mode!
 	{
@@ -1675,6 +1677,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 		}
 	}
 
+	// Note: Lat originally made the PlayerCmd hook for SRB2 Kart so credit goes to him.
+	if (gamestate == GS_LEVEL)
+		LUAh_PlayerCmd(player, cmd);
+
 	//Reset away view if a command is given.
 	if (ssplayer == 1 && (cmd->forwardmove || cmd->sidemove || cmd->buttons)
 		&& displayplayer != consoleplayer)
@@ -2248,7 +2254,10 @@ void G_Ticker(boolean run)
 
 			players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn;
 			players[i].oldrelangleturn = players[i].cmd.angleturn;
-			players[i].cmd.angleturn = players[i].angleturn;
+			if (P_ControlStyle(&players[i]) == CS_LMAOGALOG)
+				P_ForceLocalAngle(&players[i], players[i].angleturn << 16);
+			else
+				players[i].cmd.angleturn = players[i].angleturn;
 		}
 	}
 
@@ -2342,6 +2351,11 @@ void G_Ticker(boolean run)
 
 		if (camtoggledelay2)
 			camtoggledelay2--;
+
+		if (gametic % NAMECHANGERATE == 0)
+		{
+			memset(player_name_changes, 0, sizeof player_name_changes);
+		}
 	}
 }
 
@@ -2572,7 +2586,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
 	p->spheres = spheres;
 
 	// Don't do anything immediately
-	p->pflags |= PF_USEDOWN;
+	p->pflags |= PF_SPINDOWN;
 	p->pflags |= PF_ATTACKDOWN;
 	p->pflags |= PF_JUMPDOWN;
 
@@ -3805,7 +3819,7 @@ static void G_DoCompleted(void)
 	// a map of the proper gametype -- skip levels that don't support
 	// the current gametype. (Helps avoid playing boss levels in Race,
 	// for instance).
-	if (!spec)
+	if (!spec || nextmapoverride)
 	{
 		if (nextmap >= 0 && nextmap < NUMMAPS)
 		{
@@ -3857,7 +3871,8 @@ static void G_DoCompleted(void)
 		if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1)
 			I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1);
 
-		lastmap = nextmap; // Remember last map for when you come out of the special stage.
+		if (!spec)
+			lastmap = nextmap; // Remember last map for when you come out of the special stage.
 	}
 
 	if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token)))
@@ -3878,7 +3893,7 @@ static void G_DoCompleted(void)
 		}
 	}
 
-	if (spec && !gottoken)
+	if (spec && !gottoken && !nextmapoverride)
 		nextmap = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001
 
 	automapactive = false;
diff --git a/src/g_game.h b/src/g_game.h
index c8abe560c629a607f6e3d1f24895abfc3a281a64..2bcf444c234c244c2f8f76aab62cebee226d18ee 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -18,6 +18,7 @@
 #include "doomstat.h"
 #include "d_event.h"
 #include "g_demo.h"
+#include "m_cheat.h" // objectplacing
 
 extern char gamedatafilename[64];
 extern char timeattackfolder[64];
@@ -27,7 +28,8 @@ extern char customversionstring[32];
 #ifdef SEENAMES
 extern player_t *seenplayer;
 #endif
-extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
+extern char  player_names[MAXPLAYERS][MAXPLAYERNAME+1];
+extern INT32 player_name_changes[MAXPLAYERS];
 
 extern player_t players[MAXPLAYERS];
 extern boolean playeringame[MAXPLAYERS];
@@ -64,7 +66,7 @@ typedef enum {
 	CS_STANDARD,
 	CS_SIMPLE = CS_LMAOGALOG|CS_STANDARD,
 } controlstyle_e;
-#define G_ControlStyle(ssplayer) (cv_directionchar[(ssplayer)-1].value == 3 ? CS_LMAOGALOG : ((cv_analog[(ssplayer)-1].value ? CS_LMAOGALOG : 0) | (cv_directionchar[(ssplayer)-1].value ? CS_STANDARD : 0)))
+#define G_ControlStyle(ssplayer) (cv_directionchar[(ssplayer)-1].value == 3 ? CS_LMAOGALOG : ((!objectplacing && cv_analog[(ssplayer)-1].value ? CS_LMAOGALOG : 0) | (cv_directionchar[(ssplayer)-1].value ? CS_STANDARD : 0)))
 #define P_ControlStyle(player) ((((player)->pflags & PF_ANALOGMODE) ? CS_LMAOGALOG : 0) | (((player)->pflags & PF_DIRECTIONCHAR) ? CS_STANDARD : 0))
 
 extern consvar_t cv_autobrake, cv_autobrake2;
diff --git a/src/g_input.c b/src/g_input.c
index ecce4d83c8444457d0db4f632e5921959c44685e..d3c21e774c4359d4f2433379dcbbe6e7fdc79436 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -25,11 +25,11 @@ static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY
 static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}};
 
 // mouse values are used once
-consvar_t cv_mousesens = {"mousesens", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mousesens2 = {"mousesens2", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mouseysens = {"mouseysens", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mouseysens2 = {"mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_controlperkey = {"controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mousesens = CVAR_INIT ("mousesens", "20", CV_SAVE, mousesens_cons_t, NULL);
+consvar_t cv_mousesens2 = CVAR_INIT ("mousesens2", "20", CV_SAVE, mousesens_cons_t, NULL);
+consvar_t cv_mouseysens = CVAR_INIT ("mouseysens", "20", CV_SAVE, mousesens_cons_t, NULL);
+consvar_t cv_mouseysens2 = CVAR_INIT ("mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL);
+consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL);
 
 INT32 mousex, mousey;
 INT32 mlooky; // like mousey but with a custom sensitivity for mlook
@@ -57,13 +57,13 @@ const INT32 gcl_tutorial_check[num_gcl_tutorial_check] = {
 const INT32 gcl_tutorial_used[num_gcl_tutorial_used] = {
 	gc_forward, gc_backward, gc_strafeleft, gc_straferight,
 	gc_turnleft, gc_turnright,
-	gc_jump, gc_use
+	gc_jump, gc_spin
 };
 
 const INT32 gcl_tutorial_full[num_gcl_tutorial_full] = {
 	gc_forward, gc_backward, gc_strafeleft, gc_straferight,
 	gc_lookup, gc_lookdown, gc_turnleft, gc_turnright, gc_centerview,
-	gc_jump, gc_use,
+	gc_jump, gc_spin,
 	gc_fire, gc_firenormal
 };
 
@@ -82,10 +82,10 @@ const INT32 gcl_movement_camera[num_gcl_movement_camera] = {
 
 const INT32 gcl_jump[num_gcl_jump] = { gc_jump };
 
-const INT32 gcl_use[num_gcl_use] = { gc_use };
+const INT32 gcl_spin[num_gcl_spin] = { gc_spin };
 
-const INT32 gcl_jump_use[num_gcl_jump_use] = {
-	gc_jump, gc_use
+const INT32 gcl_jump_spin[num_gcl_jump_spin] = {
+	gc_jump, gc_spin
 };
 
 typedef struct
@@ -583,7 +583,7 @@ static const char *gamecontrolname[num_gamecontrols] =
 	"fire",
 	"firenormal",
 	"tossflag",
-	"use",
+	"spin",
 	"camtoggle",
 	"camreset",
 	"lookup",
@@ -692,7 +692,7 @@ void G_DefineDefaultControls(void)
 	gamecontroldefault[gcs_fps][gc_turnright  ][0] = KEY_RIGHTARROW;
 	gamecontroldefault[gcs_fps][gc_centerview ][0] = KEY_END;
 	gamecontroldefault[gcs_fps][gc_jump       ][0] = KEY_SPACE;
-	gamecontroldefault[gcs_fps][gc_use        ][0] = KEY_LSHIFT;
+	gamecontroldefault[gcs_fps][gc_spin       ][0] = KEY_LSHIFT;
 	gamecontroldefault[gcs_fps][gc_fire       ][0] = KEY_RCTRL;
 	gamecontroldefault[gcs_fps][gc_fire       ][1] = KEY_MOUSE1+0;
 	gamecontroldefault[gcs_fps][gc_firenormal ][0] = 'c';
@@ -708,7 +708,7 @@ void G_DefineDefaultControls(void)
 	gamecontroldefault[gcs_platform][gc_turnright  ][0] = KEY_RIGHTARROW;
 	gamecontroldefault[gcs_platform][gc_centerview ][0] = KEY_END;
 	gamecontroldefault[gcs_platform][gc_jump       ][0] = KEY_SPACE;
-	gamecontroldefault[gcs_platform][gc_use        ][0] = KEY_LSHIFT;
+	gamecontroldefault[gcs_platform][gc_spin       ][0] = KEY_LSHIFT;
 	gamecontroldefault[gcs_platform][gc_fire       ][0] = 's';
 	gamecontroldefault[gcs_platform][gc_fire       ][1] = KEY_MOUSE1+0;
 	gamecontroldefault[gcs_platform][gc_firenormal ][0] = 'w';
@@ -743,7 +743,7 @@ void G_DefineDefaultControls(void)
 		gamecontroldefault[i][gc_weaponnext ][1] = KEY_JOY1+1; // B
 		gamecontroldefault[i][gc_weaponprev ][1] = KEY_JOY1+2; // X
 		gamecontroldefault[i][gc_tossflag   ][1] = KEY_JOY1+0; // A
-		gamecontroldefault[i][gc_use        ][1] = KEY_JOY1+4; // LB
+		gamecontroldefault[i][gc_spin       ][1] = KEY_JOY1+4; // LB
 		gamecontroldefault[i][gc_camtoggle  ][1] = KEY_HAT1+0; // D-Pad Up
 		gamecontroldefault[i][gc_camreset   ][1] = KEY_JOY1+3; // Y
 		gamecontroldefault[i][gc_centerview ][1] = KEY_JOY1+9; // Right Stick
@@ -758,7 +758,7 @@ void G_DefineDefaultControls(void)
 		gamecontrolbisdefault[i][gc_weaponnext][0] = KEY_2JOY1+1; // B
 		gamecontrolbisdefault[i][gc_weaponprev][0] = KEY_2JOY1+2; // X
 		gamecontrolbisdefault[i][gc_tossflag  ][0] = KEY_2JOY1+0; // A
-		gamecontrolbisdefault[i][gc_use       ][0] = KEY_2JOY1+4; // LB
+		gamecontrolbisdefault[i][gc_spin      ][0] = KEY_2JOY1+4; // LB
 		gamecontrolbisdefault[i][gc_camreset  ][0] = KEY_2JOY1+3; // Y
 		gamecontrolbisdefault[i][gc_centerview][0] = KEY_2JOY1+9; // Right Stick
 		gamecontrolbisdefault[i][gc_jump      ][0] = KEY_2JOY1+5; // RB
@@ -890,7 +890,7 @@ static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT
 
 	if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22
 		numctrl == gc_weaponnext || numctrl == gc_weaponprev || numctrl == gc_tossflag ||
-		numctrl == gc_use || numctrl == gc_camreset || numctrl == gc_jump ||
+		numctrl == gc_spin || numctrl == gc_camreset || numctrl == gc_jump ||
 		numctrl == gc_pause || numctrl == gc_systemmenu || numctrl == gc_camtoggle ||
 		numctrl == gc_screenshot || numctrl == gc_talkkey || numctrl == gc_scores ||
 		numctrl == gc_centerview
@@ -996,7 +996,9 @@ static void setcontrol(INT32 (*gc)[2])
 	INT32 player = ((void*)gc == (void*)&gamecontrolbis ? 1 : 0);
 	boolean nestedoverride = false;
 
-	namectrl = COM_Argv(1);
+	// Update me for 2.3
+	namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin";
+
 	for (numctrl = 0; numctrl < num_gamecontrols && stricmp(namectrl, gamecontrolname[numctrl]);
 		numctrl++)
 		;
diff --git a/src/g_input.h b/src/g_input.h
index a7484c7adba4be4ad6a996b60677a1135f471e22..ce38f6ba9d68a623b880361d868aeebdd18eb135 100644
--- a/src/g_input.h
+++ b/src/g_input.h
@@ -80,7 +80,7 @@ typedef enum
 	gc_fire,
 	gc_firenormal,
 	gc_tossflag,
-	gc_use,
+	gc_spin,
 	gc_camtoggle,
 	gc_camreset,
 	gc_lookup,
@@ -141,8 +141,8 @@ extern INT32 gamecontrolbisdefault[num_gamecontrolschemes][num_gamecontrols][2];
 #define num_gcl_camera 2
 #define num_gcl_movement_camera 6
 #define num_gcl_jump 1
-#define num_gcl_use 1
-#define num_gcl_jump_use 2
+#define num_gcl_spin 1
+#define num_gcl_jump_spin 2
 
 extern const INT32 gcl_tutorial_check[num_gcl_tutorial_check];
 extern const INT32 gcl_tutorial_used[num_gcl_tutorial_used];
@@ -151,8 +151,8 @@ extern const INT32 gcl_movement[num_gcl_movement];
 extern const INT32 gcl_camera[num_gcl_camera];
 extern const INT32 gcl_movement_camera[num_gcl_movement_camera];
 extern const INT32 gcl_jump[num_gcl_jump];
-extern const INT32 gcl_use[num_gcl_use];
-extern const INT32 gcl_jump_use[num_gcl_jump_use];
+extern const INT32 gcl_spin[num_gcl_spin];
+extern const INT32 gcl_jump_spin[num_gcl_jump_spin];
 
 // peace to my little coder fingers!
 // check a gamecontrol being active or not
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 631aa056b66dcdb78f90f9953236ecff83374dff..39c06fa0cdb3f51642e2750ad91457e1dfea3f41 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -110,12 +110,6 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
 			if (mipmap->colormap)
 				texel = mipmap->colormap[texel];
 
-			// If the mipmap is chromakeyed, check if the texel's color
-			// is equivalent to the chroma key's color index.
-			alpha = 0xff;
-			if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
-				alpha = 0x00;
-
 			// hope compiler will get this switch out of the loops (dreams...)
 			// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
 			// Alam: SRB2 uses Mingw, HUGS
@@ -513,11 +507,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
 
 #ifndef NO_PNG_LUMPS
 		if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
-			// Dummy variables.
-			INT32 pngwidth, pngheight;
-			realpatch = (softwarepatch_t *)Picture_PNGConvert(pdata, PICFMT_DOOMPATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0);
-		}
+			realpatch = (softwarepatch_t *)Picture_PNGConvert(pdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 #ifdef WALLFLATS
@@ -928,7 +918,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 #ifndef NO_PNG_LUMPS
 	else if (levelflat->type == LEVELFLAT_PNG)
 	{
-		INT32 pngwidth, pngheight;
+		INT32 pngwidth = 0, pngheight = 0;
 		GLMipmap_t *mipmap = levelflat->mipmap;
 		UINT8 *flat;
 		size_t size;
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 715c45ef3ea5d28da8d4b241fa38fdd960a2d3a4..a7f7acd22d21df314df0a3e7c41c63454bd3005f 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -132,6 +132,40 @@ typedef struct
 	FLOAT       t;            // t texture ordinate (t over w)
 } FOutVector;
 
+typedef struct vbo_vertex_s
+{
+	float x, y, z;
+	float u, v;
+	unsigned char r, g, b, a;
+} gl_skyvertex_t;
+
+typedef enum gl_skyloopmode_e
+{
+	HWD_SKYLOOP_FAN,
+	HWD_SKYLOOP_STRIP
+} gl_skyloopmode_t;
+
+typedef struct
+{
+	gl_skyloopmode_t mode;
+	int vertexcount;
+	int vertexindex;
+	boolean use_texture;
+} gl_skyloopdef_t;
+
+typedef struct
+{
+	unsigned int vbo;
+	int rows, columns;
+	int loopcount;
+
+	int detail, vertex_count;
+	int texture, width, height;
+	boolean rebuild; // VBO needs to be rebuilt
+
+	gl_skyloopdef_t *loops;
+	gl_skyvertex_t *data;
+} gl_sky_t;
 
 // ==========================================================================
 //                                                               RENDER MODES
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index cc1354909500d9b41f7aa213ff18a4590f47ade9..cc5569bd7334d920089111e08dd1a75b98bc4a81 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -37,7 +37,7 @@ EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
 EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
 EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags);
 EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, UINT32 *IndexArray);
-EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform);
+EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky);
 EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags);
 EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor);
 EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo);
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index a8644bb9a346d152c6a0cef99497b6baf2000aa7..e60645eb63e5e1fc977f698390b237e784781f84 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -1959,7 +1959,7 @@ static cliprange_t *   hw_newend;
 static cliprange_t     gl_solidsegs[MAXSEGS];
 
 // needs fix: walls are incorrectly clipped one column less
-static consvar_t cv_glclipwalls = {"gr_clipwalls", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_glclipwalls = CVAR_INIT ("gr_clipwalls", "Off", 0, CV_OnOff, NULL);
 
 static void printsolidsegs(void)
 {
@@ -5189,10 +5189,155 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 #endif
 
 // ==========================================================================
-//
+// Sky dome rendering, ported from PrBoom+
 // ==========================================================================
+
+static gl_sky_t gl_sky;
+
+static void HWR_SkyDomeVertex(gl_sky_t *sky, gl_skyvertex_t *vbo, int r, int c, signed char yflip, float delta, boolean foglayer)
+{
+	const float radians = (float)(M_PIl / 180.0f);
+	const float scale = 10000.0f;
+	const float maxSideAngle = 60.0f;
+
+	float topAngle = (c / (float)sky->columns * 360.0f);
+	float sideAngle = (maxSideAngle * (sky->rows - r) / sky->rows);
+	float height = (float)(sin(sideAngle * radians));
+	float realRadius = (float)(scale * cos(sideAngle * radians));
+	float x = (float)(realRadius * cos(topAngle * radians));
+	float y = (!yflip) ? scale * height : -scale * height;
+	float z = (float)(realRadius * sin(topAngle * radians));
+	float timesRepeat = (4 * (256.0f / sky->width));
+	if (fpclassify(timesRepeat) == FP_ZERO)
+		timesRepeat = 1.0f;
+
+	if (!foglayer)
+	{
+		vbo->r = 255;
+		vbo->g = 255;
+		vbo->b = 255;
+		vbo->a = (r == 0 ? 0 : 255);
+
+		// And the texture coordinates.
+		vbo->u = (-timesRepeat * c / (float)sky->columns);
+		if (!yflip)	// Flipped Y is for the lower hemisphere.
+			vbo->v = (r / (float)sky->rows) + 0.5f;
+		else
+			vbo->v = 1.0f + ((sky->rows - r) / (float)sky->rows) + 0.5f;
+	}
+
+	if (r != 4)
+		y += 300.0f;
+
+	// And finally the vertex.
+	vbo->x = x;
+	vbo->y = y + delta;
+	vbo->z = z;
+}
+
+// Clears the sky dome.
+void HWR_ClearSkyDome(void)
+{
+	gl_sky_t *sky = &gl_sky;
+
+	if (sky->loops)
+		free(sky->loops);
+	if (sky->data)
+		free(sky->data);
+
+	sky->loops = NULL;
+	sky->data = NULL;
+
+	sky->vbo = 0;
+	sky->rows = sky->columns = 0;
+	sky->loopcount = 0;
+
+	sky->detail = 0;
+	sky->texture = -1;
+	sky->width = sky->height = 0;
+
+	sky->rebuild = true;
+}
+
+void HWR_BuildSkyDome(void)
+{
+	int c, r;
+	signed char yflip;
+	int row_count = 4;
+	int col_count = 4;
+	float delta;
+
+	gl_sky_t *sky = &gl_sky;
+	gl_skyvertex_t *vertex_p;
+	texture_t *texture = textures[texturetranslation[skytexture]];
+
+	sky->detail = 16;
+	col_count *= sky->detail;
+
+	if ((sky->columns != col_count) || (sky->rows != row_count))
+		HWR_ClearSkyDome();
+
+	sky->columns = col_count;
+	sky->rows = row_count;
+	sky->vertex_count = 2 * sky->rows * (sky->columns * 2 + 2) + sky->columns * 2;
+
+	if (!sky->loops)
+		sky->loops = malloc((sky->rows * 2 + 2) * sizeof(sky->loops[0]));
+
+	// create vertex array
+	if (!sky->data)
+		sky->data = malloc(sky->vertex_count * sizeof(sky->data[0]));
+
+	sky->texture = texturetranslation[skytexture];
+	sky->width = texture->width;
+	sky->height = texture->height;
+
+	vertex_p = &sky->data[0];
+	sky->loopcount = 0;
+
+	for (yflip = 0; yflip < 2; yflip++)
+	{
+		sky->loops[sky->loopcount].mode = HWD_SKYLOOP_FAN;
+		sky->loops[sky->loopcount].vertexindex = vertex_p - &sky->data[0];
+		sky->loops[sky->loopcount].vertexcount = col_count;
+		sky->loops[sky->loopcount].use_texture = false;
+		sky->loopcount++;
+
+		delta = 0.0f;
+
+		for (c = 0; c < col_count; c++)
+		{
+			HWR_SkyDomeVertex(sky, vertex_p, 1, c, yflip, 0.0f, true);
+			vertex_p->r = 255;
+			vertex_p->g = 255;
+			vertex_p->b = 255;
+			vertex_p->a = 255;
+			vertex_p++;
+		}
+
+		delta = (yflip ? 5.0f : -5.0f) / 128.0f;
+
+		for (r = 0; r < row_count; r++)
+		{
+			sky->loops[sky->loopcount].mode = HWD_SKYLOOP_STRIP;
+			sky->loops[sky->loopcount].vertexindex = vertex_p - &sky->data[0];
+			sky->loops[sky->loopcount].vertexcount = 2 * col_count + 2;
+			sky->loops[sky->loopcount].use_texture = true;
+			sky->loopcount++;
+
+			for (c = 0; c <= col_count; c++)
+			{
+				HWR_SkyDomeVertex(sky, vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0), yflip, delta, false);
+				HWR_SkyDomeVertex(sky, vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0), yflip, delta, false);
+			}
+		}
+	}
+}
+
 static void HWR_DrawSkyBackground(player_t *player)
 {
+	HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated);
+
 	if (cv_glskydome.value)
 	{
 		FTransform dometransform;
@@ -5230,7 +5375,16 @@ static void HWR_DrawSkyBackground(player_t *player)
 		dometransform.splitscreen = splitscreen;
 
 		HWR_GetTexture(texturetranslation[skytexture]);
-		HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform);
+
+		if (gl_sky.texture != texturetranslation[skytexture])
+		{
+			HWR_ClearSkyDome();
+			HWR_BuildSkyDome();
+		}
+
+		HWD.pfnSetShader(7); // sky shader
+		HWD.pfnSetTransform(&dometransform);
+		HWD.pfnRenderSkyDome(&gl_sky);
 	}
 	else
 	{
@@ -5311,10 +5465,11 @@ static void HWR_DrawSkyBackground(player_t *player)
 			v[0].t = v[1].t -= ((float) angle / angleturn);
 		}
 
-		HWD.pfnSetShader(7); // sky shader
+		HWD.pfnUnSetShader();
 		HWD.pfnDrawPolygon(NULL, v, 4, 0);
-		HWD.pfnSetShader(0);
 	}
+
+	HWD.pfnSetShader(0);
 }
 
 
@@ -5841,34 +5996,32 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA
 	{0, NULL}};
 CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
 
-consvar_t cv_glshaders = {"gr_shaders", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_fovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL);
 
 #ifdef ALAM_LIGHTING
-consvar_t cv_gldynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glstaticlighting  = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glcoronasize = {"gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_gldynamiclighting = CVAR_INIT ("gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_glstaticlighting  = CVAR_INIT ("gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_glcoronas = CVAR_INIT ("gr_coronas", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL);
 #endif
 
-consvar_t cv_glmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glmodellighting = {"gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL);
+consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL);
 
-consvar_t cv_glshearing = {"gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL);
+consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_glskydome = CVAR_INIT ("gr_skydome", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL);
+consvar_t cv_glslopecontrast = CVAR_INIT ("gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL);
 
-consvar_t cv_glfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t,
-                             CV_glfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t,
-                             CV_glanisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_glfiltermode = CVAR_INIT ("gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange);
+consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, CV_glanisotropic_OnChange);
 
-consvar_t cv_glsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL);
 
-consvar_t cv_glbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL);
 
 static void CV_glfiltermode_OnChange(void)
 {
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index 780572a851ac53df8afcbfb4b42a15f69da23e43..e3c795b22436b4c23686f3eca82cf7cd535e75ba 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -31,6 +31,8 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height);
 void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight);
 void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
 void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
+void HWR_ClearSkyDome(void);
+void HWR_BuildSkyDome(void);
 void HWR_DrawViewBorder(INT32 clearlines);
 void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum);
 void HWR_InitTextureMapping(void);
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 057ef62c1accb4d221f5531569cad555be15bea3..d5c9cedaf75f4c2c5f8e6e2159d06c62739497b8 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1192,6 +1192,7 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t
 	return spr2;
 }
 
+// Adjust texture coords of model to fit into a patch's max_s and max_t
 static void adjustTextureCoords(model_t *model, patch_t *patch)
 {
 	int i;
@@ -1202,24 +1203,35 @@ static void adjustTextureCoords(model_t *model, patch_t *patch)
 		int j;
 		mesh_t *mesh = &model->meshes[i];
 		int numVertices;
-		float *uvPtr = mesh->uvs;
+		float *uvReadPtr = mesh->originaluvs;
+		float *uvWritePtr;
 
 		// i dont know if this is actually possible, just logical conclusion of structure in CreateModelVBOs
-		if (!mesh->frames && !mesh->tinyframes) return;
+		if (!mesh->frames && !mesh->tinyframes) continue;
 
 		if (mesh->frames) // again CreateModelVBO and CreateModelVBOTiny iterate like this so I'm gonna do that too
 			numVertices = mesh->numTriangles * 3;
 		else
 			numVertices = mesh->numVertices;
 
+		// if originaluvs points to uvs, we need to allocate new memory for adjusted uvs
+		// the old uvs are kept around for use in possible readjustments
+		if (mesh->uvs == mesh->originaluvs)
+			mesh->uvs = Z_Malloc(numVertices * 2 * sizeof(float), PU_STATIC, NULL);
+
+		uvWritePtr = mesh->uvs;
+
 		// fix uvs (texture coordinates) to take into account that the actual texture
 		// has empty space added until the next power of two
 		for (j = 0; j < numVertices; j++)
 		{
-			*uvPtr++ *= gpatch->max_s;
-			*uvPtr++ *= gpatch->max_t;
+			*uvWritePtr++ = *uvReadPtr++ * gpatch->max_s;
+			*uvWritePtr++ = *uvReadPtr++ * gpatch->max_t;
 		}
 	}
+	// Save the values we adjusted the uvs for
+	model->max_s = gpatch->max_s;
+	model->max_t = gpatch->max_t;
 }
 
 //
@@ -1243,6 +1255,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 	if (spr->precip)
 		return false;
 
+	// Lactozilla: Disallow certain models from rendering
+	if (!HWR_AllowModel(spr->mobj))
+		return false;
+
 	memset(&p, 0x00, sizeof(FTransform));
 
 	// MD2 colormap fix
@@ -1360,10 +1376,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			if (md2->model)
 			{
 				md2_printModelInfo(md2->model);
-				// if model uses sprite patch as texture, then
+				// If model uses sprite patch as texture, then
 				// adjust texture coordinates to take power of two textures into account
 				if (!gpatch || !hwrPatch->mipmap->format)
 					adjustTextureCoords(md2->model, spr->gpatch);
+				// note down the max_s and max_t that end up in the VBO
+				md2->model->vbo_max_s = md2->model->max_s;
+				md2->model->vbo_max_t = md2->model->max_t;
 				HWD.pfnCreateModelVBOs(md2->model);
 			}
 			else
@@ -1374,10 +1393,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			}
 		}
 
-		// Lactozilla: Disallow certain models from rendering
-		if (!HWR_AllowModel(spr->mobj))
-			return false;
-
 		//HWD.pfnSetBlend(blend); // This seems to actually break translucency?
 		finalscale = md2->scale;
 		//Hurdler: arf, I don't like that implementation at all... too much crappy
@@ -1417,9 +1432,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			// Translation or skin number found
 			HWR_GetBlendedTexture(gpatch, blendgpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color);
 		}
-		else
+		else // Sprite
 		{
-			// Sprite
+			// Check if sprite dimensions are different from previously used sprite.
+			// If so, uvs need to be readjusted.
+			// Comparing floats with the != operator here should be okay because they
+			// are just copies of glpatches' max_s and max_t values.
+			// Instead of the != operator, memcmp is used to avoid a compiler warning.
+			if (memcmp(&(hwrPatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 ||
+				memcmp(&(hwrPatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0)
+				adjustTextureCoords(md2->model, gpatch);
 			HWR_GetMappedPatch(spr->gpatch, spr->colormap);
 		}
 
diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c
index ac73f8acac4b577f1ca18bd077e8bba837f320d8..4ed03744bfe072db597c0e2d120fd72ccd77a6ca 100644
--- a/src/hardware/hw_model.c
+++ b/src/hardware/hw_model.c
@@ -221,6 +221,15 @@ model_t *LoadModel(const char *filename, int ztag)
 		material->shininess = 25.0f;
 	}
 
+	// Set originaluvs to point to uvs
+	for (i = 0; i < model->numMeshes; i++)
+		model->meshes[i].originaluvs = model->meshes[i].uvs;
+
+	model->max_s = 1.0;
+	model->max_t = 1.0;
+	model->vbo_max_s = 1.0;
+	model->vbo_max_t = 1.0;
+
 	return model;
 }
 
diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h
index 2a5240bdefbda6320fa2411b451a5bf86408124e..6b39eb24d90e9b27bc21704edceacdda15679efe 100644
--- a/src/hardware/hw_model.h
+++ b/src/hardware/hw_model.h
@@ -59,6 +59,11 @@ typedef struct mesh_s
 	int numTriangles;
 
 	float *uvs;
+	// if uv adjustment is needed, uvs is changed to point to adjusted ones and
+	// this one retains the originals
+	// note: this member has been added with the assumption that models are never freed.
+	// (UnloadModel is called by nobody at the time of writing.)
+	float *originaluvs;
 	float *lightuvs;
 
 	int numFrames;
@@ -99,6 +104,15 @@ typedef struct model_s
 	char *framenames;
 	boolean interpolate[256];
 	modelspr2frames_t *spr2frames;
+
+	// the max_s and max_t values that the uvs are currently adjusted to
+	// (if a sprite is used as a texture)
+	float max_s;
+	float max_t;
+	// These are the values that the uvs in the VBO have been adjusted to.
+	// If they are not same as max_s and max_t, then the VBO won't be used.
+	float vbo_max_s;
+	float vbo_max_t;
 } model_t;
 
 extern int numModels;
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index fbe65bc1718d4bbb4e957dc9b93b4b97c4ab0eb7..8b0e746b240767f030b92b8142dd59df91a556fd 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -95,6 +95,8 @@ static GLuint finalScreenTexture = 0;
 static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
 static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade);
 
+static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
+
 // shortcut for ((float)1/i)
 static const GLfloat byte2float[256] = {
 	0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f,
@@ -770,6 +772,18 @@ static INT32 shader_leveltime = 0;
 		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \
 	"}\0"
 
+//
+// Sky fragment shader
+// Modulates poly_color with gl_Color
+//
+
+#define GLSL_SKY_FRAGMENT_SHADER \
+	"uniform sampler2D tex;\n" \
+	"uniform vec4 poly_color;\n" \
+	"void main(void) {\n" \
+		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
+	"}\0"
+
 static const char *fragment_shaders[] = {
 	// Default fragment shader
 	GLSL_DEFAULT_FRAGMENT_SHADER,
@@ -793,10 +807,7 @@ static const char *fragment_shaders[] = {
 	GLSL_FOG_FRAGMENT_SHADER,
 
 	// Sky fragment shader
-	"uniform sampler2D tex;\n"
-	"void main(void) {\n"
-		"gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
-	"}\0",
+	GLSL_SKY_FRAGMENT_SHADER,
 
 	// Model fragment shader + diffuse lighting from above
 	GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER,
@@ -1964,6 +1975,14 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF
 		if (!shader->program)
 			return;
 
+		// Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f)
+		if (poly == NULL)
+			poly = &shader_defaultcolor;
+		if (tint == NULL)
+			tint = &shader_defaultcolor;
+		if (fade == NULL)
+			fade = &shader_defaultcolor;
+
 		#define UNIFORM_1(uniform, a, function) \
 			if (uniform != -1) \
 				function (uniform, a);
@@ -1984,12 +2003,14 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF
 		UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f);
 		UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f);
 		UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f);
+
 		if (Surface != NULL)
 		{
 			UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f);
 			UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f);
 			UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f);
 		}
+
 		UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)shader_leveltime) / TICRATE, pglUniform1f);
 
 		#undef UNIFORM_1
@@ -2144,233 +2165,83 @@ EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutV
 	// the DrawPolygon variant of this has some code about polyflags and wrapping here but havent noticed any problems from omitting it?
 }
 
-typedef struct vbo_vertex_s
-{
-	float x, y, z;
-	float u, v;
-	unsigned char r, g, b, a;
-} vbo_vertex_t;
-
-typedef struct
-{
-	int mode;
-	int vertexcount;
-	int vertexindex;
-	int use_texture;
-} GLSkyLoopDef;
-
-typedef struct
-{
-	unsigned int id;
-	int rows, columns;
-	int loopcount;
-	GLSkyLoopDef *loops;
-	vbo_vertex_t *data;
-} GLSkyVBO;
-
 static const boolean gl_ext_arb_vertex_buffer_object = true;
 
-#define NULL_VBO_VERTEX ((vbo_vertex_t*)NULL)
-#define sky_vbo_x (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->x : &vbo->data[0].x)
-#define sky_vbo_u (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->u : &vbo->data[0].u)
-#define sky_vbo_r (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->r : &vbo->data[0].r)
-
-// The texture offset to be applied to the texture coordinates in SkyVertex().
-static int rows, columns;
-static signed char yflip;
-static int texw, texh;
-static boolean foglayer;
-static float delta = 0.0f;
-
-static int gl_sky_detail = 16;
-
-static INT32 lasttex = -1;
-
-#define MAP_COEFF 128.0f
-
-static void SkyVertex(vbo_vertex_t *vbo, int r, int c)
-{
-	const float radians = (float)(M_PIl / 180.0f);
-	const float scale = 10000.0f;
-	const float maxSideAngle = 60.0f;
-
-	float topAngle = (c / (float)columns * 360.0f);
-	float sideAngle = (maxSideAngle * (rows - r) / rows);
-	float height = (float)(sin(sideAngle * radians));
-	float realRadius = (float)(scale * cos(sideAngle * radians));
-	float x = (float)(realRadius * cos(topAngle * radians));
-	float y = (!yflip) ? scale * height : -scale * height;
-	float z = (float)(realRadius * sin(topAngle * radians));
-	float timesRepeat = (4 * (256.0f / texw));
-	if (fpclassify(timesRepeat) == FP_ZERO)
-		timesRepeat = 1.0f;
-
-	if (!foglayer)
-	{
-		vbo->r = 255;
-		vbo->g = 255;
-		vbo->b = 255;
-		vbo->a = (r == 0 ? 0 : 255);
-
-		// And the texture coordinates.
-		vbo->u = (-timesRepeat * c / (float)columns);
-		if (!yflip)	// Flipped Y is for the lower hemisphere.
-			vbo->v = (r / (float)rows) + 0.5f;
-		else
-			vbo->v = 1.0f + ((rows - r) / (float)rows) + 0.5f;
-	}
-
-	if (r != 4)
-	{
-		y += 300.0f;
-	}
-
-	// And finally the vertex.
-	vbo->x = x;
-	vbo->y = y + delta;
-	vbo->z = z;
-}
-
-static GLSkyVBO sky_vbo;
-
-static void gld_BuildSky(int row_count, int col_count)
-{
-	int c, r;
-	vbo_vertex_t *vertex_p;
-	int vertex_count = 2 * row_count * (col_count * 2 + 2) + col_count * 2;
-
-	GLSkyVBO *vbo = &sky_vbo;
-
-	if ((vbo->columns != col_count) || (vbo->rows != row_count))
-	{
-		free(vbo->loops);
-		free(vbo->data);
-		memset(vbo, 0, sizeof(&vbo));
-	}
-
-	if (!vbo->data)
-	{
-		memset(vbo, 0, sizeof(&vbo));
-		vbo->loops = malloc((row_count * 2 + 2) * sizeof(vbo->loops[0]));
-		// create vertex array
-		vbo->data = malloc(vertex_count * sizeof(vbo->data[0]));
-	}
-
-	vbo->columns = col_count;
-	vbo->rows = row_count;
-
-	vertex_p = &vbo->data[0];
-	vbo->loopcount = 0;
-
-	for (yflip = 0; yflip < 2; yflip++)
-	{
-		vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_FAN;
-		vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0];
-		vbo->loops[vbo->loopcount].vertexcount = col_count;
-		vbo->loops[vbo->loopcount].use_texture = false;
-		vbo->loopcount++;
-
-		delta = 0.0f;
-		foglayer = true;
-		for (c = 0; c < col_count; c++)
-		{
-			SkyVertex(vertex_p, 1, c);
-			vertex_p->r = 255;
-			vertex_p->g = 255;
-			vertex_p->b = 255;
-			vertex_p->a = 255;
-			vertex_p++;
-		}
-		foglayer = false;
-
-		delta = (yflip ? 5.0f : -5.0f) / MAP_COEFF;
-
-		for (r = 0; r < row_count; r++)
-		{
-			vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_STRIP;
-			vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0];
-			vbo->loops[vbo->loopcount].vertexcount = 2 * col_count + 2;
-			vbo->loops[vbo->loopcount].use_texture = true;
-			vbo->loopcount++;
-
-			for (c = 0; c <= col_count; c++)
-			{
-				SkyVertex(vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0));
-				SkyVertex(vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0));
-			}
-		}
-	}
-}
+#define NULL_VBO_VERTEX ((gl_skyvertex_t*)NULL)
+#define sky_vbo_x (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->x : &sky->data[0].x)
+#define sky_vbo_u (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->u : &sky->data[0].u)
+#define sky_vbo_r (gl_ext_arb_vertex_buffer_object ? &NULL_VBO_VERTEX->r : &sky->data[0].r)
 
-//-----------------------------------------------------------------------------
-//
-//
-//
-//-----------------------------------------------------------------------------
-
-static void RenderDome(INT32 skytexture)
+EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky)
 {
 	int i, j;
-	int vbosize;
-	GLSkyVBO *vbo = &sky_vbo;
-
-	rows = 4;
-	columns = 4 * gl_sky_detail;
 
-	vbosize = 2 * rows * (columns * 2 + 2) + columns * 2;
+	Shader_Load(NULL, NULL, NULL, NULL);
 
 	// Build the sky dome! Yes!
-	if (lasttex != skytexture)
+	if (sky->rebuild)
 	{
 		// delete VBO when already exists
 		if (gl_ext_arb_vertex_buffer_object)
 		{
-			if (vbo->id)
-				pglDeleteBuffers(1, &vbo->id);
+			if (sky->vbo)
+				pglDeleteBuffers(1, &sky->vbo);
 		}
 
-		lasttex = skytexture;
-		gld_BuildSky(rows, columns);
-
 		if (gl_ext_arb_vertex_buffer_object)
 		{
 			// generate a new VBO and get the associated ID
-			pglGenBuffers(1, &vbo->id);
+			pglGenBuffers(1, &sky->vbo);
 
 			// bind VBO in order to use
-			pglBindBuffer(GL_ARRAY_BUFFER, vbo->id);
+			pglBindBuffer(GL_ARRAY_BUFFER, sky->vbo);
 
 			// upload data to VBO
-			pglBufferData(GL_ARRAY_BUFFER, vbosize * sizeof(vbo->data[0]), vbo->data, GL_STATIC_DRAW);
+			pglBufferData(GL_ARRAY_BUFFER, sky->vertex_count * sizeof(sky->data[0]), sky->data, GL_STATIC_DRAW);
 		}
+
+		sky->rebuild = false;
 	}
 
 	// bind VBO in order to use
 	if (gl_ext_arb_vertex_buffer_object)
-		pglBindBuffer(GL_ARRAY_BUFFER, vbo->id);
+		pglBindBuffer(GL_ARRAY_BUFFER, sky->vbo);
 
 	// activate and specify pointers to arrays
-	pglVertexPointer(3, GL_FLOAT, sizeof(vbo->data[0]), sky_vbo_x);
-	pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo->data[0]), sky_vbo_u);
-	pglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vbo->data[0]), sky_vbo_r);
+	pglVertexPointer(3, GL_FLOAT, sizeof(sky->data[0]), sky_vbo_x);
+	pglTexCoordPointer(2, GL_FLOAT, sizeof(sky->data[0]), sky_vbo_u);
+	pglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(sky->data[0]), sky_vbo_r);
 
 	// activate color arrays
 	pglEnableClientState(GL_COLOR_ARRAY);
 
 	// set transforms
-	pglScalef(1.0f, (float)texh / 230.0f, 1.0f);
+	pglScalef(1.0f, (float)sky->height / 200.0f, 1.0f);
 	pglRotatef(270.0f, 0.0f, 1.0f, 0.0f);
 
 	for (j = 0; j < 2; j++)
 	{
-		for (i = 0; i < vbo->loopcount; i++)
+		for (i = 0; i < sky->loopcount; i++)
 		{
-			GLSkyLoopDef *loop = &vbo->loops[i];
+			gl_skyloopdef_t *loop = &sky->loops[i];
+			unsigned int mode = 0;
 
 			if (j == 0 ? loop->use_texture : !loop->use_texture)
 				continue;
 
-			pglDrawArrays(loop->mode, loop->vertexindex, loop->vertexcount);
+			switch (loop->mode)
+			{
+				case HWD_SKYLOOP_FAN:
+					mode = GL_TRIANGLE_FAN;
+					break;
+				case HWD_SKYLOOP_STRIP:
+					mode = GL_TRIANGLE_STRIP;
+					break;
+				default:
+					continue;
+			}
+
+			pglDrawArrays(mode, loop->vertexindex, loop->vertexcount);
 		}
 	}
 
@@ -2385,16 +2256,6 @@ static void RenderDome(INT32 skytexture)
 	pglDisableClientState(GL_COLOR_ARRAY);
 }
 
-EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform)
-{
-	SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated);
-	SetTransform(&transform);
-	texw = texture_width;
-	texh = texture_height;
-	RenderDome(tex);
-	SetBlend(0);
-}
-
 // ==========================================================================
 //
 // ==========================================================================
@@ -2683,6 +2544,8 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 
 	boolean useTinyFrames;
 
+	boolean useVBO = true;
+
 	int i;
 
 	// Because otherwise, scaling the screen negatively vertically breaks the lighting
@@ -2826,6 +2689,15 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 	if (useTinyFrames)
 		pglScalef(1 / 64.0f, 1 / 64.0f, 1 / 64.0f);
 
+	// Don't use the VBO if it does not have the correct texture coordinates.
+	// (Can happen when model uses a sprite as a texture and the sprite changes)
+	// Comparing floats with the != operator here should be okay because they
+	// are just copies of glpatches' max_s and max_t values.
+	// Instead of the != operator, memcmp is used to avoid a compiler warning.
+	if (memcmp(&(model->vbo_max_s), &(model->max_s), sizeof(model->max_s)) != 0 ||
+		memcmp(&(model->vbo_max_t), &(model->max_t), sizeof(model->max_t)) != 0)
+		useVBO = false;
+
 	pglEnableClientState(GL_NORMAL_ARRAY);
 
 	for (i = 0; i < model->numMeshes; i++)
@@ -2842,13 +2714,23 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 
 			if (!nextframe || fpclassify(pol) == FP_ZERO)
 			{
-				pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
-				pglVertexPointer(3, GL_SHORT, sizeof(vbotiny_t), BUFFER_OFFSET(0));
-				pglNormalPointer(GL_BYTE, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short)*3));
-				pglTexCoordPointer(2, GL_FLOAT, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short) * 3 + sizeof(char) * 6));
+				if (useVBO)
+				{
+					pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
+					pglVertexPointer(3, GL_SHORT, sizeof(vbotiny_t), BUFFER_OFFSET(0));
+					pglNormalPointer(GL_BYTE, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short)*3));
+					pglTexCoordPointer(2, GL_FLOAT, sizeof(vbotiny_t), BUFFER_OFFSET(sizeof(short) * 3 + sizeof(char) * 6));
 
-				pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
-				pglBindBuffer(GL_ARRAY_BUFFER, 0);
+					pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
+					pglBindBuffer(GL_ARRAY_BUFFER, 0);
+				}
+				else
+				{
+					pglVertexPointer(3, GL_SHORT, 0, frame->vertices);
+					pglNormalPointer(GL_BYTE, 0, frame->normals);
+					pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
+					pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
+				}
 			}
 			else
 			{
@@ -2884,21 +2766,25 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 
 			if (!nextframe || fpclassify(pol) == FP_ZERO)
 			{
-				// Zoom! Take advantage of just shoving the entire arrays to the GPU.
-/*				pglVertexPointer(3, GL_FLOAT, 0, frame->vertices);
-				pglNormalPointer(GL_FLOAT, 0, frame->normals);
-				pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
-				pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);*/
-
-				pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
-				pglVertexPointer(3, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(0));
-				pglNormalPointer(GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 3));
-				pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 6));
-
-				pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);
-				// No tinyframes, no mesh indices
-				//pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
-				pglBindBuffer(GL_ARRAY_BUFFER, 0);
+				if (useVBO)
+				{
+					pglBindBuffer(GL_ARRAY_BUFFER, frame->vboID);
+					pglVertexPointer(3, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(0));
+					pglNormalPointer(GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 3));
+					pglTexCoordPointer(2, GL_FLOAT, sizeof(vbo64_t), BUFFER_OFFSET(sizeof(float) * 6));
+
+					pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);
+					// No tinyframes, no mesh indices
+					//pglDrawElements(GL_TRIANGLES, mesh->numTriangles * 3, GL_UNSIGNED_SHORT, mesh->indices);
+					pglBindBuffer(GL_ARRAY_BUFFER, 0);
+				}
+				else
+				{
+					pglVertexPointer(3, GL_FLOAT, 0, frame->vertices);
+					pglNormalPointer(GL_FLOAT, 0, frame->normals);
+					pglTexCoordPointer(2, GL_FLOAT, 0, mesh->uvs);
+					pglDrawArrays(GL_TRIANGLES, 0, mesh->numTriangles * 3);
+				}
 			}
 			else
 			{
diff --git a/src/http-mserv.c b/src/http-mserv.c
new file mode 100644
index 0000000000000000000000000000000000000000..7c7d04495cd8f5641bd7c6f236c47bd0eb344c64
--- /dev/null
+++ b/src/http-mserv.c
@@ -0,0 +1,691 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 2020 by James R.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+// \brief HTTP based master server
+
+/*
+Documentation available here.
+
+                     <http://mb.srb2.org/MS/tools/api/v1/>
+*/
+
+#ifdef HAVE_CURL
+#include <curl/curl.h>
+#endif
+
+#include "doomdef.h"
+#include "d_clisrv.h"
+#include "command.h"
+#include "m_argv.h"
+#include "m_menu.h"
+#include "mserv.h"
+#include "i_tcp.h"/* for current_port */
+#include "i_threads.h"
+
+/* reasonable default I guess?? */
+#define DEFAULT_BUFFER_SIZE (4096)
+
+/* I just stop myself from making macros anymore. */
+#define Blame( ... ) \
+	CONS_Printf("\x85" __VA_ARGS__)
+
+static void MasterServer_Debug_OnChange (void);
+
+consvar_t cv_masterserver_timeout = CVAR_INIT
+(
+		"masterserver_timeout", "5", CV_SAVE, CV_Unsigned,
+		NULL
+);
+
+consvar_t cv_masterserver_debug = CVAR_INIT
+(
+	"masterserver_debug", "Off", CV_SAVE|CV_CALL, CV_OnOff,
+	MasterServer_Debug_OnChange
+);
+
+consvar_t cv_masterserver_token = CVAR_INIT
+(
+		"masterserver_token", "", CV_SAVE, NULL,
+		NULL
+);
+
+#ifdef MASTERSERVER
+
+static int hms_started;
+
+static char *hms_api;
+#ifdef HAVE_THREADS
+static I_mutex hms_api_mutex;
+#endif
+
+static char *hms_server_token;
+
+struct HMS_buffer
+{
+	CURL *curl;
+	char *buffer;
+	int   needle;
+	int    end;
+};
+
+static void
+Contact_error (void)
+{
+	CONS_Alert(CONS_ERROR,
+			"There was a problem contacting the master server...\n"
+	);
+}
+
+static size_t
+HMS_on_read (char *s, size_t _1, size_t n, void *userdata)
+{
+	struct HMS_buffer *buffer;
+	size_t blocks;
+
+	(void)_1;
+
+	buffer = userdata;
+
+	if (n >= (size_t)( buffer->end - buffer->needle ))
+	{
+		/* resize to next multiple of buffer size */
+		blocks = ( n / DEFAULT_BUFFER_SIZE + 1 );
+		buffer->end += ( blocks * DEFAULT_BUFFER_SIZE );
+
+		buffer->buffer = realloc(buffer->buffer, buffer->end);
+	}
+
+	memcpy(&buffer->buffer[buffer->needle], s, n);
+	buffer->needle += n;
+
+	return n;
+}
+
+static struct HMS_buffer *
+HMS_connect (const char *format, ...)
+{
+	va_list ap;
+	CURL *curl;
+	char *url;
+	char *quack_token;
+	size_t seek;
+	size_t token_length;
+	struct HMS_buffer *buffer;
+
+	if (! hms_started)
+	{
+		if (curl_global_init(CURL_GLOBAL_ALL) != 0)
+		{
+			Contact_error();
+			Blame("From curl_global_init.\n");
+			return NULL;
+		}
+		else
+		{
+			atexit(curl_global_cleanup);
+			hms_started = 1;
+		}
+	}
+
+	curl = curl_easy_init();
+
+	if (! curl)
+	{
+		Contact_error();
+		Blame("From curl_easy_init.\n");
+		return NULL;
+	}
+
+	if (cv_masterserver_token.string[0])
+	{
+		quack_token = curl_easy_escape(curl, cv_masterserver_token.string, 0);
+		token_length = ( sizeof "?token="-1 )+ strlen(quack_token);
+	}
+	else
+	{
+		quack_token = NULL;
+		token_length = 0;
+	}
+
+#ifdef HAVE_THREADS
+	I_lock_mutex(&hms_api_mutex);
+#endif
+
+	seek = strlen(hms_api) + 1;/* + '/' */
+
+	va_start (ap, format);
+	url = malloc(seek + vsnprintf(0, 0, format, ap) + token_length + 1);
+	va_end (ap);
+
+	sprintf(url, "%s/", hms_api);
+
+#ifdef HAVE_THREADS
+	I_unlock_mutex(hms_api_mutex);
+#endif
+
+	va_start (ap, format);
+	seek += vsprintf(&url[seek], format, ap);
+	va_end (ap);
+
+	if (quack_token)
+		sprintf(&url[seek], "?token=%s", quack_token);
+
+	CONS_Printf("HMS: connecting '%s'...\n", url);
+
+	buffer = malloc(sizeof *buffer);
+	buffer->curl = curl;
+	buffer->end = DEFAULT_BUFFER_SIZE;
+	buffer->buffer = malloc(buffer->end);
+	buffer->needle = 0;
+
+	if (cv_masterserver_debug.value)
+	{
+		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+		curl_easy_setopt(curl, CURLOPT_STDERR, logstream);
+	}
+
+	if (M_CheckParm("-bindaddr") && M_IsNextParm())
+	{
+		curl_easy_setopt(curl, CURLOPT_INTERFACE, M_GetNextParm());
+	}
+
+	curl_easy_setopt(curl, CURLOPT_URL, url);
+	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+	curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+
+	curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read);
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
+
+	curl_free(quack_token);
+	free(url);
+
+	return buffer;
+}
+
+static int
+HMS_do (struct HMS_buffer *buffer)
+{
+	CURLcode cc;
+	long status;
+
+	char *p;
+
+	cc = curl_easy_perform(buffer->curl);
+
+	if (cc != CURLE_OK)
+	{
+		Contact_error();
+		Blame(
+				"From curl_easy_perform: %s\n",
+				curl_easy_strerror(cc)
+		);
+		return 0;
+	}
+
+	buffer->buffer[buffer->needle] = '\0';
+
+	curl_easy_getinfo(buffer->curl, CURLINFO_RESPONSE_CODE, &status);
+
+	if (status != 200)
+	{
+		p = strchr(buffer->buffer, '\n');
+
+		if (p)
+			*p = '\0';
+
+		Contact_error();
+		Blame(
+				"Master server error %ld: %s%s\n",
+				status,
+				buffer->buffer,
+				( (p) ? "" : " (malformed)" )
+		);
+
+		return 0;
+	}
+	else
+		return 1;
+}
+
+static void
+HMS_end (struct HMS_buffer *buffer)
+{
+	curl_easy_cleanup(buffer->curl);
+	free(buffer->buffer);
+	free(buffer);
+}
+
+int
+HMS_fetch_rooms (int joining, int query_id)
+{
+	struct HMS_buffer *hms;
+	int ok;
+
+	int doing_shit;
+
+	char *id;
+	char *title;
+	char *room_motd;
+
+	int id_no;
+
+	char *p;
+	char *end;
+
+	int i;
+
+	(void)query_id;
+
+	hms = HMS_connect("rooms");
+
+	if (! hms)
+		return 0;
+
+	if (HMS_do(hms))
+	{
+		doing_shit = 1;
+
+		p = hms->buffer;
+
+		for (i = 0; i < NUM_LIST_ROOMS && ( end = strstr(p, "\n\n\n") );)
+		{
+			*end = '\0';
+
+			id    = strtok(p, "\n");
+			title = strtok(0, "\n");
+			room_motd = strtok(0, "");
+
+			if (id && title && room_motd)
+			{
+				id_no = atoi(id);
+
+				/*
+				Don't show the 'All' room if hosting. And it's a hack like this
+				because I'm way too lazy to add another feature to the MS.
+				*/
+				if (joining || id_no != 0)
+				{
+#ifdef HAVE_THREADS
+					I_lock_mutex(&ms_QueryId_mutex);
+					{
+						if (query_id != ms_QueryId)
+							doing_shit = 0;
+					}
+					I_unlock_mutex(ms_QueryId_mutex);
+
+					if (! doing_shit)
+						break;
+#endif
+
+					room_list[i].header.buffer[0] = 1;
+
+					room_list[i].id = id_no;
+					strlcpy(room_list[i].name, title, sizeof room_list[i].name);
+					strlcpy(room_list[i].motd, room_motd, sizeof room_list[i].motd);
+
+					i++;
+				}
+
+				p = ( end + 3 );/* skip the three linefeeds */
+			}
+			else
+				break;
+		}
+
+		if (doing_shit)
+			room_list[i].header.buffer[0] = 0;
+
+		ok = 1;
+
+		if (doing_shit)
+		{
+#ifdef HAVE_THREADS
+			I_lock_mutex(&m_menu_mutex);
+#endif
+			{
+				for (i = 0; room_list[i].header.buffer[0]; i++)
+				{
+					if(*room_list[i].name != '\0')
+					{
+						MP_RoomMenu[i+1].text = room_list[i].name;
+						roomIds[i] = room_list[i].id;
+						MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
+					}
+				}
+			}
+#ifdef HAVE_THREADS
+			I_unlock_mutex(m_menu_mutex);
+#endif
+		}
+	}
+	else
+		ok = 0;
+
+	HMS_end(hms);
+
+	return ok;
+}
+
+int
+HMS_register (void)
+{
+	struct HMS_buffer *hms;
+	int ok;
+
+	char post[256];
+
+	char *title;
+
+	hms = HMS_connect("rooms/%d/register", ms_RoomId);
+
+	if (! hms)
+		return 0;
+
+	title = curl_easy_escape(hms->curl, cv_servername.string, 0);
+
+	snprintf(post, sizeof post,
+			"port=%d&"
+			"title=%s&"
+			"version=%s",
+
+			current_port,
+
+			title,
+
+			SRB2VERSION
+	);
+
+	curl_free(title);
+
+	curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
+
+	ok = HMS_do(hms);
+
+	if (ok)
+	{
+		hms_server_token = strdup(strtok(hms->buffer, "\n"));
+	}
+
+	HMS_end(hms);
+
+	return ok;
+}
+
+int
+HMS_unlist (void)
+{
+	struct HMS_buffer *hms;
+	int ok;
+
+	hms = HMS_connect("servers/%s/unlist", hms_server_token);
+
+	if (! hms)
+		return 0;
+
+	curl_easy_setopt(hms->curl, CURLOPT_CUSTOMREQUEST, "POST");
+
+	ok = HMS_do(hms);
+	HMS_end(hms);
+
+	free(hms_server_token);
+
+	return ok;
+}
+
+int
+HMS_update (void)
+{
+	struct HMS_buffer *hms;
+	int ok;
+
+	char post[256];
+
+	char *title;
+
+	hms = HMS_connect("servers/%s/update", hms_server_token);
+
+	if (! hms)
+		return 0;
+
+	title = curl_easy_escape(hms->curl, cv_servername.string, 0);
+
+	snprintf(post, sizeof post,
+			"title=%s",
+			title
+	);
+
+	curl_free(title);
+
+	curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
+
+	ok = HMS_do(hms);
+	HMS_end(hms);
+
+	return ok;
+}
+
+void
+HMS_list_servers (void)
+{
+	struct HMS_buffer *hms;
+
+	char *list;
+	char *p;
+
+	hms = HMS_connect("servers");
+
+	if (! hms)
+		return;
+
+	if (HMS_do(hms))
+	{
+		list = curl_easy_unescape(hms->curl, hms->buffer, 0, NULL);
+
+		p = strtok(list, "\n");
+
+		while (p != NULL)
+		{
+			CONS_Printf("\x80%s\n", p);
+			p = strtok(NULL, "\n");
+		}
+
+		curl_free(list);
+	}
+
+	HMS_end(hms);
+}
+
+msg_server_t *
+HMS_fetch_servers (msg_server_t *list, int room_number, int query_id)
+{
+	struct HMS_buffer *hms;
+
+	int doing_shit;
+
+	char local_version[9];
+
+	char *room;
+
+	char *address;
+	char *port;
+	char *title;
+	char *version;
+
+	char *end;
+	char *section_end;
+	char *p;
+
+	int i;
+
+	(void)query_id;
+
+	if (room_number > 0)
+	{
+		hms = HMS_connect("rooms/%d/servers", room_number);
+	}
+	else
+		hms = HMS_connect("servers");
+
+	if (! hms)
+		return NULL;
+
+	if (HMS_do(hms))
+	{
+		doing_shit = 1;
+
+		snprintf(local_version, sizeof local_version,
+				"%s",
+				SRB2VERSION
+		);
+
+		p = hms->buffer;
+		i = 0;
+
+		do
+		{
+			section_end = strstr(p, "\n\n");
+
+			room = strtok(p, "\n");
+
+			p = strtok(0, "");
+
+			if (! p)
+				break;
+
+			while (i < MAXSERVERLIST && ( end = strchr(p, '\n') ))
+			{
+				*end = '\0';
+
+				address = strtok(p, " ");
+				port    = strtok(0, " ");
+				title   = strtok(0, " ");
+				version = strtok(0, "");
+
+				if (address && port && title && version)
+				{
+#ifdef HAVE_THREADS
+					I_lock_mutex(&ms_QueryId_mutex);
+					{
+						if (query_id != ms_QueryId)
+							doing_shit = 0;
+					}
+					I_unlock_mutex(ms_QueryId_mutex);
+
+					if (! doing_shit)
+						break;
+#endif
+
+					if (strcmp(version, local_version) == 0)
+					{
+						strlcpy(list[i].ip,      address, sizeof list[i].ip);
+						strlcpy(list[i].port,    port,    sizeof list[i].port);
+						strlcpy(list[i].name,    title,   sizeof list[i].name);
+						strlcpy(list[i].version, version, sizeof list[i].version);
+
+						list[i].room = atoi(room);
+
+						list[i].header.buffer[0] = 1;
+
+						i++;
+					}
+
+					if (end == section_end)/* end of list for this room */
+						break;
+					else
+						p = ( end + 1 );/* skip server delimiter */
+				}
+				else
+				{
+					section_end = 0;/* malformed so quit the parsing */
+					break;
+				}
+			}
+
+			if (! doing_shit)
+				break;
+
+			p = ( section_end + 2 );
+		}
+		while (section_end) ;
+
+		if (doing_shit)
+			list[i].header.buffer[0] = 0;
+	}
+	else
+		list = NULL;
+
+	HMS_end(hms);
+
+	return list;
+}
+
+int
+HMS_compare_mod_version (char *buffer, size_t buffer_size)
+{
+	struct HMS_buffer *hms;
+	int ok;
+
+	char *version;
+	char *version_name;
+
+	hms = HMS_connect("versions/%d", MODID);
+
+	if (! hms)
+		return 0;
+
+	ok = 0;
+
+	if (HMS_do(hms))
+	{
+		version      = strtok(hms->buffer, " ");
+		version_name = strtok(0, "\n");
+
+		if (version && version_name)
+		{
+			if (atoi(version) != MODVERSION)
+			{
+				strlcpy(buffer, version_name, buffer_size);
+				ok = 1;
+			}
+			else
+				ok = -1;
+		}
+	}
+
+	HMS_end(hms);
+
+	return ok;
+}
+
+void
+HMS_set_api (char *api)
+{
+#ifdef HAVE_THREADS
+	I_lock_mutex(&hms_api_mutex);
+#endif
+	{
+		free(hms_api);
+		hms_api = api;
+	}
+#ifdef HAVE_THREADS
+	I_unlock_mutex(hms_api_mutex);
+#endif
+}
+
+#endif/*MASTERSERVER*/
+
+static void
+MasterServer_Debug_OnChange (void)
+{
+#ifdef MASTERSERVER
+	/* TODO: change to 'latest-log.txt' for log files revision. */
+	if (cv_masterserver_debug.value)
+		CONS_Printf("Master server debug messages will appear in log.txt\n");
+#endif
+}
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index ff9f274fcd70af58c9886394b1c0283f31abd52a..72fb9272d441135456286f908da9ba7e2ff9dc98 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -330,8 +330,6 @@ void HU_Init(void)
 
 	// set shift translation table
 	shiftxform = english_shiftxform;
-
-	HU_LoadGraphics();
 }
 
 static inline void HU_Stop(void)
@@ -1466,7 +1464,7 @@ static void HU_drawMiniChat(void)
 				if (cv_chatbacktint.value) // on request of wolfy
 					V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
 
-				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, !cv_allcaps.value, colormap);
+				V_DrawChatCharacter(x + dx + 2, y+dy, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap);
 			}
 
 			dx += charwidth;
@@ -1559,7 +1557,7 @@ static void HU_drawChatLog(INT32 offset)
 			else
 			{
 				if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
-					V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, !cv_allcaps.value, colormap);
+					V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j++] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
 				else
 					j++; // don't forget to increment this or we'll get stuck in the limbo.
 			}
@@ -1659,7 +1657,7 @@ static void HU_DrawChat(void)
 			++i;
 		else
 		{
-			V_DrawChatCharacter(chatx + c + 2, y, talk[i] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|cflag, !cv_allcaps.value, V_GetStringColormap(talk[i]|cflag));
+			V_DrawChatCharacter(chatx + c + 2, y, talk[i] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|cflag, true, V_GetStringColormap(talk[i]|cflag));
 			i++;
 		}
 
@@ -1677,7 +1675,7 @@ static void HU_DrawChat(void)
 	typelines = 1;
 
 	if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
-		V_DrawChatCharacter(chatx + 2 + c, y+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL);
+		V_DrawChatCharacter(chatx + 2 + c, y+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, true, NULL);
 
 	while (w_chat[i])
 	{
@@ -1687,7 +1685,7 @@ static void HU_DrawChat(void)
 			INT32 cursorx = (c+charwidth < boxw-charwidth) ? (chatx + 2 + c+charwidth) : (chatx+1); // we may have to go down.
 			INT32 cursory = (cursorx != chatx+1) ? (y) : (y+charheight);
 			if (hu_tick < 4)
-				V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL);
+				V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, true, NULL);
 
 			if (cursorx == chatx+1 && saylen == i) // a weirdo hack
 			{
@@ -1700,7 +1698,7 @@ static void HU_DrawChat(void)
 		if (w_chat[i] < HU_FONTSTART)
 			++i;
 		else
-			V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, !cv_allcaps.value, NULL);
+			V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, true, NULL);
 
 		c += charwidth;
 		if (c > boxw-(charwidth*2) && !skippedline)
@@ -1825,7 +1823,7 @@ static void HU_DrawChat_Old(void)
 	}
 
 	if ((strlen(w_chat) == 0 || c_input == 0) && hu_tick < 4)
-		V_DrawCharacter(HU_INPUTX+c, y+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, !cv_allcaps.value);
+		V_DrawCharacter(HU_INPUTX+c, y+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
 
 	i = 0;
 	while (w_chat[i])
@@ -1835,7 +1833,7 @@ static void HU_DrawChat_Old(void)
 		{
 			INT32 cursorx = (HU_INPUTX+c+charwidth < vid.width) ? (HU_INPUTX + c + charwidth) : (HU_INPUTX); // we may have to go down.
 			INT32 cursory = (cursorx != HU_INPUTX) ? (y) : (y+charheight);
-			V_DrawCharacter(cursorx, cursory+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, !cv_allcaps.value);
+			V_DrawCharacter(cursorx, cursory+2*con_scalefactor, '_' |cv_constextsize.value | V_NOSCALESTART|t, true);
 		}
 
 		//Hurdler: isn't it better like that?
diff --git a/src/i_sound.h b/src/i_sound.h
index 4bd05d23442322d3a4ee2500f4c2c62e942b33d0..a2249a10273fa48c95650a75fa692b84d4de37d8 100644
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -9,7 +9,7 @@
 // See the 'LICENSE' file for more details.
 //-----------------------------------------------------------------------------
 /// \file  i_sound.h
-/// \brief System interface, sound, music and CD
+/// \brief System interface, sound, music
 
 #ifndef __I_SOUND__
 #define __I_SOUND__
@@ -241,53 +241,4 @@ boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
 boolean I_FadeOutStopSong(UINT32 ms);
 boolean I_FadeInPlaySong(UINT32 ms, boolean looping);
 
-/// ------------------------
-//  CD MUSIC I/O
-/// ------------------------
-
-/**	\brief  cd music interface
-*/
-extern UINT8 cdaudio_started;
-
-/**	\brief Startup the CD system
-*/
-void I_InitCD(void);
-
-/**	\brief Stop the CD playback
-*/
-void I_StopCD(void);
-
-/**	\brief Pause the CD playback
-*/
-void I_PauseCD(void);
-
-/**	\brief Resume the CD playback
-*/
-void I_ResumeCD(void);
-
-/**	\brief Shutdown the CD system
-*/
-void I_ShutdownCD(void);
-
-/**	\brief Update the CD info
-*/
-void I_UpdateCD(void);
-
-/**	\brief	The I_PlayCD function
-
-	\param	track	CD track number
-	\param	looping	if true, loop the track
-
-	\return	void
-*/
-void I_PlayCD(UINT8 track, UINT8 looping);
-
-/**	\brief	The I_SetVolumeCD function
-
-	\param	volume	volume level to set at
-
-	\return	return 0 on failure
-*/
-boolean I_SetVolumeCD(INT32 volume);
-
 #endif
diff --git a/src/i_threads.h b/src/i_threads.h
new file mode 100644
index 0000000000000000000000000000000000000000..ecb9fce6715f3b8c40cc2bd37a0b3caa0d07101b
--- /dev/null
+++ b/src/i_threads.h
@@ -0,0 +1,39 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 2020 by James R.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  i_threads.h
+/// \brief Multithreading abstraction
+
+#ifdef HAVE_THREADS
+
+#ifndef I_THREADS_H
+#define I_THREADS_H
+
+typedef void (*I_thread_fn)(void *userdata);
+
+typedef void * I_mutex;
+typedef void * I_cond;
+
+void      I_start_threads (void);
+void      I_stop_threads  (void);
+
+void      I_spawn_thread (const char *name, I_thread_fn, void *userdata);
+
+/* check in your thread whether to return early */
+int       I_thread_is_stopped (void);
+
+void      I_lock_mutex      (I_mutex *);
+void      I_unlock_mutex    (I_mutex);
+
+void      I_hold_cond       (I_cond *, I_mutex);
+
+void      I_wake_one_cond   (I_cond *);
+void      I_wake_all_cond   (I_cond *);
+
+#endif/*I_THREADS_H*/
+#endif/*HAVE_THREADS*/
diff --git a/src/info.c b/src/info.c
index fccd1b2693d62926a2e19a4d9524349f79ae2056..cb5fb0889e2830313f1e54bb0350b95da3c52f8a 100644
--- a/src/info.c
+++ b/src/info.c
@@ -5139,7 +5139,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOCLIP|MF_SPECIAL, // flags
+		MF_SPECIAL,     // flags
 		S_NULL          // raisestate
 	},
 
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 6b25e32ea5e1746536b31111cf9eea749d42c453..d74af421459b0011f5e060ec1c040c9a58314a9c 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -32,9 +32,12 @@
 #include "lua_script.h"
 #include "lua_libs.h"
 #include "lua_hud.h" // hud_running errors
+#include "lua_hook.h" // hook_cmd_running errors
 
 #define NOHUD if (hud_running)\
-return luaL_error(L, "HUD rendering code should not call this function!");
+return luaL_error(L, "HUD rendering code should not call this function!");\
+else if (hook_cmd_running)\
+return luaL_error(L, "CMD building code should not call this function!");
 
 boolean luaL_checkboolean(lua_State *L, int narg) {
 	luaL_checktype(L, narg, LUA_TBOOLEAN);
@@ -910,44 +913,52 @@ static int lib_pMaceRotate(lua_State *L)
 static int lib_pRailThinker(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	mobj_t *ptmthing = tmthing;
 	NOHUD
 	INLEVEL
 	if (!mobj)
 		return LUA_ErrInvalid(L, "mobj_t");
 	lua_pushboolean(L, P_RailThinker(mobj));
+	P_SetTarget(&tmthing, ptmthing);
 	return 1;
 }
 
 static int lib_pXYMovement(lua_State *L)
 {
 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	mobj_t *ptmthing = tmthing;
 	NOHUD
 	INLEVEL
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	P_XYMovement(actor);
+	P_SetTarget(&tmthing, ptmthing);
 	return 0;
 }
 
 static int lib_pRingXYMovement(lua_State *L)
 {
 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	mobj_t *ptmthing = tmthing;
 	NOHUD
 	INLEVEL
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	P_RingXYMovement(actor);
+	P_SetTarget(&tmthing, ptmthing);
 	return 0;
 }
 
 static int lib_pSceneryXYMovement(lua_State *L)
 {
 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	mobj_t *ptmthing = tmthing;
 	NOHUD
 	INLEVEL
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	P_SceneryXYMovement(actor);
+	P_SetTarget(&tmthing, ptmthing);
 	return 0;
 }
 
@@ -959,6 +970,7 @@ static int lib_pZMovement(lua_State *L)
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	lua_pushboolean(L, P_ZMovement(actor));
+	P_CheckPosition(actor, actor->x, actor->y);
 	return 1;
 }
 
@@ -970,6 +982,7 @@ static int lib_pRingZMovement(lua_State *L)
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	P_RingZMovement(actor);
+	P_CheckPosition(actor, actor->x, actor->y);
 	return 0;
 }
 
@@ -981,6 +994,7 @@ static int lib_pSceneryZMovement(lua_State *L)
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	lua_pushboolean(L, P_SceneryZMovement(actor));
+	P_CheckPosition(actor, actor->x, actor->y);
 	return 1;
 }
 
@@ -992,6 +1006,7 @@ static int lib_pPlayerZMovement(lua_State *L)
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
 	P_PlayerZMovement(actor);
+	P_CheckPosition(actor, actor->x, actor->y);
 	return 0;
 }
 
@@ -2586,30 +2601,56 @@ static int lib_rGetNameByColor(lua_State *L)
 
 // S_SOUND
 ////////////
+static int GetValidSoundOrigin(lua_State *L, void **origin)
+{
+	const char *type;
+
+	lua_settop(L, 1);
+	type = GetUserdataUType(L);
+
+	if (fasticmp(type, "mobj_t"))
+	{
+		*origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+		if (!(*origin))
+			return LUA_ErrInvalid(L, "mobj_t");
+		return 1;
+	}
+	else if (fasticmp(type, "sector_t"))
+	{
+		*origin = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
+		if (!(*origin))
+			return LUA_ErrInvalid(L, "sector_t");
+
+		*origin = &((sector_t *)(*origin))->soundorg;
+		return 1;
+	}
+
+	return LUA_ErrInvalid(L, "mobj_t/sector_t");
+}
+
 static int lib_sStartSound(lua_State *L)
 {
-	const void *origin = NULL;
+	void *origin = NULL;
 	sfxenum_t sound_id = luaL_checkinteger(L, 2);
 	player_t *player = NULL;
 	//NOHUD
+
 	if (sound_id >= NUMSFX)
 		return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
-	if (!lua_isnil(L, 1))
-	{
-		origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-		if (!origin)
-			return LUA_ErrInvalid(L, "mobj_t");
-	}
+
 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
 	{
 		player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
 		if (!player)
 			return LUA_ErrInvalid(L, "player_t");
 	}
+	if (!lua_isnil(L, 1))
+		if (!GetValidSoundOrigin(L, &origin))
+			return 0;
 	if (!player || P_IsLocalPlayer(player))
 	{
-		if (hud_running)
-			origin = NULL;	// HUD rendering startsound shouldn't have an origin, just remove it instead of having a retarded error.
+		if (hud_running || hook_cmd_running)
+			origin = NULL;	// HUD rendering and CMD building startsound shouldn't have an origin, just remove it instead of having a retarded error.
 
 		S_StartSound(origin, sound_id);
 	}
@@ -2618,18 +2659,12 @@ static int lib_sStartSound(lua_State *L)
 
 static int lib_sStartSoundAtVolume(lua_State *L)
 {
-	const void *origin = NULL;
+	void *origin = NULL;
 	sfxenum_t sound_id = luaL_checkinteger(L, 2);
 	INT32 volume = (INT32)luaL_checkinteger(L, 3);
 	player_t *player = NULL;
 	//NOHUD
 
-	if (!lua_isnil(L, 1))
-	{
-		origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-		if (!origin)
-			return LUA_ErrInvalid(L, "mobj_t");
-	}
 	if (sound_id >= NUMSFX)
 		return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
 	if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
@@ -2638,30 +2673,37 @@ static int lib_sStartSoundAtVolume(lua_State *L)
 		if (!player)
 			return LUA_ErrInvalid(L, "player_t");
 	}
+	if (!lua_isnil(L, 1))
+		if (!GetValidSoundOrigin(L, &origin))
+			return LUA_ErrInvalid(L, "mobj_t/sector_t");
+
 	if (!player || P_IsLocalPlayer(player))
-	S_StartSoundAtVolume(origin, sound_id, volume);
+		S_StartSoundAtVolume(origin, sound_id, volume);
 	return 0;
 }
 
 static int lib_sStopSound(lua_State *L)
 {
-	void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	void *origin = NULL;
 	//NOHUD
-	if (!origin)
-		return LUA_ErrInvalid(L, "mobj_t");
+	if (!GetValidSoundOrigin(L, &origin))
+		return LUA_ErrInvalid(L, "mobj_t/sector_t");
+
 	S_StopSound(origin);
 	return 0;
 }
 
 static int lib_sStopSoundByID(lua_State *L)
 {
-	void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	void *origin = NULL;
 	sfxenum_t sound_id = luaL_checkinteger(L, 2);
 	//NOHUD
-	if (!origin)
-		return LUA_ErrInvalid(L, "mobj_t");
+
 	if (sound_id >= NUMSFX)
 		return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
+	if (!lua_isnil(L, 1))
+		if (!GetValidSoundOrigin(L, &origin))
+			return LUA_ErrInvalid(L, "mobj_t/sector_t");
 
 	S_StopSoundByID(origin, sound_id);
 	return 0;
@@ -2887,11 +2929,12 @@ static int lib_sSetMusicPosition(lua_State *L)
 
 static int lib_sOriginPlaying(lua_State *L)
 {
-	void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	void *origin = NULL;
 	//NOHUD
 	INLEVEL
-	if (!origin)
-		return LUA_ErrInvalid(L, "mobj_t");
+	if (!GetValidSoundOrigin(L, &origin))
+		return LUA_ErrInvalid(L, "mobj_t/sector_t");
+
 	lua_pushboolean(L, S_OriginPlaying(origin));
 	return 1;
 }
@@ -2908,14 +2951,15 @@ static int lib_sIdPlaying(lua_State *L)
 
 static int lib_sSoundPlaying(lua_State *L)
 {
-	void *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	void *origin = NULL;
 	sfxenum_t id = luaL_checkinteger(L, 2);
 	//NOHUD
 	INLEVEL
-	if (!origin)
-		return LUA_ErrInvalid(L, "mobj_t");
 	if (id >= NUMSFX)
 		return luaL_error(L, "sfx %d out of range (0 - %d)", id, NUMSFX-1);
+	if (!GetValidSoundOrigin(L, &origin))
+		return LUA_ErrInvalid(L, "mobj_t/sector_t");
+
 	lua_pushboolean(L, S_SoundPlaying(origin, id));
 	return 1;
 }
diff --git a/src/lua_hook.h b/src/lua_hook.h
index 48f6cab32c51ceb695d325b47196341033d0a6a7..47850812f059c5825e3f53428c4bbecda4e7a5ef 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -59,11 +59,14 @@ enum hook {
 	hook_PlayerThink,
 	hook_ShouldJingleContinue,
 	hook_GameQuit,
+	hook_PlayerCmd,
 
 	hook_MAX // last hook
 };
 extern const char *const hookNames[];
 
+extern boolean hook_cmd_running;
+
 void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load)
 void LUAh_MapLoad(void); // Hook for map load
 void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer
@@ -113,4 +116,5 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_
 #endif
 #define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink
 boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing
-void LUAh_GameQuit(void); // Hook for game quitting
\ No newline at end of file
+void LUAh_GameQuit(void); // Hook for game quitting
+boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart)
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index ebf6f9deb2c5f72b87faf3cbb98d6cdfaa4aea7a..8840c81a008def5c46fc9a6a0944392b7fa07f18 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -71,6 +71,7 @@ const char *const hookNames[hook_MAX+1] = {
 	"PlayerThink",
 	"ShouldJingleContinue",
 	"GameQuit",
+	"PlayerCmd",
 	NULL
 };
 
@@ -1793,6 +1794,49 @@ void LUAh_GameQuit(void)
 			hookp->error = true;
 		}
 	}
-	
+
 	lua_pop(gL, 1); // Pop error handler
 }
+
+// Hook for building player's ticcmd struct (Ported from SRB2Kart)
+boolean hook_cmd_running = false;
+boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd)
+{
+	hook_p hookp;
+	boolean hooked = false;
+	if (!gL || !(hooksAvailable[hook_PlayerCmd/8] & (1<<(hook_PlayerCmd%8))))
+		return false;
+
+	lua_settop(gL, 0);
+	lua_pushcfunction(gL, LUA_GetErrorMessage);
+
+	hook_cmd_running = true;
+	for (hookp = roothook; hookp; hookp = hookp->next)
+	{
+		if (hookp->type != hook_PlayerCmd)
+			continue;
+
+		if (lua_gettop(gL) == 1)
+		{
+			LUA_PushUserdata(gL, player, META_PLAYER);
+			LUA_PushUserdata(gL, cmd, META_TICCMD);
+		}
+		PushHook(gL, hookp);
+		lua_pushvalue(gL, -3);
+		lua_pushvalue(gL, -3);
+		if (lua_pcall(gL, 2, 1, 1)) {
+			if (!hookp->error || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			hookp->error = true;
+			continue;
+		}
+		if (lua_toboolean(gL, -1))
+			hooked = true;
+		lua_pop(gL, 1);
+	}
+
+	lua_settop(gL, 0);
+	hook_cmd_running = false;
+	return hooked;
+}
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 69e807d502273f4f86ae97f05ee615e60ff5768a..ba3342b44680639f01612a46314dc1ec8ef383c9 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -916,6 +916,19 @@ static int libd_getColormap(lua_State *L)
 	return 1;
 }
 
+static int libd_getStringColormap(lua_State *L)
+{
+	INT32 flags = luaL_checkinteger(L, 1);
+	UINT8* colormap = NULL;
+	HUDONLY
+	colormap = V_GetStringColormap(flags & V_CHARCOLORMASK);
+	if (colormap) {
+		LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use!
+		return 1;
+	}
+	return 0;
+}
+
 static int libd_fadeScreen(lua_State *L)
 {
 	UINT16 color = luaL_checkinteger(L, 1);
@@ -1066,6 +1079,7 @@ static luaL_Reg lib_draw[] = {
 	{"getSpritePatch", libd_getSpritePatch},
 	{"getSprite2Patch", libd_getSprite2Patch},
 	{"getColormap", libd_getColormap},
+	{"getStringColormap", libd_getStringColormap},
 	// drawing
 	{"draw", libd_draw},
 	{"drawScaled", libd_drawScaled},
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index 213b1e3f87bd62f10375f5ac4ea88cee7b7f7cb7..18e51995117717fd5ca47a0182876ecdea7eac1f 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -26,6 +26,7 @@
 #include "lua_script.h"
 #include "lua_libs.h"
 #include "lua_hud.h" // hud_running errors
+#include "lua_hook.h" // hook_cmd_running errors
 
 extern CV_PossibleValue_t Color_cons_t[];
 extern UINT8 skincolor_modified[];
@@ -166,6 +167,8 @@ static int lib_setSpr2default(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter spr2defaults[] in CMD building code!");
 
 // todo: maybe allow setting below first freeslot..? step 1 is toggling this, step 2 is testing to see whether it's net-safe
 #ifdef SETALLSPR2DEFAULTS
@@ -372,6 +375,8 @@ static int lib_setSpriteInfo(lua_State *L)
 		return luaL_error(L, "Do not alter spriteinfo_t from within a hook or coroutine!");
 	if (hud_running)
 		return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter spriteinfo_t in CMD building code!");     
 
 	lua_remove(L, 1);
 	{
@@ -452,6 +457,8 @@ static int spriteinfo_set(lua_State *L)
 		return luaL_error(L, "Do not alter spriteinfo_t from within a hook or coroutine!");
 	if (hud_running)
 		return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter spriteinfo_t in CMD building code!");
 
 	I_Assert(sprinfo != NULL);
 
@@ -525,6 +532,8 @@ static int pivotlist_set(lua_State *L)
 		return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!");
 	if (hud_running)
 		return luaL_error(L, "Do not alter spriteframepivot_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter spriteframepivot_t in CMD building code!");
 
 	I_Assert(pivotlist != NULL);
 
@@ -579,6 +588,8 @@ static int framepivot_set(lua_State *L)
 		return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!");
 	if (hud_running)
 		return luaL_error(L, "Do not alter spriteframepivot_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter spriteframepivot_t in CMD building code!");
 
 	I_Assert(framepivot != NULL);
 
@@ -678,6 +689,8 @@ static int lib_setState(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter states in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter states in CMD building code!");
 
 	// clear the state to start with, in case of missing table elements
 	memset(state,0,sizeof(state_t));
@@ -898,6 +911,8 @@ static int state_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter states in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter states in CMD building code!");
 
 	if (fastcmp(field,"sprite")) {
 		value = luaL_checknumber(L, 3);
@@ -998,6 +1013,8 @@ static int lib_setMobjInfo(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter mobjinfo in CMD building code!");
 
 	// clear the mobjinfo to start with, in case of missing table elements
 	memset(info,0,sizeof(mobjinfo_t));
@@ -1165,6 +1182,8 @@ static int mobjinfo_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter mobjinfo in CMD building code!");
 
 	I_Assert(info != NULL);
 	I_Assert(info >= mobjinfo);
@@ -1287,6 +1306,8 @@ static int lib_setSfxInfo(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter sfxinfo in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter sfxinfo in CMD building code!");
 
 	lua_pushnil(L);
 	while (lua_next(L, 1)) {
@@ -1368,6 +1389,8 @@ static int sfxinfo_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter S_sfx in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter S_sfx in CMD building code!");
 
 	I_Assert(sfx != NULL);
 
@@ -1435,6 +1458,8 @@ static int lib_setluabanks(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter luabanks[] in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter luabanks[] in CMD building code!");
 
 	lua_remove(L, 1); // don't care about luabanks[] dummy userdata.
 
@@ -1515,6 +1540,8 @@ static int lib_setSkinColor(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter skincolors in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter skincolors in CMD building code!");
 
 	// clear the skincolor to start with, in case of missing table elements
 	memset(info,0,sizeof(skincolor_t));
@@ -1534,8 +1561,10 @@ static int lib_setSkinColor(lua_State *L)
 			strlcpy(info->name, n, MAXCOLORNAME+1);
 			if (strlen(n) > MAXCOLORNAME)
 				CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') longer than %d chars; clipped to %s.\n", n, MAXCOLORNAME, info->name);
+#if 0
 			if (strchr(info->name, ' ') != NULL)
 				CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') contains spaces.\n", info->name);
+#endif
 
 			if (info->name[0] != '\0') // don't check empty string for dupe
 			{
@@ -1625,8 +1654,10 @@ static int skincolor_set(lua_State *L)
 		strlcpy(info->name, n, MAXCOLORNAME+1);
 		if (strlen(n) > MAXCOLORNAME)
 			CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') longer than %d chars; clipped to %s.\n", n, MAXCOLORNAME, info->name);
+#if 0
 		if (strchr(info->name, ' ') != NULL)
 			CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') contains spaces.\n", info->name);
+#endif
 
 		if (info->name[0] != '\0') // don't check empty string for dupe
 		{
@@ -1699,6 +1730,8 @@ static int colorramp_set(lua_State *L)
 		return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' index %d out of range (0 - %d)", n, COLORRAMPSIZE-1);
 	if (hud_running)
 		return luaL_error(L, "Do not alter skincolor_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter skincolor_t in CMD building code!");
 	colorramp[n] = i;
 	skincolor_modified[cnum] = true;
 	return 0;
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 216818d29b63e85356c698884ea94d93bff79844..12a0be27d0f9e728264816599f232238ea206a06 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -21,6 +21,7 @@
 #include "lua_script.h"
 #include "lua_libs.h"
 #include "lua_hud.h" // hud_running errors
+#include "lua_hook.h" // hook_cmd_running errors
 
 #include "dehacked.h"
 #include "fastcmp.h"
@@ -585,6 +586,8 @@ static int sector_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter sector_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter sector_t in CMD building code!");
 
 	switch(field)
 	{
@@ -1772,6 +1775,8 @@ static int ffloor_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter ffloor_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter ffloor_t in CMD building code!");
 
 	switch(field)
 	{
@@ -1896,6 +1901,8 @@ static int slope_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter pslope_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter pslope_t in CMD building code!");
 
 	switch(field) // todo: reorganize this shit
 	{
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 4fa938ea54ba0025f87994a0f0bc68a49d467e64..a1a3e96c93afd9d036ad6f8120e6a1c0bf82b9ac 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -20,6 +20,7 @@
 #include "lua_script.h"
 #include "lua_libs.h"
 #include "lua_hud.h" // hud_running errors
+#include "lua_hook.h" // hook_cmd_running errors
 
 static const char *const array_opt[] ={"iterate",NULL};
 
@@ -437,6 +438,8 @@ static int mobj_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter mobj_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter mobj_t in CMD building code!");
 
 	switch(field)
 	{
@@ -878,6 +881,8 @@ static int mapthing_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter mapthing_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter mapthing_t in CMD building code!");
 
 	if(fastcmp(field,"x"))
 		mt->x = (INT16)luaL_checkinteger(L, 3);
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index 1ce9be525f50146735f3973bb5b36de246c5b383..412dc3eff6b1f0927e2d0483878a38110acf3b05 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -20,6 +20,7 @@
 #include "lua_script.h"
 #include "lua_libs.h"
 #include "lua_hud.h" // hud_running errors
+#include "lua_hook.h" // hook_cmd_running errors
 
 static int lib_iteratePlayers(lua_State *L)
 {
@@ -400,6 +401,8 @@ static int player_set(lua_State *L)
 
 	if (hud_running)
 		return luaL_error(L, "Do not alter player_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter player_t in CMD building code!");
 
 	if (fastcmp(field,"mo") || fastcmp(field,"realmo")) {
 		mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
@@ -770,6 +773,8 @@ static int power_set(lua_State *L)
 		return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p);
 	if (hud_running)
 		return luaL_error(L, "Do not alter player_t in HUD rendering code!");
+	if (hook_cmd_running)
+		return luaL_error(L, "Do not alter player_t in CMD building code!");
 	powers[p] = i;
 	return 0;
 }
diff --git a/src/m_anigif.c b/src/m_anigif.c
index 83bc3dddc0d46a682fa3df8863caf0a841de5c04..f30effb9bb715f0037be5a4684bf25aa700a696e 100644
--- a/src/m_anigif.c
+++ b/src/m_anigif.c
@@ -29,10 +29,10 @@
 // GIFs are always little-endian
 #include "byteptr.h"
 
-consvar_t cv_gif_optimize = {"gif_optimize", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gif_downscale =  {"gif_downscale", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gif_dynamicdelay = {"gif_dynamicdelay", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gif_localcolortable =  {"gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_gif_optimize = CVAR_INIT ("gif_optimize", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_gif_downscale =  CVAR_INIT ("gif_downscale", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_gif_localcolortable =  CVAR_INIT ("gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL);
 
 #ifdef HAVE_ANIGIF
 static boolean gif_optimize = false; // So nobody can do something dumb
@@ -499,20 +499,22 @@ static size_t gifframe_size = 8192;
 // converts an RGB frame to a frame with a palette.
 //
 #ifdef HWRENDER
+static colorlookup_t gif_colorlookup;
+
 static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
 {
 	UINT8 r, g, b;
 	size_t src = 0, dest = 0;
 	size_t size = (vid.width * vid.height * 3);
 
-	InitColorLUT(gif_framepalette);
+	InitColorLUT(&gif_colorlookup, gif_framepalette, true);
 
 	while (src < size)
 	{
 		r = (UINT8)linear[src];
 		g = (UINT8)linear[src + 1];
 		b = (UINT8)linear[src + 2];
-		scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS];
+		scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b);
 		src += (3 * scrbuf_downscaleamt);
 		dest += scrbuf_downscaleamt;
 	}
diff --git a/src/m_cheat.c b/src/m_cheat.c
index c42763afdb99562ac68f3e465912b959f4ce0f80..349f00c4858722a984bdb48bacd13af168245651 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -967,10 +967,10 @@ static CV_PossibleValue_t op_speed_t[] = {{1, "MIN"}, {128, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t op_flags_t[] = {{0, "MIN"}, {15, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t op_hoopflags_t[] = {{0, "MIN"}, {15, "MAX"}, {0, NULL}};
 
-consvar_t cv_mapthingnum = {"op_mapthingnum", "0", CV_NOTINNET, op_mapthing_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_speed = {"op_speed", "16", CV_NOTINNET, op_speed_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_opflags = {"op_flags", "0", CV_NOTINNET, op_flags_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ophoopflags = {"op_hoopflags", "4", CV_NOTINNET, op_hoopflags_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mapthingnum = CVAR_INIT ("op_mapthingnum", "0", CV_NOTINNET, op_mapthing_t, NULL);
+consvar_t cv_speed = CVAR_INIT ("op_speed", "16", CV_NOTINNET, op_speed_t, NULL);
+consvar_t cv_opflags = CVAR_INIT ("op_flags", "0", CV_NOTINNET, op_flags_t, NULL);
+consvar_t cv_ophoopflags = CVAR_INIT ("op_hoopflags", "4", CV_NOTINNET, op_hoopflags_t, NULL);
 
 boolean objectplacing = false;
 mobjtype_t op_currentthing = 0; // For the object placement mode
@@ -1023,8 +1023,8 @@ static void OP_CycleThings(INT32 amt)
 		states[S_OBJPLACE_DUMMY].frame = states[mobjinfo[op_currentthing].spawnstate].frame;
 	}
 	if (players[0].mo->eflags & MFE_VERTICALFLIP) // correct z when flipped
-		players[0].mo->z += players[0].mo->height - mobjinfo[op_currentthing].height;
-	players[0].mo->height = mobjinfo[op_currentthing].height;
+		players[0].mo->z += players[0].mo->height - FixedMul(mobjinfo[op_currentthing].height, players[0].mo->scale);
+	players[0].mo->height = FixedMul(mobjinfo[op_currentthing].height, players[0].mo->scale);
 	P_SetPlayerMobjState(players[0].mo, S_OBJPLACE_DUMMY);
 
 	op_currentdoomednum = mobjinfo[op_currentthing].doomednum;
@@ -1107,6 +1107,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
 	mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle)));
 
 	mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value;
+	mt->scale = player->mo->scale;
+	mt->tag = 0;
+	memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args));
+	memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs));
+	mt->pitch = mt->roll = 0;
 	return mt;
 }
 
@@ -1144,7 +1149,7 @@ void OP_NightsObjectplace(player_t *player)
 	if (player->pflags & PF_ATTACKDOWN)
 	{
 		// Are ANY objectplace buttons pressed?  If no, remove flag.
-		if (!(cmd->buttons & (BT_ATTACK|BT_TOSSFLAG|BT_USE|BT_WEAPONNEXT|BT_WEAPONPREV)))
+		if (!(cmd->buttons & (BT_ATTACK|BT_TOSSFLAG|BT_SPIN|BT_WEAPONNEXT|BT_WEAPONPREV)))
 			player->pflags &= ~PF_ATTACKDOWN;
 
 		// Do nothing.
@@ -1251,7 +1256,7 @@ void OP_NightsObjectplace(player_t *player)
 	}
 
 	// This places a custom object as defined in the console cv_mapthingnum.
-	if (cmd->buttons & BT_USE)
+	if (cmd->buttons & BT_SPIN)
 	{
 		UINT16 angle;
 
@@ -1297,27 +1302,26 @@ void OP_ObjectplaceMovement(player_t *player)
 {
 	ticcmd_t *cmd = &player->cmd;
 
-	if (!player->climbing && (netgame || !cv_analog[0].value || (player->pflags & PF_SPINNING)))
-		player->drawangle = player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
+	player->drawangle = player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
 
 	ticruned++;
 	if (!(cmd->angleturn & TICCMD_RECEIVED))
 		ticmiss++;
 
 	if (cmd->buttons & BT_JUMP)
-		player->mo->z += FRACUNIT*cv_speed.value;
-	else if (cmd->buttons & BT_USE)
-		player->mo->z -= FRACUNIT*cv_speed.value;
+		player->mo->z += player->mo->scale*cv_speed.value;
+	else if (cmd->buttons & BT_SPIN)
+		player->mo->z -= player->mo->scale*cv_speed.value;
 
 	if (cmd->forwardmove != 0)
 	{
-		P_Thrust(player->mo, player->mo->angle, (cmd->forwardmove*FRACUNIT/MAXPLMOVE)*cv_speed.value);
+		P_Thrust(player->mo, player->mo->angle, (cmd->forwardmove*player->mo->scale/MAXPLMOVE)*cv_speed.value);
 		P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
 		player->mo->momx = player->mo->momy = 0;
 	}
 	if (cmd->sidemove != 0)
 	{
-		P_Thrust(player->mo, player->mo->angle-ANGLE_90, (cmd->sidemove*FRACUNIT/MAXPLMOVE)*cv_speed.value);
+		P_Thrust(player->mo, player->mo->angle-ANGLE_90, (cmd->sidemove*player->mo->scale/MAXPLMOVE)*cv_speed.value);
 		P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
 		player->mo->momx = player->mo->momy = 0;
 	}
@@ -1443,62 +1447,75 @@ void Command_ObjectPlace_f(void)
 	G_SetGameModified(multiplayer);
 
 	// Entering objectplace?
-	if (!objectplacing)
+	if (!objectplacing || COM_Argc() > 1)
 	{
-		objectplacing = true;
-
-		if (players[0].powers[pw_carry] == CR_NIGHTSMODE)
-			return;
-
-		if (!COM_CheckParm("-silent"))
+		if (!objectplacing)
 		{
-			HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE|V_AUTOFADEOUT);
-			HU_SetCEchoDuration(10);
-			HU_DoCEcho(va(M_GetText(
-				"\\\\\\\\\\\\\\\\\\\\\\\\\x82"
-				"   Objectplace Controls:   \x80\\\\"
-				"Weapon Next/Prev: Cycle mapthings\\"
-				"            Jump: Float up       \\"
-				"            Spin: Float down     \\"
-				"       Fire Ring: Place object   \\")));
-		}
+			objectplacing = true;
 
-		// Save all the player's data.
-		op_oldflags1 = players[0].mo->flags;
-		op_oldflags2 = players[0].mo->flags2;
-		op_oldeflags = players[0].mo->eflags;
-		op_oldpflags = players[0].pflags;
-		op_oldmomx = players[0].mo->momx;
-		op_oldmomy = players[0].mo->momy;
-		op_oldmomz = players[0].mo->momz;
-		op_oldheight = players[0].mo->height;
-		op_oldstate = S_PLAY_STND;
-		op_oldcolor = players[0].mo->color; // save color too in case of super/fireflower
-
-		// Remove ALL flags and motion.
-		P_UnsetThingPosition(players[0].mo);
-		players[0].pflags = 0;
-		players[0].mo->flags2 = 0;
-		players[0].mo->eflags = 0;
-		players[0].mo->flags = (MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP);
-		players[0].mo->momx = players[0].mo->momy = players[0].mo->momz = 0;
-		P_SetThingPosition(players[0].mo);
+			if (players[0].powers[pw_carry] == CR_NIGHTSMODE)
+				return;
+
+			if (!COM_CheckParm("-silent"))
+			{
+				HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE|V_AUTOFADEOUT);
+				HU_SetCEchoDuration(10);
+				HU_DoCEcho(va(M_GetText(
+					"\\\\\\\\\\\\\\\\\\\\\\\\\x82"
+					"   Objectplace Controls:   \x80\\\\"
+					"Weapon Next/Prev: Cycle mapthings\\"
+					"            Jump: Float up       \\"
+					"            Spin: Float down     \\"
+					"       Fire Ring: Place object   \\")));
+			}
 
-		// Take away color so things display properly
-		players[0].mo->color = 0;
+			// Save all the player's data.
+			op_oldflags1 = players[0].mo->flags;
+			op_oldflags2 = players[0].mo->flags2;
+			op_oldeflags = players[0].mo->eflags;
+			op_oldpflags = players[0].pflags;
+			op_oldmomx = players[0].mo->momx;
+			op_oldmomy = players[0].mo->momy;
+			op_oldmomz = players[0].mo->momz;
+			op_oldheight = players[0].mo->height;
+			op_oldstate = S_PLAY_STND;
+			op_oldcolor = players[0].mo->color; // save color too in case of super/fireflower
+
+			// Remove ALL flags and motion.
+			P_UnsetThingPosition(players[0].mo);
+			players[0].pflags = 0;
+			players[0].mo->flags2 = 0;
+			players[0].mo->eflags = 0;
+			players[0].mo->flags = (MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP);
+			players[0].mo->momx = players[0].mo->momy = players[0].mo->momz = 0;
+			P_SetThingPosition(players[0].mo);
+
+			// Take away color so things display properly
+			players[0].mo->color = 0;
+
+			// Like the classics, recover from death by entering objectplace
+			if (players[0].mo->health <= 0)
+			{
+				players[0].mo->health = 1;
+				players[0].deadtimer = 0;
+				op_oldflags1 = mobjinfo[MT_PLAYER].flags;
+				++players[0].lives;
+				players[0].playerstate = PST_LIVE;
+				P_RestoreMusic(&players[0]);
+			}
+			else
+				op_oldstate = (statenum_t)(players[0].mo->state-states);
+		}
 
-		// Like the classics, recover from death by entering objectplace
-		if (players[0].mo->health <= 0)
+		if (COM_Argc() > 1)
 		{
-			players[0].mo->health = 1;
-			players[0].deadtimer = 0;
-			op_oldflags1 = mobjinfo[MT_PLAYER].flags;
-			++players[0].lives;
-			players[0].playerstate = PST_LIVE;
-			P_RestoreMusic(&players[0]);
+			UINT16 mapthingnum = atoi(COM_Argv(1));
+			mobjtype_t type = P_GetMobjtype(mapthingnum);
+			if (type == MT_UNKNOWN)
+				CONS_Printf(M_GetText("No mobj type delegated to thing type %d.\n"), mapthingnum);
+			else
+				op_currentthing = type;
 		}
-		else
-			op_oldstate = (statenum_t)(players[0].mo->state-states);
 
 		// If no thing set, then cycle a little
 		if (!op_currentthing)
@@ -1506,8 +1523,8 @@ void Command_ObjectPlace_f(void)
 			op_currentthing = 1;
 			OP_CycleThings(1);
 		}
-		else // Cycle things sets this for the former.
-			players[0].mo->height = mobjinfo[op_currentthing].height;
+		else
+			OP_CycleThings(0); // sets all necessary height values without cycling op_currentthing
 
 		P_SetPlayerMobjState(players[0].mo, S_OBJPLACE_DUMMY);
 	}
diff --git a/src/m_menu.c b/src/m_menu.c
index 3c6397ebb90408537250693b1efd6f96251380fa..9300f6d5575455ff64cb2bc9ce1a0de37b338ee5 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -32,6 +32,7 @@
 #include "sounds.h"
 #include "s_sound.h"
 #include "i_system.h"
+#include "i_threads.h"
 
 // Addfile
 #include "filesrch.h"
@@ -74,12 +75,6 @@
 #endif
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-int	snprintf(char *str, size_t n, const char *fmt, ...);
-//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
 #if defined (__GNUC__) && (__GNUC__ >= 4)
 #define FIXUPO0
 #endif
@@ -122,6 +117,12 @@ typedef enum
 	NUM_QUITMESSAGES
 } text_enum;
 
+#ifdef HAVE_THREADS
+I_mutex m_menu_mutex;
+#endif
+
+M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
+
 const char *quitmsg[NUM_QUITMESSAGES];
 
 // Stuff for customizing the player select screen Tails 09-22-2003
@@ -405,37 +406,29 @@ static void M_ResetCvars(void);
 
 // Consvar onchange functions
 static void Newgametype_OnChange(void);
-#ifdef HWRENDER
-static void Newrenderer_OnChange(void);
-#endif
 static void Dummymares_OnChange(void);
 
 // ==========================================================================
 // CONSOLE VARIABLES AND THEIR POSSIBLE VALUES GO HERE.
 // ==========================================================================
 
-consvar_t cv_showfocuslost = {"showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL };
+consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL);
 
 static CV_PossibleValue_t map_cons_t[] = {
 	{1,"MIN"},
 	{NUMMAPS, "MAX"},
 	{0,NULL}
 };
-consvar_t cv_nextmap = {"nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_nextmap = CVAR_INIT ("nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange);
 
 static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}};
-consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange);
 
 // This gametype list is integral for many different reasons.
 // When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h!
 CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1];
 
-consvar_t cv_newgametype = {"newgametype", "Co-op", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-#ifdef HWRENDER
-consvar_t cv_newrenderer = {"newrenderer", "Software", CV_HIDEN|CV_CALL, cv_renderer_t, Newrenderer_OnChange, 0, NULL, NULL, 0, 0, NULL};
-static int newrenderer_set = 1;/* Software doesn't need confirmation! */
-#endif
+consvar_t cv_newgametype = CVAR_INIT ("newgametype", "Co-op", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange);
 
 static CV_PossibleValue_t serversort_cons_t[] = {
 	{0,"Ping"},
@@ -446,22 +439,22 @@ static CV_PossibleValue_t serversort_cons_t[] = {
 	{5,"Gametype"},
 	{0,NULL}
 };
-consvar_t cv_serversort = {"serversort", "Ping", CV_HIDEN | CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_serversort = CVAR_INIT ("serversort", "Ping", CV_HIDEN | CV_CALL, serversort_cons_t, M_SortServerList);
 
 // first time memory
-consvar_t cv_tutorialprompt = {"tutorialprompt", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_tutorialprompt = CVAR_INIT ("tutorialprompt", "On", CV_SAVE, CV_OnOff, NULL);
 
 // autorecord demos for time attack
-static consvar_t cv_autorecord = {"autorecord", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_autorecord = CVAR_INIT ("autorecord", "Yes", 0, CV_YesNo, NULL);
 
 CV_PossibleValue_t ghost_cons_t[] = {{0, "Hide"}, {1, "Show"}, {2, "Show All"}, {0, NULL}};
 CV_PossibleValue_t ghost2_cons_t[] = {{0, "Hide"}, {1, "Show"}, {0, NULL}};
 
-consvar_t cv_ghost_bestscore = {"ghost_bestscore", "Show", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ghost_besttime  = {"ghost_besttime",  "Show", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ghost_bestrings = {"ghost_bestrings", "Show", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ghost_last      = {"ghost_last",      "Show", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ghost_guest     = {"ghost_guest",     "Show", CV_SAVE, ghost2_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_ghost_bestscore = CVAR_INIT ("ghost_bestscore", "Show", CV_SAVE, ghost_cons_t, NULL);
+consvar_t cv_ghost_besttime  = CVAR_INIT ("ghost_besttime",  "Show", CV_SAVE, ghost_cons_t, NULL);
+consvar_t cv_ghost_bestrings = CVAR_INIT ("ghost_bestrings", "Show", CV_SAVE, ghost_cons_t, NULL);
+consvar_t cv_ghost_last      = CVAR_INIT ("ghost_last",      "Show", CV_SAVE, ghost_cons_t, NULL);
+consvar_t cv_ghost_guest     = CVAR_INIT ("ghost_guest",     "Show", CV_SAVE, ghost2_cons_t, NULL);
 
 //Console variables used solely in the menu system.
 //todo: add a way to use non-console variables in the menu
@@ -475,19 +468,19 @@ static CV_PossibleValue_t dummymares_cons_t[] = {
 	{-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL}
 };
 
-static consvar_t cv_dummyteam = {"dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_dummyscramble = {"dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_dummyrings = {"dummyrings", "0", CV_HIDEN, ringlimit_cons_t,	NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_dummylives = {"dummylives", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_dummycontinues = {"dummycontinues", "0", CV_HIDEN, contlimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dummymares_cons_t, Dummymares_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL);
+static consvar_t cv_dummyscramble = CVAR_INIT ("dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL);
+static consvar_t cv_dummyrings = CVAR_INIT ("dummyrings", "0", CV_HIDEN, ringlimit_cons_t,	NULL);
+static consvar_t cv_dummylives = CVAR_INIT ("dummylives", "0", CV_HIDEN, liveslimit_cons_t, NULL);
+static consvar_t cv_dummycontinues = CVAR_INIT ("dummycontinues", "0", CV_HIDEN, contlimit_cons_t, NULL);
+static consvar_t cv_dummymares = CVAR_INIT ("dummymares", "Overall", CV_HIDEN|CV_CALL, dummymares_cons_t, Dummymares_OnChange);
 
 CV_PossibleValue_t marathon_cons_t[] = {{0, "Standard"}, {1, "Live Event Backup"}, {2, "Ultimate"}, {0, NULL}};
 CV_PossibleValue_t loadless_cons_t[] = {{0, "Realtime"}, {1, "In-game"}, {0, NULL}};
 
-consvar_t cv_dummymarathon = {"dummymarathon", "Standard", CV_HIDEN, marathon_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_dummycutscenes = {"dummycutscenes", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_dummyloadless = {"dummyloadless", "In-game", CV_HIDEN, loadless_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_dummymarathon = CVAR_INIT ("dummymarathon", "Standard", CV_HIDEN, marathon_cons_t, NULL);
+consvar_t cv_dummycutscenes = CVAR_INIT ("dummycutscenes", "Off", CV_HIDEN, CV_OnOff, NULL);
+consvar_t cv_dummyloadless = CVAR_INIT ("dummyloadless", "In-game", CV_HIDEN, loadless_cons_t, NULL);
 
 // ==========================================================================
 // ORGANIZATION START.
@@ -1033,7 +1026,7 @@ enum
 	FIRSTSERVERLINE
 };
 
-static menuitem_t MP_RoomMenu[] =
+menuitem_t MP_RoomMenu[] =
 {
 	{IT_STRING | IT_CALL, NULL, "<Unlisted Mode>", M_ChooseRoom,   9},
 	{IT_DISABLED,         NULL, "",               M_ChooseRoom,  18},
@@ -1116,7 +1109,7 @@ static menuitem_t OP_ChangeControlsMenu[] =
 	{IT_CALL | IT_STRING2, NULL, "Move Left",        M_ChangeControl, gc_strafeleft  },
 	{IT_CALL | IT_STRING2, NULL, "Move Right",       M_ChangeControl, gc_straferight },
 	{IT_CALL | IT_STRING2, NULL, "Jump",             M_ChangeControl, gc_jump      },
-	{IT_CALL | IT_STRING2, NULL, "Spin",             M_ChangeControl, gc_use     },
+	{IT_CALL | IT_STRING2, NULL, "Spin",             M_ChangeControl, gc_spin     },
 	{IT_HEADER, NULL, "Camera", NULL, 0},
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
 	{IT_CALL | IT_STRING2, NULL, "Look Up",        M_ChangeControl, gc_lookup      },
@@ -1346,7 +1339,7 @@ static menuitem_t OP_VideoOptionsMenu[] =
 #endif
 	{IT_STRING | IT_CVAR, NULL, "Vertical Sync",                &cv_vidwait,         16},
 #ifdef HWRENDER
-	{IT_STRING | IT_CVAR, NULL, "Renderer",                     &cv_newrenderer,        21},
+	{IT_STRING | IT_CVAR, NULL, "Renderer",                     &cv_renderer,        21},
 #else
 	{IT_TRANSTEXT | IT_PAIR, "Renderer", "Software",            &cv_renderer,           21},
 #endif
@@ -1662,8 +1655,11 @@ static menuitem_t OP_ServerOptionsMenu[] =
 #ifndef NONET
 	{IT_HEADER, NULL, "Advanced", NULL, 225},
 	{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server",        &cv_masterserver,       231},
+
 	{IT_STRING | IT_CVAR,    NULL, "Join delay",                       &cv_joindelay,          246},
 	{IT_STRING | IT_CVAR,    NULL, "Attempts to resynchronise",        &cv_resynchattempts,    251},
+
+	{IT_STRING | IT_CVAR,    NULL, "Show IP Address of Joiners",       &cv_showjoinaddress,    256},
 #endif
 };
 
@@ -2161,8 +2157,6 @@ static void M_VideoOptions(INT32 choice)
 		OP_VideoOptionsMenu[op_video_renderer].patch = NULL;
 		OP_VideoOptionsMenu[op_video_renderer].text = "Renderer";
 	}
-
-	CV_StealthSetValue(&cv_newrenderer, cv_renderer.value);
 #endif
 
 	M_SetupNextMenu(&OP_VideoOptionsDef);
@@ -2461,46 +2455,6 @@ static void Newgametype_OnChange(void)
 	}
 }
 
-#ifdef HWRENDER
-static void Newrenderer_AREYOUSURE(INT32 c)
-{
-	int n;
-	switch (c)
-	{
-		case 'y':
-		case KEY_ENTER:
-			n = cv_newrenderer.value;
-			newrenderer_set |= n;
-			CV_SetValue(&cv_renderer, n);
-			break;
-		default:
-			CV_StealthSetValue(&cv_newrenderer, cv_renderer.value);
-	}
-}
-
-static void Newrenderer_OnChange(void)
-{
-	/* Well this works for now because there's only two options. */
-	int n;
-	n = cv_newrenderer.value;
-	newrenderer_set |= cv_renderer.value;
-	if (( newrenderer_set & n ))
-		CV_SetValue(&cv_renderer, n);
-	else
-	{
-		M_StartMessage(
-				"The OpenGL renderer is incomplete.\n"
-				"Some visuals may fail to appear, or\n"
-				"appear incorrectly.\n"
-				"Do you still want to switch to it?\n"
-				"\n"
-				"(Press 'y' or 'n')",
-				Newrenderer_AREYOUSURE, MM_YESNO
-		);
-	}
-}
-#endif/*HWRENDER*/
-
 void Screenshot_option_Onchange(void)
 {
 	OP_ScreenshotOptionsMenu[op_screenshot_folder].status =
@@ -3087,7 +3041,6 @@ static void M_GoBack(INT32 choice)
 		//make sure the game doesn't still think we're in a netgame.
 		if (!Playing() && netgame && multiplayer)
 		{
-			MSCloseUDPSocket();		// Clean up so we can re-open the connection later.
 			netgame = multiplayer = false;
 		}
 
@@ -3846,6 +3799,30 @@ void M_SetupNextMenu(menu_t *menudef)
 {
 	INT16 i;
 
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+	if (currentMenu == &MP_RoomDef || currentMenu == &MP_ConnectDef)
+	{
+		I_lock_mutex(&ms_QueryId_mutex);
+		{
+			ms_QueryId++;
+		}
+		I_unlock_mutex(ms_QueryId_mutex);
+	}
+
+	if (currentMenu == &MP_ConnectDef)
+	{
+		I_lock_mutex(&ms_ServerList_mutex);
+		{
+			if (ms_ServerList)
+			{
+				free(ms_ServerList);
+				ms_ServerList = NULL;
+			}
+		}
+		I_unlock_mutex(ms_ServerList_mutex);
+	}
+#endif/*HAVE_THREADS*/
+
 	if (currentMenu->quitroutine)
 	{
 		// If you're going from a menu to itself, why are you running the quitroutine? You're not quitting it! -SH
@@ -3909,6 +3886,19 @@ void M_Ticker(void)
 
 	if (currentMenu == &OP_ScreenshotOptionsDef)
 		M_SetupScreenshotMenu();
+
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+	I_lock_mutex(&ms_ServerList_mutex);
+	{
+		if (ms_ServerList)
+		{
+			CL_QueryServerList(ms_ServerList);
+			free(ms_ServerList);
+			ms_ServerList = NULL;
+		}
+	}
+	I_unlock_mutex(ms_ServerList_mutex);
+#endif
 }
 
 //
@@ -7972,7 +7962,7 @@ static void M_SecretsMenu(INT32 choice)
 
 		skyRoomMenuTranslations[i-1] = (UINT8)ul;
 		SR_MainMenu[i].text = unlockables[ul].name;
-		SR_MainMenu[i].alphaKey = (UINT8)unlockables[ul].height;
+		SR_MainMenu[i].alphaKey = (UINT16)unlockables[ul].height;
 
 		if (unlockables[ul].type == SECRET_HEADER)
 		{
@@ -8432,7 +8422,7 @@ static void M_DrawLoadGameData(void)
 				sprdef = &charbotskin->sprites[SPR2_SIGN];
 				if (!sprdef->numframes)
 					goto skipbot;
-				colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin, charbotskin->prefcolor, 0);
+				colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin-1, charbotskin->prefcolor, 0);
 				sprframe = &sprdef->spriteframes[0];
 				patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH);
 
@@ -10886,22 +10876,65 @@ static INT32 menuRoomIndex = 0;
 
 static void M_DrawRoomMenu(void)
 {
+	static int frame = -12;
+	int dot_frame;
+	char text[4];
+
 	const char *rmotd;
+	const char *waiting_message;
+
+	int dots;
+
+	if (m_waiting_mode)
+	{
+		dot_frame = frame / 4;
+		dots = dot_frame + 3;
+
+		strcpy(text, "   ");
+
+		if (dots > 0)
+		{
+			if (dot_frame < 0)
+				dot_frame = 0;
+
+			strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
+		}
+
+		if (++frame == 12)
+			frame = -12;
+
+		currentMenu->menuitems[0].text = text;
+	}
 
 	// use generic drawer for cursor, items and title
 	M_DrawGenericMenu();
 
 	V_DrawString(currentMenu->x - 16, currentMenu->y, V_YELLOWMAP, M_GetText("Select a room"));
 
-	M_DrawTextBox(144, 24, 20, 20);
+	if (m_waiting_mode == M_NOT_WAITING)
+	{
+		M_DrawTextBox(144, 24, 20, 20);
 
-	if (itemOn == 0)
-		rmotd = M_GetText("Don't connect to the Master Server.");
-	else
-		rmotd = room_list[itemOn-1].motd;
+		if (itemOn == 0)
+			rmotd = M_GetText("Don't connect to the Master Server.");
+		else
+			rmotd = room_list[itemOn-1].motd;
 
-	rmotd = V_WordWrap(0, 20*8, 0, rmotd);
-	V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
+		rmotd = V_WordWrap(0, 20*8, 0, rmotd);
+		V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
+	}
+
+	if (m_waiting_mode)
+	{
+		// Display a little "please wait" message.
+		M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
+		if (m_waiting_mode == M_WAITING_VERSION)
+			waiting_message = "Checking for updates...";
+		else
+			waiting_message = "Fetching room info...";
+		V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, waiting_message);
+		V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
+	}
 }
 
 static void M_DrawConnectMenu(void)
@@ -10969,6 +11002,14 @@ static void M_DrawConnectMenu(void)
 	localservercount = serverlistcount;
 
 	M_DrawGenericMenu();
+
+	if (m_waiting_mode)
+	{
+		// Display a little "please wait" message.
+		M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
+		V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers...");
+		V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
+	}
 }
 
 static boolean M_CancelConnect(void)
@@ -11058,10 +11099,10 @@ void M_SortServerList(void)
 
 #ifndef NONET
 #ifdef UPDATE_ALERT
-static boolean M_CheckMODVersion(void)
+static boolean M_CheckMODVersion(int id)
 {
 	char updatestring[500];
-	const char *updatecheck = GetMODVersion();
+	const char *updatecheck = GetMODVersion(id);
 	if(updatecheck)
 	{
 		sprintf(updatestring, UPDATE_ALERT_STRING, VERSIONSTRING, updatecheck);
@@ -11070,8 +11111,67 @@ static boolean M_CheckMODVersion(void)
 	} else
 		return true;
 }
+#endif/*UPDATE_ALERT*/
+
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+static void
+Check_new_version_thread (int *id)
+{
+	int hosting;
+	int okay;
+
+	okay = 0;
+
+#ifdef UPDATE_ALERT
+	if (M_CheckMODVersion(*id))
+#endif
+	{
+		I_lock_mutex(&ms_QueryId_mutex);
+		{
+			okay = ( *id == ms_QueryId );
+		}
+		I_unlock_mutex(ms_QueryId_mutex);
+
+		if (okay)
+		{
+			I_lock_mutex(&m_menu_mutex);
+			{
+				m_waiting_mode = M_WAITING_ROOMS;
+				hosting = ( currentMenu->prevMenu == &MP_ServerDef );
+			}
+			I_unlock_mutex(m_menu_mutex);
+
+			GetRoomsList(hosting, *id);
+		}
+	}
+#ifdef UPDATE_ALERT
+	else
+	{
+		I_lock_mutex(&ms_QueryId_mutex);
+		{
+			okay = ( *id == ms_QueryId );
+		}
+		I_unlock_mutex(ms_QueryId_mutex);
+	}
 #endif
 
+	if (okay)
+	{
+		I_lock_mutex(&m_menu_mutex);
+		{
+			if (m_waiting_mode)
+			{
+				m_waiting_mode = M_NOT_WAITING;
+				MP_RoomMenu[0].text = "<Offline Mode>";
+			}
+		}
+		I_unlock_mutex(m_menu_mutex);
+	}
+
+	free(id);
+}
+#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
+
 static void M_ConnectMenu(INT32 choice)
 {
 	(void)choice;
@@ -11099,18 +11199,21 @@ static void M_ConnectMenuModChecks(INT32 choice)
 
 	if (modifiedgame)
 	{
-		M_StartMessage(M_GetText("Add-ons are currently loaded.\n\nYou will only be able to join a server if\nit has the same ones loaded in the same order, which may be unlikely.\n\nIf you wish to play on other servers,\nrestart the game to clear existing add-ons.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER);
+		M_StartMessage(M_GetText("You have add-ons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2 will automatically add\neverything you need when you join.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER);
 		return;
 	}
 
 	M_ConnectMenu(-1);
 }
 
-static UINT32 roomIds[NUM_LIST_ROOMS];
+UINT32 roomIds[NUM_LIST_ROOMS];
 
 static void M_RoomMenu(INT32 choice)
 {
 	INT32 i;
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+	int *id;
+#endif
 
 	(void)choice;
 
@@ -11123,34 +11226,54 @@ static void M_RoomMenu(INT32 choice)
 	if (rendermode == render_soft)
 		I_FinishUpdate(); // page flip or blit buffer
 
-	if (GetRoomsList(currentMenu == &MP_ServerDef) < 0)
-		return;
-
-#ifdef UPDATE_ALERT
-	if (!M_CheckMODVersion())
-		return;
-#endif
-
 	for (i = 1; i < NUM_LIST_ROOMS+1; ++i)
 		MP_RoomMenu[i].status = IT_DISABLED;
 	memset(roomIds, 0, sizeof(roomIds));
 
-	for (i = 0; room_list[i].header.buffer[0]; i++)
+	MP_RoomDef.prevMenu = currentMenu;
+	M_SetupNextMenu(&MP_RoomDef);
+
+#ifdef MASTERSERVER
+#ifdef HAVE_THREADS
+#ifdef UPDATE_ALERT
+	m_waiting_mode = M_WAITING_VERSION;
+#else/*UPDATE_ALERT*/
+	m_waiting_mode = M_WAITING_ROOMS;
+#endif/*UPDATE_ALERT*/
+
+	MP_RoomMenu[0].text = "";
+
+	id = malloc(sizeof *id);
+
+	I_lock_mutex(&ms_QueryId_mutex);
 	{
-		if(*room_list[i].name != '\0')
-		{
-			MP_RoomMenu[i+1].text = room_list[i].name;
-			roomIds[i] = room_list[i].id;
-			MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
-		}
+		*id = ms_QueryId;
 	}
+	I_unlock_mutex(ms_QueryId_mutex);
 
-	MP_RoomDef.prevMenu = currentMenu;
-	M_SetupNextMenu(&MP_RoomDef);
+	I_spawn_thread("check-new-version",
+			(I_thread_fn)Check_new_version_thread, id);
+#else/*HAVE_THREADS*/
+#ifdef UPDATE_ALERT
+	if (M_CheckMODVersion(0))
+#endif/*UPDATE_ALERT*/
+	{
+		GetRoomsList(currentMenu->prevMenu == &MP_ServerDef, 0);
+	}
+#endif/*HAVE_THREADS*/
+#endif/*MASTERSERVER*/
 }
 
 static void M_ChooseRoom(INT32 choice)
 {
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+	I_lock_mutex(&ms_QueryId_mutex);
+	{
+		ms_QueryId++;
+	}
+	I_unlock_mutex(ms_QueryId_mutex);
+#endif
+
 	if (choice == 0)
 		ms_RoomId = -1;
 	else
diff --git a/src/m_menu.h b/src/m_menu.h
index 52bdb0dead9eafe30b12e1c8b127940f7cd1dc3b..0465128ef75063b57cd3849bb6faab251e45e139 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -18,8 +18,10 @@
 #include "doomstat.h" // for NUMGAMETYPES
 #include "d_event.h"
 #include "command.h"
-#include "r_skins.h" // for SKINNAMESIZE
 #include "f_finale.h" // for ttmode_enum
+#include "i_threads.h"
+#include "mserv.h"
+#include "r_things.h" // for SKINNAMESIZE
 
 // Compatibility with old-style named NiGHTS replay files.
 #define OLDNREPLAYNAME
@@ -226,6 +228,18 @@ typedef enum
 } menumessagetype_t;
 void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype);
 
+typedef enum
+{
+	M_NOT_WAITING,
+
+	M_WAITING_VERSION,
+	M_WAITING_ROOMS,
+	M_WAITING_SERVERS,
+}
+M_waiting_mode_t;
+
+extern M_waiting_mode_t m_waiting_mode;
+
 // Called by linux_x/i_video_xshm.c
 void M_QuitResponse(INT32 ch);
 
@@ -313,9 +327,12 @@ typedef struct menuitem_s
 	void *itemaction;
 
 	// hotkey in menu or y of the item
-	UINT8 alphaKey;
+	UINT16 alphaKey;
 } menuitem_t;
 
+extern menuitem_t MP_RoomMenu[];
+extern UINT32     roomIds[NUM_LIST_ROOMS];
+
 typedef struct menu_s
 {
 	UINT32         menuid;             // ID to encode menu type and hierarchy
@@ -335,6 +352,10 @@ void M_ClearMenus(boolean callexitmenufunc);
 // Maybe this goes here????? Who knows.
 boolean M_MouseNeeded(void);
 
+#ifdef HAVE_THREADS
+extern I_mutex m_menu_mutex;
+#endif
+
 extern menu_t *currentMenu;
 
 extern menu_t MainDef;
diff --git a/src/m_misc.c b/src/m_misc.c
index 216fde056c001690899debd7ad1ff2b2f982604b..d97d8f94be36972a82880f79316ac8d2f7149131 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -102,16 +102,16 @@ typedef off_t off64_t;
 #endif
 
 static CV_PossibleValue_t screenshot_cons_t[] = {{0, "Default"}, {1, "HOME"}, {2, "SRB2"}, {3, "CUSTOM"}, {0, NULL}};
-consvar_t cv_screenshot_option = {"screenshot_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Screenshot_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_screenshot_folder = {"screenshot_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_screenshot_option = CVAR_INIT ("screenshot_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Screenshot_option_Onchange);
+consvar_t cv_screenshot_folder = CVAR_INIT ("screenshot_folder", "", CV_SAVE, NULL, NULL);
 
-consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_screenshot_colorprofile = CVAR_INIT ("screenshot_colorprofile", "Yes", CV_SAVE, CV_YesNo, NULL);
 
 static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}};
-consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_moviemode = CVAR_INIT ("moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange);
 
-consvar_t cv_movie_option = {"movie_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Moviemode_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_movie_folder = {"movie_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_movie_option = CVAR_INIT ("movie_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Moviemode_option_Onchange);
+consvar_t cv_movie_folder = CVAR_INIT ("movie_folder", "", CV_SAVE, NULL, NULL);
 
 static CV_PossibleValue_t zlib_mem_level_t[] = {
 	{1, "(Min Memory) 1"},
@@ -153,16 +153,16 @@ static CV_PossibleValue_t apng_delay_t[] = {
 
 // zlib memory usage is as follows:
 // (1 << (zlib_window_bits+2)) +  (1 << (zlib_level+9))
-consvar_t cv_zlib_memory = {"png_memory_level", "7", CV_SAVE, zlib_mem_level_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_zlib_level = {"png_compress_level", "(Optimal) 6", CV_SAVE, zlib_level_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_zlib_strategy = {"png_strategy", "Normal", CV_SAVE, zlib_strategy_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_zlib_window_bits = {"png_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_zlib_memory = CVAR_INIT ("png_memory_level", "7", CV_SAVE, zlib_mem_level_t, NULL);
+consvar_t cv_zlib_level = CVAR_INIT ("png_compress_level", "(Optimal) 6", CV_SAVE, zlib_level_t, NULL);
+consvar_t cv_zlib_strategy = CVAR_INIT ("png_strategy", "Normal", CV_SAVE, zlib_strategy_t, NULL);
+consvar_t cv_zlib_window_bits = CVAR_INIT ("png_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL);
 
-consvar_t cv_zlib_memorya = {"apng_memory_level", "(Max Memory) 9", CV_SAVE, zlib_mem_level_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_zlib_levela = {"apng_compress_level", "4", CV_SAVE, zlib_level_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_zlib_strategya = {"apng_strategy", "RLE", CV_SAVE, zlib_strategy_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_zlib_window_bitsa = {"apng_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_apng_delay = {"apng_speed", "1x", CV_SAVE, apng_delay_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_zlib_memorya = CVAR_INIT ("apng_memory_level", "(Max Memory) 9", CV_SAVE, zlib_mem_level_t, NULL);
+consvar_t cv_zlib_levela = CVAR_INIT ("apng_compress_level", "4", CV_SAVE, zlib_level_t, NULL);
+consvar_t cv_zlib_strategya = CVAR_INIT ("apng_strategy", "RLE", CV_SAVE, zlib_strategy_t, NULL);
+consvar_t cv_zlib_window_bitsa = CVAR_INIT ("apng_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL);
+consvar_t cv_apng_delay = CVAR_INIT ("apng_speed", "1x", CV_SAVE, apng_delay_t, NULL);
 
 boolean takescreenshot = false; // Take a screenshot this tic
 
@@ -793,8 +793,6 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
 	 "SDL";
 #elif defined (_WINDOWS)
 	 "DirectX";
-#elif defined (PC_DOS)
-	 "Allegro";
 #else
 	 "Unknown";
 #endif
diff --git a/src/mserv.c b/src/mserv.c
index af56907885cc7575069cd4c649ec456ff690b04e..fa646b8996776ff17474a9c2f8e6a986626453fd 100644
--- a/src/mserv.c
+++ b/src/mserv.c
@@ -2,212 +2,81 @@
 //-----------------------------------------------------------------------------
 // Copyright (C) 1998-2000 by DooM Legacy Team.
 // Copyright (C) 1999-2020 by Sonic Team Junior.
+// Copyright (C)      2020 by James R.
 //
 // This program is free software distributed under the
 // terms of the GNU General Public License, version 2.
 // See the 'LICENSE' file for more details.
 //-----------------------------------------------------------------------------
 /// \file  mserv.c
-/// \brief Commands used for communicate with the master server
-
-#ifdef __GNUC__
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#endif
+/// \brief Commands used to communicate with the master server
 
+#if !defined (UNDER_CE)
 #include <time.h>
-
-#if (defined (NOMSERV)) && !defined (NONET)
-#define NONET
-#endif
-
-#ifndef NONET
-
-#ifndef NO_IPV6
-#define HAVE_IPV6
-#endif
-
-#ifdef _WIN32
-#define RPC_NO_WINDOWS_H
-#ifdef HAVE_IPV6
-#include <ws2tcpip.h>
-#else
-#include <winsock.h>     // socket(),...
-#endif //!HAVE_IPV6
-#else
-#include <arpa/inet.h>
-#ifdef __APPLE_CC__
-#ifndef _BSD_SOCKLEN_T_
-#define _BSD_SOCKLEN_T_
-#endif
 #endif
-#include <sys/socket.h> // socket(),...
-#include <netinet/in.h> // sockaddr_in
-#include <netdb.h> // getaddrinfo(),...
-#include <sys/ioctl.h>
-
-#include <sys/time.h> // timeval,... (TIMEOUT)
-#include <errno.h>
-#endif // _WIN32
-#endif // !NONET
 
 #include "doomstat.h"
 #include "doomdef.h"
 #include "command.h"
-#include "i_net.h"
-#include "console.h"
+#include "i_threads.h"
 #include "mserv.h"
-#include "d_net.h"
-#include "i_tcp.h"
-#include "i_system.h"
-#include "byteptr.h"
 #include "m_menu.h"
-#include "m_argv.h" // Alam is going to kill me <3
-#include "m_misc.h" //  GetRevisionString()
-
-#include "i_addrinfo.h"
-
-// ================================ DEFINITIONS ===============================
-
-#define PACKET_SIZE 1024
-
-
-#define  MS_NO_ERROR            	   0
-#define  MS_SOCKET_ERROR        	-201
-#define  MS_CONNECT_ERROR       	-203
-#define  MS_WRITE_ERROR         	-210
-#define  MS_READ_ERROR          	-211
-#define  MS_CLOSE_ERROR         	-212
-#define  MS_GETHOSTBYNAME_ERROR 	-220
-#define  MS_GETHOSTNAME_ERROR   	-221
-#define  MS_TIMEOUT_ERROR       	-231
-
-// see master server code for the values
-#define ADD_SERVER_MSG          	101
-#define REMOVE_SERVER_MSG       	103
-#define ADD_SERVERv2_MSG        	104
-#define GET_SERVER_MSG          	200
-#define GET_SHORT_SERVER_MSG    	205
-#define ASK_SERVER_MSG          	206
-#define ANSWER_ASK_SERVER_MSG   	207
-#define ASK_SERVER_MSG          	206
-#define ANSWER_ASK_SERVER_MSG   	207
-#define GET_MOTD_MSG            	208
-#define SEND_MOTD_MSG           	209
-#define GET_ROOMS_MSG           	210
-#define SEND_ROOMS_MSG          	211
-#define GET_ROOMS_HOST_MSG      	212
-#define GET_VERSION_MSG         	213
-#define SEND_VERSION_MSG        	214
-#define GET_BANNED_MSG          	215 // Someone's been baaaaaad!
-#define PING_SERVER_MSG         	216
-
-#define HEADER_SIZE (sizeof (INT32)*4)
-
-#define HEADER_MSG_POS    0
-#define IP_MSG_POS       16
-#define PORT_MSG_POS     32
-#define HOSTNAME_MSG_POS 40
-
-
-#if defined(_MSC_VER)
-#pragma pack(1)
-#endif
+#include "z_zone.h"
 
-/** A message to be exchanged with the master server.
-  */
-typedef struct
-{
-	INT32 id;                  ///< Unused?
-	INT32 type;                ///< Type of message.
-	INT32 room;                ///< Because everyone needs a roomie.
-	UINT32 length;             ///< Length of the message.
-	char buffer[PACKET_SIZE]; ///< Actual contents of the message.
-} ATTRPACK msg_t;
-
-#if defined(_MSC_VER)
-#pragma pack()
-#endif
+#ifdef MASTERSERVER
 
-typedef struct Copy_CVarMS_t
-{
-	char ip[64];
-	char port[8];
-	char name[64];
-} Copy_CVarMS_s;
-static Copy_CVarMS_s registered_server;
-static time_t MSLastPing;
-
-#if defined(_MSC_VER)
-#pragma pack(1)
-#endif
-typedef struct
-{
-	char ip[16];         // Big enough to hold a full address.
-	UINT16 port;
-	UINT8 padding1[2];
-	tic_t time;
-} ATTRPACK ms_holepunch_packet_t;
-#if defined(_MSC_VER)
-#pragma pack()
-#endif
+static int     MSId;
+static int     MSRegisteredId = -1;
 
-// win32 or djgpp
-#if defined (_WIN32) || defined (__DJGPP__)
-#define ioctl ioctlsocket
-#define close closesocket
-#ifdef WATTCP
-#define strerror strerror_s
-#endif
-#ifdef _WIN32
-#undef errno
-#define errno h_errno // some very strange things happen when not using h_error
-#endif
-#ifndef AI_ADDRCONFIG
-#define AI_ADDRCONFIG 0x00000400
-#endif
-#endif
+static boolean MSRegistered;
+static boolean MSInProgress;
+static boolean MSUpdateAgain;
+
+static time_t  MSLastPing;
+
+#ifdef HAVE_THREADS
+static I_mutex MSMutex;
+static I_cond  MSCond;
+
+#  define Lock_state()   I_lock_mutex  (&MSMutex)
+#  define Unlock_state() I_unlock_mutex (MSMutex)
+#else/*HAVE_THREADS*/
+#  define Lock_state()
+#  define Unlock_state()
+#endif/*HAVE_THREADS*/
 
 #ifndef NONET
 static void Command_Listserv_f(void);
 #endif
+
+#endif/*MASTERSERVER*/
+
+static void Update_parameters (void);
+
 static void MasterServer_OnChange(void);
-static void ServerName_OnChange(void);
 
-#define DEF_PORT "28900"
-consvar_t cv_masterserver = {"masterserver", "ms.srb2.org:"DEF_PORT, CV_SAVE, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_servername = {"servername", "SRB2 server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, ServerName_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
+	{2,  "MIN"},
+	{60, "MAX"},
+	{0,NULL}
+};
 
-INT16 ms_RoomId = -1;
+consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange);
+consvar_t cv_servername = CVAR_INIT ("servername", "SRB2 server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);
 
-static enum { MSCS_NONE, MSCS_WAITING, MSCS_REGISTERED, MSCS_FAILED } con_state = MSCS_NONE;
+consvar_t cv_masterserver_update_rate = CVAR_INIT ("masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters);
 
-static INT32 msnode = -1;
-UINT16 current_port = 0;
+INT16 ms_RoomId = -1;
 
-#if defined (_WIN32) && !defined (NONET)
-typedef SOCKET SOCKET_TYPE;
-#define ERRSOCKET (SOCKET_ERROR)
-#else
-#if (defined (__unix__) && !defined (MSDOS)) || defined (__APPLE__) || defined (__HAIKU__)
-typedef int SOCKET_TYPE;
-#else
-typedef unsigned long SOCKET_TYPE;
-#endif
-#define ERRSOCKET (-1)
-#endif
+#if defined (MASTERSERVER) && defined (HAVE_THREADS)
+int           ms_QueryId;
+I_mutex       ms_QueryId_mutex;
 
-#if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (_WIN32)
-typedef int socklen_t;
+msg_server_t *ms_ServerList;
+I_mutex       ms_ServerList_mutex;
 #endif
 
-#ifndef NONET
-static SOCKET_TYPE socket_fd = ERRSOCKET; // WINSOCK socket
-static struct timeval select_timeout;
-static fd_set wset;
-static size_t recvfull(SOCKET_TYPE s, char *buf, size_t len, int flags);
-#endif
+UINT16 current_port = 0;
 
 // Room list is an external variable now.
 // Avoiding having to get info ten thousand times...
@@ -222,417 +91,100 @@ void AddMServCommands(void)
 {
 #ifndef NONET
 	CV_RegisterVar(&cv_masterserver);
+	CV_RegisterVar(&cv_masterserver_update_rate);
+	CV_RegisterVar(&cv_masterserver_timeout);
+	CV_RegisterVar(&cv_masterserver_debug);
+	CV_RegisterVar(&cv_masterserver_token);
 	CV_RegisterVar(&cv_servername);
+#ifdef MASTERSERVER
 	COM_AddCommand("listserv", Command_Listserv_f);
 #endif
-}
-
-/** Closes the connection to the master server.
-  *
-  * \todo Fix for Windows?
-  */
-static void CloseConnection(void)
-{
-#ifndef NONET
-	if (socket_fd != (SOCKET_TYPE)ERRSOCKET)
-		close(socket_fd);
-	socket_fd = ERRSOCKET;
 #endif
 }
 
-//
-// MS_Write():
-//
-static INT32 MS_Write(msg_t *msg)
-{
-#ifdef NONET
-	(void)msg;
-	return MS_WRITE_ERROR;
-#else
-	size_t len;
-
-	if (msg->length == 0)
-		msg->length = (INT32)strlen(msg->buffer);
-	len = msg->length + HEADER_SIZE;
-
-	msg->type = htonl(msg->type);
-	msg->length = htonl(msg->length);
-	msg->room = htonl(msg->room);
-
-	if ((size_t)send(socket_fd, (char *)msg, (int)len, 0) != len)
-		return MS_WRITE_ERROR;
-	return 0;
-#endif
-}
-
-//
-// MS_Read():
-//
-static INT32 MS_Read(msg_t *msg)
-{
-#ifdef NONET
-	(void)msg;
-	return MS_READ_ERROR;
-#else
-	if (recvfull(socket_fd, (char *)msg, HEADER_SIZE, 0) != HEADER_SIZE)
-		return MS_READ_ERROR;
-
-	msg->type = ntohl(msg->type);
-	msg->length = ntohl(msg->length);
-	msg->room = ntohl(msg->room);
-
-	if (!msg->length) // fix a bug in Windows 2000
-		return 0;
-
-	if (recvfull(socket_fd, (char *)msg->buffer, msg->length, 0) != msg->length)
-		return MS_READ_ERROR;
-	return 0;
-#endif
-}
-
-#ifndef NONET
-/** Gets a list of game servers from the master server.
-  */
-static INT32 GetServersList(void)
-{
-	msg_t msg;
-	INT32 count = 0;
-
-	msg.type = GET_SERVER_MSG;
-	msg.length = 0;
-	msg.room = 0;
-	if (MS_Write(&msg) < 0)
-		return MS_WRITE_ERROR;
-
-	while (MS_Read(&msg) >= 0)
-	{
-		if (!msg.length)
-		{
-			if (!count)
-				CONS_Alert(CONS_NOTICE, M_GetText("No servers currently running.\n"));
-			return MS_NO_ERROR;
-		}
-		count++;
-		CONS_Printf("%s",msg.buffer);
-	}
-
-	return MS_READ_ERROR;
-}
-#endif
+#ifdef MASTERSERVER
 
-//
-// MS_Connect()
-//
-#ifndef NONET
-static INT32 MS_SubConnect(const char *ip_addr, const char *str_port, INT32 async, struct sockaddr *bindaddr, socklen_t bindaddrlen)
+static void WarnGUI (void)
 {
-	struct my_addrinfo *ai, *runp, hints;
-	int gaie;
-
-	memset (&hints, 0x00, sizeof(hints));
-#ifdef AI_ADDRCONFIG
-	hints.ai_flags = AI_ADDRCONFIG;
+#ifdef HAVE_THREADS
+	I_lock_mutex(&m_menu_mutex);
 #endif
-	hints.ai_family = AF_INET;
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_protocol = IPPROTO_TCP;
-
-	//I_InitTcpNetwork(); this is already done on startup in D_SRB2Main()
-	if (!I_InitTcpDriver()) // this is done only if not already done
-		return MS_SOCKET_ERROR;
-
-	gaie = I_getaddrinfo(ip_addr, str_port, &hints, &ai);
-	if (gaie != 0)
-		return MS_GETHOSTBYNAME_ERROR;
-	else
-		runp = ai;
-
-	while (runp != NULL)
-	{
-		socket_fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
-		if (socket_fd != (SOCKET_TYPE)ERRSOCKET)
-		{
-			if (!bindaddr || bind(socket_fd, bindaddr, bindaddrlen) == 0)
-			{
-				if (async) // do asynchronous connection
-				{
-#ifdef FIONBIO
-#ifdef WATTCP
-					char res = 1;
-#else
-					unsigned long res = 1;
-#endif
-
-					ioctl(socket_fd, FIONBIO, &res);
-#endif
-
-					if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) == ERRSOCKET)
-					{
-#ifdef _WIN32 // humm, on win32/win64 it doesn't work with EINPROGRESS (stupid windows)
-						if (WSAGetLastError() != WSAEWOULDBLOCK)
-#else
-							if (errno != EINPROGRESS)
-#endif
-							{
-								con_state = MSCS_FAILED;
-								CloseConnection();
-								I_freeaddrinfo(ai);
-								return MS_CONNECT_ERROR;
-							}
-					}
-					con_state = MSCS_WAITING;
-					FD_ZERO(&wset);
-					FD_SET(socket_fd, &wset);
-					select_timeout.tv_sec = 0, select_timeout.tv_usec = 0;
-					I_freeaddrinfo(ai);
-					return 0;
-				}
-				else if (connect(socket_fd, runp->ai_addr, (socklen_t)runp->ai_addrlen) != ERRSOCKET)
-				{
-					I_freeaddrinfo(ai);
-					return 0;
-				}
-			}
-			close(socket_fd);
-		}
-		runp = runp->ai_next;
-	}
-	I_freeaddrinfo(ai);
-	return MS_CONNECT_ERROR;
-}
-#endif/*NONET xd*/
-
-static INT32 MS_Connect(const char *ip_addr, const char *str_port, INT32 async)
-{
-#ifdef NONET
-	(void)ip_addr;
-	(void)str_port;
-	(void)async;
-	return MS_CONNECT_ERROR;
-#else
-	const char *lhost;
-	struct my_addrinfo hints;
-	struct my_addrinfo *ai, *aip;
-	int c;
-	if (M_CheckParm("-bindaddr") && ( lhost = M_GetNextParm() ))
-	{
-		memset (&hints, 0x00, sizeof(hints));
-#ifdef AI_ADDRCONFIG
-		hints.ai_flags = AI_ADDRCONFIG;
+	M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n\nCheck the console for details.\n"), NULL, MM_NOTHING);
+#ifdef HAVE_THREADS
+	I_unlock_mutex(m_menu_mutex);
 #endif
-		hints.ai_family = AF_INET;
-		hints.ai_socktype = SOCK_STREAM;
-		hints.ai_protocol = IPPROTO_TCP;
-		if (( c = I_getaddrinfo(lhost, 0, &hints, &ai) ) != 0)
-		{
-			CONS_Printf(
-					"mserv.c: bind to %s: %s\n",
-					lhost,
-					gai_strerror(c));
-			return MS_GETHOSTBYNAME_ERROR;
-		}
-		for (aip = ai; aip; aip = aip->ai_next)
-		{
-			c = MS_SubConnect(ip_addr, str_port, async, aip->ai_addr, aip->ai_addrlen);
-			if (c == 0)
-			{
-				I_freeaddrinfo(ai);
-				return 0;
-			}
-		}
-		I_freeaddrinfo(ai);
-		return c;
-	}
-	else
-		return MS_SubConnect(ip_addr, str_port, async, 0, 0);
-#endif/*NONET xd*/
 }
 
 #define NUM_LIST_SERVER MAXSERVERLIST
-const msg_server_t *GetShortServersList(INT32 room)
+msg_server_t *GetShortServersList(INT32 room, int id)
 {
-	static msg_server_t server_list[NUM_LIST_SERVER+1]; // +1 for easy test
-	msg_t msg;
-	INT32 i;
+	msg_server_t *server_list;
 
-	// we must be connected to the master server before writing to it
-	if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
-	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
-		return NULL;
-	}
-
-	msg.type = GET_SHORT_SERVER_MSG;
-	msg.length = 0;
-	msg.room = room;
-	if (MS_Write(&msg) < 0)
-		return NULL;
+	// +1 for easy test
+	server_list = malloc(( NUM_LIST_SERVER + 1 ) * sizeof *server_list);
 
-	for (i = 0; i < NUM_LIST_SERVER && MS_Read(&msg) >= 0; i++)
-	{
-		if (!msg.length)
-		{
-			server_list[i].header.buffer[0] = 0;
-			CloseConnection();
-			return server_list;
-		}
-		M_Memcpy(&server_list[i], msg.buffer, sizeof (msg_server_t));
-		server_list[i].header.buffer[0] = 1;
-	}
-	CloseConnection();
-	if (i == NUM_LIST_SERVER)
-	{
-		server_list[i].header.buffer[0] = 0;
+	if (HMS_fetch_servers(server_list, room, id))
 		return server_list;
-	}
 	else
+	{
+		free(server_list);
+		WarnGUI();
 		return NULL;
+	}
 }
 
-INT32 GetRoomsList(boolean hosting)
+INT32 GetRoomsList(boolean hosting, int id)
 {
-	static msg_ban_t banned_info[1];
-	msg_t msg;
-	INT32 i;
-
-	// we must be connected to the master server before writing to it
-	if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
-	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
-		return -1;
-	}
-
-	if (hosting)
-		msg.type = GET_ROOMS_HOST_MSG;
-	else
-		msg.type = GET_ROOMS_MSG;
-	msg.length = 0;
-	msg.room = 0;
-	if (MS_Write(&msg) < 0)
-	{
-		room_list[0].id = 1;
-		strcpy(room_list[0].motd,"Master Server Offline.");
-		strcpy(room_list[0].name,"Offline");
-		return -1;
-	}
-
-	for (i = 0; i < NUM_LIST_ROOMS && MS_Read(&msg) >= 0; i++)
-	{
-		if(msg.type == GET_BANNED_MSG)
-		{
-			char banmsg[1000];
-			M_Memcpy(&banned_info[0], msg.buffer, sizeof (msg_ban_t));
-			if (hosting)
-				sprintf(banmsg, M_GetText("You have been banned from\nhosting netgames.\n\nUnder the following IP Range:\n%s - %s\n\nFor the following reason:\n%s\n\nYour ban will expire on:\n%s"),banned_info[0].ipstart,banned_info[0].ipend,banned_info[0].reason,banned_info[0].endstamp);
-			else
-				sprintf(banmsg, M_GetText("You have been banned from\njoining netgames.\n\nUnder the following IP Range:\n%s - %s\n\nFor the following reason:\n%s\n\nYour ban will expire on:\n%s"),banned_info[0].ipstart,banned_info[0].ipend,banned_info[0].reason,banned_info[0].endstamp);
-			M_StartMessage(banmsg, NULL, MM_NOTHING);
-			ms_RoomId = -1;
-			return -2;
-		}
-		if (!msg.length)
-		{
-			room_list[i].header.buffer[0] = 0;
-			CloseConnection();
-			return 1;
-		}
-		M_Memcpy(&room_list[i], msg.buffer, sizeof (msg_rooms_t));
-		room_list[i].header.buffer[0] = 1;
-	}
-	CloseConnection();
-	if (i == NUM_LIST_ROOMS)
-	{
-		room_list[i].header.buffer[0] = 0;
+	if (HMS_fetch_rooms( ! hosting, id))
 		return 1;
-	}
 	else
 	{
-		room_list[0].id = 1;
-		strcpy(room_list[0].motd,M_GetText("Master Server Offline."));
-		strcpy(room_list[0].name,M_GetText("Offline"));
+		WarnGUI();
 		return -1;
 	}
 }
 
 #ifdef UPDATE_ALERT
-const char *GetMODVersion(void)
+char *GetMODVersion(int id)
 {
-	static msg_t msg;
+	char *buffer;
+	int c;
 
-	// we must be connected to the master server before writing to it
-	if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
-	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n"), NULL, MM_NOTHING);
-		return NULL;
-	}
+	(void)id;
+
+	buffer = malloc(16);
+
+	c = HMS_compare_mod_version(buffer, 16);
 
-	msg.type = GET_VERSION_MSG;
-	msg.length = sizeof MODVERSION;
-	msg.room = MODID; // Might as well use it for something.
-	sprintf(msg.buffer,"%d",MODVERSION);
-	if (MS_Write(&msg) < 0)
+#ifdef HAVE_THREADS
+	I_lock_mutex(&ms_QueryId_mutex);
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("Could not send to the Master Server\n"));
-		M_StartMessage(M_GetText("Could not send to the Master Server\n"), NULL, MM_NOTHING);
-		CloseConnection();
-		return NULL;
+		if (id != ms_QueryId)
+			c = -1;
 	}
+	I_unlock_mutex(ms_QueryId_mutex);
+#endif
 
-	if (MS_Read(&msg) < 0)
+	if (c > 0)
+		return buffer;
+	else
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("No reply from the Master Server\n"));
-		M_StartMessage(M_GetText("No reply from the Master Server\n"), NULL, MM_NOTHING);
-		CloseConnection();
-		return NULL;
-	}
+		free(buffer);
 
-	CloseConnection();
+		if (! c)
+			WarnGUI();
 
-	if(strcmp(msg.buffer,"NULL") != 0)
-	{
-		return msg.buffer;
-	}
-	else
 		return NULL;
+	}
 }
 
 // Console only version of the above (used before game init)
 void GetMODVersion_Console(void)
 {
-	static msg_t msg;
-
-	// we must be connected to the master server before writing to it
-	if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
-	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		return;
-	}
-
-	msg.type = GET_VERSION_MSG;
-	msg.length = sizeof MODVERSION;
-	msg.room = MODID; // Might as well use it for something.
-	sprintf(msg.buffer,"%d",MODVERSION);
-	if (MS_Write(&msg) < 0)
-	{
-		CONS_Alert(CONS_ERROR, M_GetText("Could not send to the Master Server\n"));
-		CloseConnection();
-		return;
-	}
+	char buffer[16];
 
-	if (MS_Read(&msg) < 0)
-	{
-		CONS_Alert(CONS_ERROR, M_GetText("No reply from the Master Server\n"));
-		CloseConnection();
-		return;
-	}
-
-	CloseConnection();
-
-	if(strcmp(msg.buffer,"NULL") != 0)
-		I_Error(UPDATE_ALERT_STRING_CONSOLE, VERSIONSTRING, msg.buffer);
+	if (HMS_compare_mod_version(buffer, sizeof buffer) > 0)
+		I_Error(UPDATE_ALERT_STRING_CONSOLE, VERSIONSTRING, buffer);
 }
 #endif
 
@@ -641,388 +193,359 @@ void GetMODVersion_Console(void)
   */
 static void Command_Listserv_f(void)
 {
-	if (con_state == MSCS_WAITING)
-	{
-		CONS_Alert(CONS_NOTICE, M_GetText("Not yet connected to the Master Server.\n"));
-		return;
-	}
-
 	CONS_Printf(M_GetText("Retrieving server list...\n"));
 
-	if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		return;
+		HMS_list_servers();
 	}
-
-	if (GetServersList())
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot get server list\n"));
-
-	CloseConnection();
 }
 #endif
 
-FUNCMATH static const char *int2str(INT32 n)
+static void
+Finish_registration (void)
 {
-	INT32 i;
-	static char res[16];
+	int registered;
 
-	res[15] = '\0';
-	res[14] = (char)((char)(n%10)+'0');
-	for (i = 13; (n /= 10); i--)
-		res[i] = (char)((char)(n%10)+'0');
+	CONS_Printf("Registering this server on the master server...\n");
 
-	return &res[i+1];
-}
+	registered = HMS_register();
 
-#ifndef NONET
-static INT32 ConnectionFailed(void)
-{
-	con_state = MSCS_FAILED;
-	CONS_Alert(CONS_ERROR, M_GetText("Connection to Master Server failed\n"));
-	CloseConnection();
-	return MS_CONNECT_ERROR;
+	Lock_state();
+	{
+		MSRegistered = registered;
+		MSRegisteredId = MSId;
+
+		time(&MSLastPing);
+	}
+	Unlock_state();
+
+	if (registered)
+		CONS_Printf("Master server registration successful.\n");
 }
-#endif
 
-/** Tries to register the local game server on the master server.
-  */
-static INT32 AddToMasterServer(boolean firstadd)
+static void
+Finish_update (void)
 {
-#ifdef NONET
-	(void)firstadd;
-#else
-	static INT32 retry = 0;
-	int i, res;
-	socklen_t j;
-	msg_t msg;
-	msg_server_t *info = (msg_server_t *)msg.buffer;
-	INT32 room = -1;
-	fd_set tset;
-	time_t timestamp = time(NULL);
-	UINT32 signature, tmp;
-	const char *insname;
-
-	M_Memcpy(&tset, &wset, sizeof (tset));
-	res = select(255, NULL, &tset, NULL, &select_timeout);
-	if (res != ERRSOCKET && !res)
+	int registered;
+	int done;
+
+	Lock_state();
 	{
-		if (retry++ > 30) // an about 30 second timeout
-		{
-			retry = 0;
-			CONS_Alert(CONS_ERROR, M_GetText("Master Server timed out\n"));
-			MSLastPing = timestamp;
-			return ConnectionFailed();
-		}
-		return MS_CONNECT_ERROR;
+		registered = MSRegistered;
+		MSUpdateAgain = false;/* this will happen anyway */
 	}
-	retry = 0;
-	if (res == ERRSOCKET)
+	Unlock_state();
+
+	if (registered)
 	{
-		if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0))
+		if (HMS_update())
 		{
-			CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
-			MSLastPing = timestamp;
-			return ConnectionFailed();
+			Lock_state();
+			{
+				time(&MSLastPing);
+				MSRegistered = true;
+			}
+			Unlock_state();
+
+			CONS_Printf("Updated master server listing.\n");
 		}
+		else
+			Finish_registration();
 	}
+	else
+		Finish_registration();
 
-	// so, the socket is writable, but what does that mean, that the connection is
-	// ok, or bad... let see that!
-	j = (socklen_t)sizeof (i);
-	getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (char *)&i, &j);
-	if (i) // it was bad
+	Lock_state();
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("Master Server socket error #%u: %s\n"), errno, strerror(errno));
-		MSLastPing = timestamp;
-		return ConnectionFailed();
+		done = ! MSUpdateAgain;
+
+		if (done)
+			MSInProgress = false;
 	}
+	Unlock_state();
 
-#ifdef PARANOIA
-	if (ms_RoomId <= 0)
-		I_Error("Attmepted to host in room \"All\"!\n");
-#endif
-	room = ms_RoomId;
-
-	for(signature = 0, insname = cv_servername.string; *insname; signature += *insname++);
-	tmp = (UINT32)(signature * (size_t)&MSLastPing);
-	signature *= tmp;
-	signature &= 0xAAAAAAAA;
-	M_Memcpy(&info->header.signature, &signature, sizeof (UINT32));
-
-	strcpy(info->ip, "");
-	strcpy(info->port, int2str(current_port));
-	strcpy(info->name, cv_servername.string);
-	M_Memcpy(&info->room, & room, sizeof (INT32));
-#ifndef DEVELOP
-	strcpy(info->version, SRB2VERSION);
-#else // Trunk build, send revision info
-	strcpy(info->version, GetRevisionString());
-#endif
-	strcpy(registered_server.name, cv_servername.string);
+	if (! done)
+		Finish_update();
+}
 
-	if(firstadd)
-		msg.type = ADD_SERVER_MSG;
-	else
-		msg.type = PING_SERVER_MSG;
+static void
+Finish_unlist (void)
+{
+	int registered;
 
-	msg.length = (UINT32)sizeof (msg_server_t);
-	msg.room = 0;
-	if (MS_Write(&msg) < 0)
+	Lock_state();
 	{
-		MSLastPing = timestamp;
-		return ConnectionFailed();
+		registered = MSRegistered;
 	}
+	Unlock_state();
 
-	if(con_state != MSCS_REGISTERED)
-		CONS_Printf(M_GetText("Master Server update successful.\n"));
+	if (registered)
+	{
+		CONS_Printf("Removing this server from the master server...\n");
 
-	MSLastPing = timestamp;
-	con_state = MSCS_REGISTERED;
-	CloseConnection();
+		if (HMS_unlist())
+			CONS_Printf("Server deregistration request successfully sent.\n");
+
+		Lock_state();
+		{
+			MSRegistered = false;
+		}
+		Unlock_state();
+
+#ifdef HAVE_THREADS
+		I_wake_all_cond(&MSCond);
 #endif
-	return MS_NO_ERROR;
+	}
+
+	Lock_state();
+	{
+		if (MSId == MSRegisteredId)
+			MSId++;
+	}
+	Unlock_state();
 }
 
-static INT32 RemoveFromMasterSever(void)
+#ifdef HAVE_THREADS
+static int *
+Server_id (void)
 {
-	msg_t msg;
-	msg_server_t *info = (msg_server_t *)msg.buffer;
-
-	strcpy(info->header.buffer, "");
-	strcpy(info->ip, "");
-	strcpy(info->port, int2str(current_port));
-	strcpy(info->name, registered_server.name);
-	sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION);
-
-	msg.type = REMOVE_SERVER_MSG;
-	msg.length = (UINT32)sizeof (msg_server_t);
-	msg.room = 0;
-	if (MS_Write(&msg) < 0)
-		return MS_WRITE_ERROR;
-
-	return MS_NO_ERROR;
+	int *id;
+	id = malloc(sizeof *id);
+	Lock_state();
+	{
+		*id = MSId;
+	}
+	Unlock_state();
+	return id;
 }
 
-const char *GetMasterServerPort(void)
+static int *
+New_server_id (void)
 {
-	const char *t = cv_masterserver.string;
-
-	while ((*t != ':') && (*t != '\0'))
-		t++;
-
-	if (*t)
-		return ++t;
-	else
-		return DEF_PORT;
+	int *id;
+	id = malloc(sizeof *id);
+	Lock_state();
+	{
+		*id = ++MSId;
+		I_wake_all_cond(&MSCond);
+	}
+	Unlock_state();
+	return id;
 }
 
-/** Gets the IP address of the master server. Actually, it seems to just
-  * return the hostname, instead; the lookup is done elsewhere.
-  *
-  * \return Hostname of the master server, without port number on the end.
-  * \todo Rename function?
-  */
-const char *GetMasterServerIP(void)
+static void
+Register_server_thread (int *id)
 {
-	static char str_ip[64];
-	char *t = str_ip;
+	int same;
 
-	if (strstr(cv_masterserver.string, "srb2.ssntails.org:28910")
-	 || strstr(cv_masterserver.string, "srb2.servegame.org:28910")
-	 || strstr(cv_masterserver.string, "srb2.servegame.org:28900")
-	   )
+	Lock_state();
 	{
-		// replace it with the current default one
-		CV_Set(&cv_masterserver, cv_masterserver.defaultvalue);
-	}
+		/* wait for previous unlist to finish */
+		while (*id == MSId && MSRegistered)
+			I_hold_cond(&MSCond, MSMutex);
 
-	strcpy(t, cv_masterserver.string);
+		same = ( *id == MSId );/* it could have been a while */
+	}
+	Unlock_state();
 
-	while ((*t != ':') && (*t != '\0'))
-		t++;
-	*t = '\0';
+	if (same)/* it could have been a while */
+		Finish_registration();
 
-	return str_ip;
+	free(id);
 }
 
-void MSOpenUDPSocket(void)
+static void
+Update_server_thread (int *id)
 {
-#ifndef NONET
-	if (I_NetMakeNodewPort)
+	int same;
+
+	Lock_state();
 	{
-		// If it's already open, there's nothing to do.
-		if (msnode < 0)
-			msnode = I_NetMakeNodewPort(GetMasterServerIP(), GetMasterServerPort());
+		same = ( *id == MSRegisteredId );
 	}
-	else
-#endif
-		msnode = -1;
-}
+	Unlock_state();
 
-void MSCloseUDPSocket(void)
-{
-	if (msnode != INT16_MAX) I_NetFreeNodenum(msnode);
-	msnode = -1;
+	if (same)
+		Finish_update();
+
+	free(id);
 }
 
-void RegisterServer(void)
+static void
+Unlist_server_thread (int *id)
 {
-	if (con_state == MSCS_REGISTERED || con_state == MSCS_WAITING)
-			return;
-
-	CONS_Printf(M_GetText("Registering this server on the Master Server...\n"));
-
-	strcpy(registered_server.ip, GetMasterServerIP());
-	strcpy(registered_server.port, GetMasterServerPort());
+	int same;
 
-	if (MS_Connect(registered_server.ip, registered_server.port, 1))
+	Lock_state();
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		return;
+		same = ( *id == MSRegisteredId );
 	}
-	MSOpenUDPSocket();
+	Unlock_state();
 
-	// keep the TCP connection open until AddToMasterServer() is completed;
+	if (same)
+		Finish_unlist();
+
+	free(id);
 }
 
-static inline void SendPingToMasterServer(void)
+static void
+Change_masterserver_thread (char *api)
 {
-/*	static tic_t next_time = 0;
-	tic_t cur_time;
-	char *inbuffer = (char*)netbuffer;
-
-	cur_time = I_GetTime();
-	if (!netgame)
-		UnregisterServer();
-	else if (cur_time > next_time) // ping every 2 second if possible
+	Lock_state();
 	{
-		next_time = cur_time+2*TICRATE;
-
-		if (con_state == MSCS_WAITING)
-			AddToMasterServer();
-
-		if (con_state != MSCS_REGISTERED)
-			return;
-
-		// cur_time is just a dummy data to send
-		WRITEUINT32(inbuffer, cur_time);
-		doomcom->datalength = sizeof (cur_time);
-		doomcom->remotenode = (INT16)msnode;
-		I_NetSend();
+		while (MSRegistered)
+			I_hold_cond(&MSCond, MSMutex);
 	}
-*/
+	Unlock_state();
 
-// Here, have a simpler MS Ping... - Cue
-	if(time(NULL) > (MSLastPing+(60*2)) && con_state != MSCS_NONE)
-	{
-		//CONS_Debug(DBG_NETPLAY, "%ld (current time) is greater than %d (Last Ping Time)\n", time(NULL), MSLastPing);
-		if(MSLastPing < 1)
-			AddToMasterServer(true);
-		else
-			AddToMasterServer(false);
-	}
+	HMS_set_api(api);
+}
+#endif/*HAVE_THREADS*/
+
+void RegisterServer(void)
+{
+#ifdef MASTERSERVER
+#ifdef HAVE_THREADS
+	I_spawn_thread(
+			"register-server",
+			(I_thread_fn)Register_server_thread,
+			New_server_id()
+	);
+#else
+	Finish_registration();
+#endif
+#endif/*MASTERSERVER*/
 }
 
-void SendAskInfoViaMS(INT32 node, tic_t asktime)
+static void UpdateServer(void)
 {
-	const char *address;
-	UINT16 port;
-	char *inip;
-	ms_holepunch_packet_t mshpp;
-
-	MSOpenUDPSocket();
-
-	// This must be called after calling MSOpenUDPSocket, due to the
-	// static buffer.
-	address = I_GetNodeAddress(node);
-
-	// no address?
-	if (!address)
-		return;
-
-	// Copy the IP address into the buffer.
-	inip = mshpp.ip;
-	while(*address && *address != ':') *inip++ = *address++;
-	*inip = '\0';
-
-	// Get the port.
-	port = (UINT16)(*address++ ? atoi(address) : 0);
-	mshpp.port = SHORT(port);
-
-	// Set the time for ping calculation.
-	mshpp.time = LONG(asktime);
-
-	// Send to the MS.
-	M_Memcpy(netbuffer, &mshpp, sizeof(mshpp));
-	doomcom->datalength = sizeof(ms_holepunch_packet_t);
-	doomcom->remotenode = (INT16)msnode;
-	I_NetSend();
+#ifdef HAVE_THREADS
+	I_spawn_thread(
+			"update-server",
+			(I_thread_fn)Update_server_thread,
+			Server_id()
+	);
+#else
+	Finish_update();
+#endif
 }
 
 void UnregisterServer(void)
 {
-	if (con_state != MSCS_REGISTERED)
-	{
-		con_state = MSCS_NONE;
-		CloseConnection();
-		return;
-	}
+#ifdef MASTERSERVER
+#ifdef HAVE_THREADS
+	I_spawn_thread(
+			"unlist-server",
+			(I_thread_fn)Unlist_server_thread,
+			Server_id()
+	);
+#else
+	Finish_unlist();
+#endif
+#endif/*MASTERSERVER*/
+}
 
-	con_state = MSCS_NONE;
+static boolean
+Online (void)
+{
+	return ( serverrunning && ms_RoomId > 0 );
+}
 
-	CONS_Printf(M_GetText("Removing this server from the Master Server...\n"));
+static inline void SendPingToMasterServer(void)
+{
+	int ready;
+	time_t now;
 
-	if (MS_Connect(registered_server.ip, registered_server.port, 0))
+	if (Online())
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n"));
-		return;
-	}
+		time(&now);
 
-	if (RemoveFromMasterSever() < 0)
-		CONS_Alert(CONS_ERROR, M_GetText("Cannot remove this server from the Master Server\n"));
+		Lock_state();
+		{
+			ready = (
+					MSRegisteredId == MSId &&
+					! MSInProgress &&
+					now >= ( MSLastPing + 60 * cv_masterserver_update_rate.value )
+			);
+
+			if (ready)
+				MSInProgress = true;
+		}
+		Unlock_state();
 
-	CloseConnection();
-	MSCloseUDPSocket();
-	MSLastPing = 0;
+		if (ready)
+			UpdateServer();
+	}
 }
 
 void MasterClient_Ticker(void)
 {
-	if (server && ms_RoomId > 0)
-		SendPingToMasterServer();
+#ifdef MASTERSERVER
+	SendPingToMasterServer();
+#endif
 }
 
-static void ServerName_OnChange(void)
+static void
+Set_api (const char *api)
 {
-	if (con_state == MSCS_REGISTERED)
-		AddToMasterServer(false);
+#ifdef HAVE_THREADS
+	I_spawn_thread(
+			"change-masterserver",
+			(I_thread_fn)Change_masterserver_thread,
+			strdup(api)
+	);
+#else
+	HMS_set_api(strdup(api));
+#endif
 }
 
-static void MasterServer_OnChange(void)
-{
-	UnregisterServer();
-	RegisterServer();
-}
+#endif/*MASTERSERVER*/
 
-#ifndef NONET
-// Like recv, but waits until we've got enough data to fill the buffer.
-static size_t recvfull(SOCKET_TYPE s, char *buf, size_t len, int flags)
+static void
+Update_parameters (void)
 {
-	/* Total received. */
-	size_t totallen = 0;
+#ifdef MASTERSERVER
+	int registered;
+	int delayed;
 
-	while(totallen < len)
+	if (Online())
 	{
-		ssize_t ret = (ssize_t)recv(s, buf + totallen, (int)(len - totallen), flags);
+		Lock_state();
+		{
+			delayed = MSInProgress;
 
-		/* Error. */
-		if(ret == -1)
-			return (size_t)-1;
+			if (delayed)/* do another update after the current one */
+				MSUpdateAgain = true;
+			else
+				registered = MSRegistered;
+		}
+		Unlock_state();
 
-		totallen += ret;
+		if (! delayed && registered)
+			UpdateServer();
 	}
+#endif/*MASTERSERVER*/
+}
 
-	return totallen;
+static void MasterServer_OnChange(void)
+{
+#ifdef MASTERSERVER
+	UnregisterServer();
+
+	/*
+	TODO: remove this for v2, it's just a hack
+	for those coming in with an old config.
+	*/
+	if (
+			! cv_masterserver.changed &&
+			strcmp(cv_masterserver.string, "ms.srb2.org:28900") == 0
+	){
+		CV_StealthSet(&cv_masterserver, cv_masterserver.defaultvalue);
+	}
+
+	Set_api(cv_masterserver.string);
+
+	if (Online())
+		RegisterServer();
+#endif/*MASTERSERVER*/
 }
-#endif
diff --git a/src/mserv.h b/src/mserv.h
index 5f9b8da5f430f5cbc384ba3497de3845fcb5c8b6..d0d5e49dfe9519fa5d0f1c2904fd0f2849e50100 100644
--- a/src/mserv.h
+++ b/src/mserv.h
@@ -2,6 +2,7 @@
 //-----------------------------------------------------------------------------
 // Copyright (C) 1998-2000 by DooM Legacy Team.
 // Copyright (C) 1999-2020 by Sonic Team Junior.
+// Copyright (C)      2020 by James R.
 //
 // This program is free software distributed under the
 // terms of the GNU General Public License, version 2.
@@ -13,7 +14,7 @@
 #ifndef _MSERV_H_
 #define _MSERV_H_
 
-#define MASTERSERVERS21 // MasterServer v2.1
+#include "i_threads.h"
 
 // lowered from 32 due to menu changes
 #define NUM_LIST_ROOMS 16
@@ -64,33 +65,47 @@ typedef struct
 // ================================ GLOBALS ===============================
 
 extern consvar_t cv_masterserver, cv_servername;
+extern consvar_t cv_masterserver_update_rate;
+extern consvar_t cv_masterserver_timeout;
+extern consvar_t cv_masterserver_debug;
+extern consvar_t cv_masterserver_token;
 
 // < 0 to not connect (usually -1) (offline mode)
 // == 0 to show all rooms, not a valid hosting room
 // anything else is whatever room the MS assigns to that number (online mode)
 extern INT16 ms_RoomId;
 
-const char *GetMasterServerPort(void);
-const char *GetMasterServerIP(void);
+#ifdef HAVE_THREADS
+extern int           ms_QueryId;
+extern I_mutex       ms_QueryId_mutex;
 
-void MSOpenUDPSocket(void);
-void MSCloseUDPSocket(void);
-
-void SendAskInfoViaMS(INT32 node, tic_t asktime);
+extern msg_server_t *ms_ServerList;
+extern I_mutex       ms_ServerList_mutex;
+#endif
 
 void RegisterServer(void);
 void UnregisterServer(void);
 
 void MasterClient_Ticker(void);
 
-const msg_server_t *GetShortServersList(INT32 room);
-INT32 GetRoomsList(boolean hosting);
+msg_server_t *GetShortServersList(INT32 room, int id);
+INT32 GetRoomsList(boolean hosting, int id);
 #ifdef UPDATE_ALERT
-const char *GetMODVersion(void);
+char *GetMODVersion(int id);
 void GetMODVersion_Console(void);
 #endif
 extern msg_rooms_t room_list[NUM_LIST_ROOMS+1];
 
 void AddMServCommands(void);
 
+/* HTTP */
+void HMS_set_api (char *api);
+int  HMS_fetch_rooms (int joining, int id);
+int  HMS_register (void);
+int  HMS_unlist (void);
+int  HMS_update (void);
+void HMS_list_servers (void);
+msg_server_t * HMS_fetch_servers (msg_server_t *list, int room, int id);
+int  HMS_compare_mod_version (char *buffer, size_t size_of_buffer);
+
 #endif
diff --git a/src/p_enemy.c b/src/p_enemy.c
index fd30f8e38a54924284776da4b7a11cba46612e50..ddb01b63ba4fdb2a0fa7ea1cc524a4f531f1b5d8 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -3040,11 +3040,11 @@ void A_Boss1Laser(mobj_t *actor)
 				z = actor->z + FixedMul(56*FRACUNIT, actor->scale);
 			break;
 		case 2:
-			var2 = 3; // Fire middle laser
+			var1 = locvar1; var2 = 3; // Fire middle laser
 			A_Boss1Laser(actor);
-			var2 = 0; // Fire left laser
+			var1 = locvar1; var2 = 0; // Fire left laser
 			A_Boss1Laser(actor);
-			var2 = 1; // Fire right laser
+			var1 = locvar1; var2 = 1; // Fire right laser
 			A_Boss1Laser(actor);
 			return;
 			break;
@@ -8839,25 +8839,26 @@ void A_Dye(mobj_t *actor)
 	INT32 locvar2 = var2;
 
 	mobj_t *target = ((locvar1 && actor->target) ? actor->target : actor);
-	UINT8 color = (UINT8)locvar2;
+	UINT16 color = (UINT16)locvar2;
 	if (LUA_CallAction("A_Dye", actor))
 		return;
 	if (color >= numskincolors)
 		return;
 
-	if (!color)
-		target->colorized = false;
-	else
-		target->colorized = true;
-
 	// What if it's a player?
 	if (target->player)
-	{
 		target->player->powers[pw_dye] = color;
-		return;
-	}
 
-	target->color = color;
+	if (!color)
+	{
+		target->colorized = false;
+		target->color = target->player ? target->player->skincolor : SKINCOLOR_NONE;
+	}
+	else if (!(target->player))
+	{
+		target->colorized = true;
+		target->color = color;
+	}
 }
 
 // Function: A_MoveRelative
diff --git a/src/p_local.h b/src/p_local.h
index 4077fecf6b36c2aa880b6d6cfa7c3ab546682377..cf3a66e9dc30d68ca3745845be5d57f1e7e19c9b 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -274,6 +274,8 @@ extern tic_t itemrespawntime[ITEMQUESIZE];
 extern size_t iquehead, iquetail;
 extern consvar_t cv_gravity, cv_movebob;
 
+mobjtype_t P_GetMobjtype(UINT16 mthingtype);
+
 void P_RespawnSpecials(void);
 
 mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
diff --git a/src/p_map.c b/src/p_map.c
index f7db52f6a0353a73d8b149de2f4bb8f6774816a2..74c2790f754b961442f8614fa0832f53aa55da84 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -380,7 +380,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		if ((spring->info->painchance == 3))
 		{
 			if (!(pflags = (object->player->pflags & PF_SPINNING)) &&
-				(((object->player->charability2 == CA2_SPINDASH) && (object->player->cmd.buttons & BT_USE))
+				(((object->player->charability2 == CA2_SPINDASH) && (object->player->cmd.buttons & BT_SPIN))
 				|| (spring->flags2 & MF2_AMBUSH)))
 			{
 				pflags = PF_SPINNING;
diff --git a/src/p_mobj.c b/src/p_mobj.c
index fcba1f690d58e115de9b1c5c5305c6d2a3afc2c7..de4385fa7d6618cf72dc7fc2aa53f1c590d41019 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -36,10 +36,10 @@
 #include "m_cond.h"
 
 static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
-consvar_t cv_movebob = {"movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);
 
 #ifdef WALLSPLATS
-consvar_t cv_splats = {"splats", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_splats = CVAR_INIT ("splats", "On", CV_SAVE, CV_OnOff, NULL);
 #endif
 
 actioncache_t actioncachehead;
@@ -4194,7 +4194,7 @@ boolean P_SupermanLook4Players(mobj_t *actor)
 
 	for (c = 0; c < MAXPLAYERS; c++)
 	{
-		if (playeringame[c])
+		if (playeringame[c] && !players[c].spectator)
 		{
 			if (players[c].pflags & PF_INVIS)
 				continue; // ignore notarget
@@ -11047,10 +11047,10 @@ void P_RemoveSavegameMobj(mobj_t *mobj)
 }
 
 static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
-consvar_t cv_itemrespawntime = {"respawnitemtime", "30", CV_NETVAR|CV_CHEAT, respawnitemtime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_itemrespawn = {"respawnitem", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_itemrespawntime = CVAR_INIT ("respawnitemtime", "30", CV_NETVAR|CV_CHEAT, respawnitemtime_cons_t, NULL);
+consvar_t cv_itemrespawn = CVAR_INIT ("respawnitem", "On", CV_NETVAR, CV_OnOff, NULL);
 static CV_PossibleValue_t flagtime_cons_t[] = {{0, "MIN"}, {300, "MAX"}, {0, NULL}};
-consvar_t cv_flagtime = {"flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_flagtime = CVAR_INIT ("flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, NULL);
 
 void P_SpawnPrecipitation(void)
 {
@@ -11249,7 +11249,7 @@ void P_PrecipitationEffects(void)
  * \param mthingtype Mapthing number in question.
  * \return Mobj type; MT_UNKNOWN if nothing found.
  */
-static mobjtype_t P_GetMobjtype(UINT16 mthingtype)
+mobjtype_t P_GetMobjtype(UINT16 mthingtype)
 {
 	mobjtype_t i;
 	for (i = 0; i < NUMMOBJTYPES; i++)
diff --git a/src/p_setup.c b/src/p_setup.c
index ef1ae9eba4f066007e1f5846b8c941a569fce450..10bfd08bed957aad913034aec1c0c41dd9062cc0 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -4176,9 +4176,6 @@ boolean P_LoadLevel(boolean fromnetsave)
 	// clear special respawning que
 	iquehead = iquetail = 0;
 
-	// Fab : 19-07-98 : start cd music for this level (note: can be remapped)
-	I_PlayCD((UINT8)(gamemap), false);
-
 	P_MapEnd();
 
 	// Remove the loading shit from the screen
@@ -4265,6 +4262,10 @@ void HWR_LoadLevel(void)
 #endif
 
 	HWR_CreatePlanePolygons((INT32)numnodes - 1);
+
+	// Build the sky dome
+	HWR_ClearSkyDome();
+	HWR_BuildSkyDome();
 }
 #endif
 
diff --git a/src/p_spec.c b/src/p_spec.c
index b045ad010f79b08a2ef79ce2abef158ab3b3b80d..7a79bd494f951e8a0befbf2812a23b2326200624 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1934,7 +1934,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
 		case 336: // object dye - once
 			{
 				INT32 triggercolor = (INT32)sides[triggerline->sidenum[0]].toptexture;
-				UINT8 color = (actor->player ? actor->player->powers[pw_dye] : actor->color);
+				UINT16 color = (actor->player ? actor->player->powers[pw_dye] : actor->color);
 				boolean invert = (triggerline->flags & ML_NOCLIMB ? true : false);
 
 				if (invert ^ (triggercolor != color))
@@ -4395,7 +4395,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
 	// Ignore dead players.
 	// If this strange phenomenon could be potentially used in levels,
 	// TODO: modify this to accommodate for it.
-	if (player->playerstate == PST_DEAD)
+	if (player->playerstate != PST_LIVE)
 		return;
 
 	// Conveyor stuff
@@ -5020,7 +5020,7 @@ DoneSection2:
 				if (player->mo->momz > 0)
 					break;
 
-				if (player->cmd.buttons & BT_USE)
+				if (player->cmd.buttons & BT_SPIN)
 					break;
 
 				if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate])
diff --git a/src/p_user.c b/src/p_user.c
index 44793b0cc1074684361c9bdccc3bc04ecb45cecf..7bc45bfc43eae2d928f15733b526d00103b45994 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -665,7 +665,7 @@ static void P_DeNightserizePlayer(player_t *player)
 	player->powers[pw_carry] = CR_NIGHTSFALL;
 
 	player->powers[pw_underwater] = 0;
-	player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
+	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
 	player->secondjump = 0;
 	player->homing = 0;
 	player->climbing = 0;
@@ -795,7 +795,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		}
 	}
 
-	player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
+	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
 	player->homing = 0;
 	player->mo->fuse = 0;
 	player->speed = 0;
@@ -2303,7 +2303,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 		if (dorollstuff)
 		{
 			if ((player->charability2 == CA2_SPINDASH) && !((player->pflags & (PF_SPINNING|PF_THOKKED)) == PF_THOKKED) && !(player->charability == CA_THOK && player->secondjump)
-			&& (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
+			&& (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
 				player->pflags = (player->pflags|PF_SPINNING) & ~PF_THOKKED;
 			else if (!(player->pflags & PF_STARTDASH))
 				player->pflags &= ~PF_SPINNING;
@@ -2368,7 +2368,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 				}
 			}
 			else if (player->charability2 == CA2_MELEE
-				&& ((player->panim == PA_ABILITY2) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY && player->cmd.buttons & (BT_JUMP|BT_USE))))
+				&& ((player->panim == PA_ABILITY2) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY && player->cmd.buttons & (BT_JUMP|BT_SPIN))))
 			{
 				if (player->mo->state-states != S_PLAY_MELEE_LANDING)
 				{
@@ -3576,7 +3576,7 @@ static void P_DoClimbing(player_t *player)
 	else if ((!(player->mo->momx || player->mo->momy || player->mo->momz) || !climb) && player->mo->state-states != S_PLAY_CLING)
 		P_SetPlayerMobjState(player->mo, S_PLAY_CLING);
 
-	if (cmd->buttons & BT_USE && !(player->pflags & PF_JUMPSTASIS))
+	if (cmd->buttons & BT_SPIN && !(player->pflags & PF_JUMPSTASIS))
 	{
 		player->climbing = 0;
 		player->pflags |= P_GetJumpFlags(player);
@@ -4574,7 +4574,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 		&& (player->pflags & PF_JUMPSTASIS || player->mo->state-states != S_PLAY_GLIDE_LANDING))
 		return;
 
-	if (cmd->buttons & BT_USE)
+	if (cmd->buttons & BT_SPIN)
 	{
 		if (LUAh_SpinSpecial(player))
 			return;
@@ -4591,20 +4591,20 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 		{
 			case CA2_SPINDASH: // Spinning and Spindashing
 				 // Start revving
-				if ((cmd->buttons & BT_USE) && (player->speed < FixedMul(5<<FRACBITS, player->mo->scale) || player->mo->state - states == S_PLAY_GLIDE_LANDING)
-					&& !player->mo->momz && onground && !(player->pflags & (PF_USEDOWN|PF_SPINNING))
+				if ((cmd->buttons & BT_SPIN) && (player->speed < FixedMul(5<<FRACBITS, player->mo->scale) || player->mo->state - states == S_PLAY_GLIDE_LANDING)
+					&& !player->mo->momz && onground && !(player->pflags & (PF_SPINDOWN|PF_SPINNING))
 						&& canstand)
 				{
 					player->mo->momx = player->cmomx;
 					player->mo->momy = player->cmomy;
-					player->pflags |= (PF_USEDOWN|PF_STARTDASH|PF_SPINNING);
+					player->pflags |= (PF_SPINDOWN|PF_STARTDASH|PF_SPINNING);
 					player->dashspeed = player->mindash;
 					P_SetPlayerMobjState(player->mo, S_PLAY_SPINDASH);
 					if (!player->spectator)
 						S_StartSound(player->mo, sfx_spndsh); // Make the rev sound!
 				}
 				 // Revving
-				else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH))
+				else if ((cmd->buttons & BT_SPIN) && (player->pflags & PF_STARTDASH))
 				{
 					if (player->speed > 5*player->mo->scale)
 					{
@@ -4637,18 +4637,18 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 				// If not moving up or down, and travelling faster than a speed of five while not holding
 				// down the spin button and not spinning.
 				// AKA Just go into a spin on the ground, you idiot. ;)
-				else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
+				else if ((cmd->buttons & BT_SPIN || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
 					&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
-						|| !canstand) && !(player->pflags & (PF_USEDOWN|PF_SPINNING)))
+						|| !canstand) && !(player->pflags & (PF_SPINDOWN|PF_SPINNING)))
 				{
-					player->pflags |= (PF_USEDOWN|PF_SPINNING);
+					player->pflags |= (PF_SPINDOWN|PF_SPINNING);
 					P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
 					if (!player->spectator)
 						S_StartSound(player->mo, sfx_spin);
 				}
 				else
 				// Catapult the player from a spindash rev!
-				if (onground && !(player->pflags & PF_USEDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
+				if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
 				{
 					player->pflags &= ~PF_STARTDASH;
 					if (player->powers[pw_carry] == CR_BRAKGOOP)
@@ -4690,7 +4690,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 								P_SetTarget(&visual->target, lockon);
 							}
 						}
-						if ((cmd->buttons & BT_USE) && !(player->pflags & PF_USEDOWN))
+						if ((cmd->buttons & BT_SPIN) && !(player->pflags & PF_SPINDOWN))
 						{
 							mobj_t *bullet;
 
@@ -4719,15 +4719,15 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 
 							player->mo->momx >>= 1;
 							player->mo->momy >>= 1;
-							player->pflags |= PF_USEDOWN;
+							player->pflags |= PF_SPINDOWN;
 							P_SetWeaponDelay(player, TICRATE/2);
 						}
 					}
 				}
 				break;
 			case CA2_MELEE: // Melee attack
-				if (player->panim != PA_ABILITY2 && (cmd->buttons & BT_USE)
-				&& !player->mo->momz && onground && !(player->pflags & PF_USEDOWN)
+				if (player->panim != PA_ABILITY2 && (cmd->buttons & BT_SPIN)
+				&& !player->mo->momz && onground && !(player->pflags & PF_SPINDOWN)
 				&& canstand)
 				{
 					P_ResetPlayer(player);
@@ -4767,7 +4767,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 						P_SetPlayerMobjState(player->mo, S_PLAY_MELEE);
 						S_StartSound(player->mo, sfx_s3k42);
 					}
-					player->pflags |= PF_USEDOWN;
+					player->pflags |= PF_SPINDOWN;
 				}
 				break;
 		}
@@ -5040,8 +5040,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 			;
 		else if (player->pflags & (PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player has used an ability previously
 			;
-		else if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_USEDOWN)
-			&& ((!(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX)))) // thokked is optional if you're bubblewrapped
+		else if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN)
+			&& ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted
 		{
 			if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)
 			{
@@ -5066,7 +5066,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 					}
 				}
 			}
-			if (cmd->buttons & BT_USE && !LUAh_ShieldSpecial(player)) // Spin button effects
+			if (cmd->buttons & BT_SPIN && !LUAh_ShieldSpecial(player)) // Spin button effects
 			{
 				// Force stop
 				if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
@@ -5093,6 +5093,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 						case SH_ATTRACT:
 							player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
 							player->homing = 2;
+							player->secondjump = 0;
 							P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonshield));
 							if (lockonshield)
 								{
@@ -5140,9 +5141,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 				}
 			}
 		}
-		else if ((cmd->buttons & BT_USE))
+		else if ((cmd->buttons & BT_SPIN))
 		{
-			if (!(player->pflags & PF_USEDOWN) && P_SuperReady(player))
+			if (!(player->pflags & PF_SPINDOWN) && P_SuperReady(player))
 			{
 				// If you can turn super and aren't already,
 				// and you don't have a shield, do it!
@@ -5172,7 +5173,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 						}
 						break;
 					case CA_TELEKINESIS:
-						if (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || (player->charflags & SF_MULTIABILITY))
+						if (!(player->pflags & (PF_THOKKED|PF_SPINDOWN)) || (player->charflags & SF_MULTIABILITY))
 						{
 							P_Telekinesis(player,
 								-FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player)
@@ -5180,7 +5181,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 						}
 						break;
 					case CA_TWINSPIN:
-						if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || player->charflags & SF_MULTIABILITY))
+						if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_SPINDOWN)) || player->charflags & SF_MULTIABILITY))
 							P_DoTwinSpin(player);
 						break;
 					default:
@@ -5193,7 +5194,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 	{
 		if (player->pflags & PF_JUMPED)
 		{
-			if (cmd->buttons & BT_USE && player->secondjump < 42) // speed up falling down
+			if (cmd->buttons & BT_SPIN && player->secondjump < 42) // speed up falling down
 				player->secondjump++;
 
 			if (player->flyangle > 0 && player->pflags & PF_THOKKED)
@@ -5484,6 +5485,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 		{
 			if (!P_HomingAttack(player->mo, player->mo->tracer))
 			{
+				player->pflags &= ~PF_SHIELDABILITY;
+				player->secondjump = UINT8_MAX;
 				P_SetObjectMomZ(player->mo, 6*FRACUNIT, false);
 				if (player->mo->eflags & MFE_UNDERWATER)
 					player->mo->momz = FixedMul(player->mo->momz, FRACUNIT/3);
@@ -6188,7 +6191,7 @@ static void P_SpectatorMovement(player_t *player)
 
 	if (cmd->buttons & BT_JUMP)
 		player->mo->z += FRACUNIT*16;
-	else if (cmd->buttons & BT_USE)
+	else if (cmd->buttons & BT_SPIN)
 		player->mo->z -= FRACUNIT*16;
 
 	if (player->mo->z > player->mo->ceilingz - player->mo->height)
@@ -7410,7 +7413,7 @@ static void P_NiGHTSMovement(player_t *player)
 	// No more bumper braking
 	if (!player->bumpertime
 	 && ((cmd->buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)
-	  || (cmd->buttons & BT_USE)))
+	  || (cmd->buttons & BT_SPIN)))
 	{
 		if (!(player->pflags & PF_STARTDASH))
 			S_StartSound(player->mo, sfx_ngskid);
@@ -8457,7 +8460,7 @@ void P_MovePlayer(player_t *player)
 				S_StartSound(player->mo, sfx_putput);
 
 			// Descend
-			if (cmd->buttons & BT_USE && !(player->pflags & PF_STASIS) && !player->exiting && !(player->mo->eflags & MFE_GOOWATER))
+			if (cmd->buttons & BT_SPIN && !(player->pflags & PF_STASIS) && !player->exiting && !(player->mo->eflags & MFE_GOOWATER))
 				if (P_MobjFlip(player->mo)*player->mo->momz > -FixedMul(5*actionspd, player->mo->scale))
 				{
 					if (player->fly1 > 2)
@@ -8821,9 +8824,9 @@ static void P_DoRopeHang(player_t *player)
 	player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
 	player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
 
-	if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
+	if (player->cmd.buttons & BT_SPIN && !(player->pflags & PF_STASIS)) // Drop off of the rope
 	{
-		player->pflags |= (P_GetJumpFlags(player)|PF_USEDOWN);
+		player->pflags |= (P_GetJumpFlags(player)|PF_SPINDOWN);
 		P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
 
 		P_SetTarget(&player->mo->tracer, NULL);
@@ -9476,7 +9479,7 @@ static void P_DeathThink(player_t *player)
 	// continue logic
 	if (!(netgame || multiplayer) && player->lives <= 0)
 	{
-		if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && (!continuesInSession || player->continues > 0))
+		if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_SPIN || cmd->buttons & BT_JUMP) && (!continuesInSession || player->continues > 0))
 			G_UseContinue();
 		else if (player->deadtimer >= gameovertics)
 			G_UseContinue(); // Even if we don't have one this handles ending the game
@@ -9631,45 +9634,45 @@ static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {25, "MAX"}, {0, NULL
 static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t multiplier_cons_t[] = {{0, "MIN"}, {3*FRACUNIT, "MAX"}, {0, NULL}};
 
-consvar_t cv_cam_dist = {"cam_curdist", "160", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_height = {"cam_curheight", "25", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_speed = {"cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_turnmultiplier = {"cam_turnmultiplier", "1.0", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_orbit = {"cam_orbit", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam_adjust = {"cam_adjust", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_dist = {"cam2_curdist", "160", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_height = {"cam2_curheight", "25", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_speed = {"cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_turnmultiplier = {"cam2_turnmultiplier", "1.0", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_orbit = {"cam2_orbit", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cam2_adjust = {"cam2_adjust", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_cam_dist = CVAR_INIT ("cam_curdist", "160", CV_FLOAT, NULL, NULL);
+consvar_t cv_cam_height = CVAR_INIT ("cam_curheight", "25", CV_FLOAT, NULL, NULL);
+consvar_t cv_cam_still = CVAR_INIT ("cam_still", "Off", 0, CV_OnOff, NULL);
+consvar_t cv_cam_speed = CVAR_INIT ("cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL);
+consvar_t cv_cam_rotate = CVAR_INIT ("cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange);
+consvar_t cv_cam_rotspeed = CVAR_INIT ("cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL);
+consvar_t cv_cam_turnmultiplier = CVAR_INIT ("cam_turnmultiplier", "1.0", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL);
+consvar_t cv_cam_orbit = CVAR_INIT ("cam_orbit", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_cam_adjust = CVAR_INIT ("cam_adjust", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT, NULL, NULL);
+consvar_t cv_cam2_height = CVAR_INIT ("cam2_curheight", "25", CV_FLOAT, NULL, NULL);
+consvar_t cv_cam2_still = CVAR_INIT ("cam2_still", "Off", 0, CV_OnOff, NULL);
+consvar_t cv_cam2_speed = CVAR_INIT ("cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL);
+consvar_t cv_cam2_rotate = CVAR_INIT ("cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange);
+consvar_t cv_cam2_rotspeed = CVAR_INIT ("cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL);
+consvar_t cv_cam2_turnmultiplier = CVAR_INIT ("cam2_turnmultiplier", "1.0", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL);
+consvar_t cv_cam2_orbit = CVAR_INIT ("cam2_orbit", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_cam2_adjust = CVAR_INIT ("cam2_adjust", "On", CV_SAVE, CV_OnOff, NULL);
 
 // [standard vs simple][p1 or p2]
 consvar_t cv_cam_savedist[2][2] = {
 	{ // standard
-		{"cam_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist, 0, NULL, NULL, 0, 0, NULL},
-		{"cam2_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist, 0, NULL, NULL, 0, 0, NULL}
+		CVAR_INIT ("cam_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist),
 	},
 	{ // simple
-		{"cam_simpledist", "224", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist, 0, NULL, NULL, 0, 0, NULL},
-		{"cam2_simpledist", "224", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist, 0, NULL, NULL, 0, 0, NULL}
+		CVAR_INIT ("cam_simpledist", "224", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_simpledist", "224", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist),
 
 	}
 };
 consvar_t cv_cam_saveheight[2][2] = {
 	{ // standard
-		{"cam_height", "25", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist, 0, NULL, NULL, 0, 0, NULL},
-		{"cam2_height", "25", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist, 0, NULL, NULL, 0, 0, NULL}
+		CVAR_INIT ("cam_height", "25", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_height", "25", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist),
 	},
 	{ // simple
-		{"cam_simpleheight", "48", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist, 0, NULL, NULL, 0, 0, NULL},
-		{"cam2_simpleheight", "48", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist, 0, NULL, NULL, 0, 0, NULL}
+		CVAR_INIT ("cam_simpleheight", "48", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist),
+		CVAR_INIT ("cam2_simpleheight", "48", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist),
 
 	}
 };
@@ -11010,7 +11013,7 @@ static void P_MinecartThink(player_t *player)
 			else if (detright && player->cmd.sidemove > 0)
 				sidelock = detright;
 
-			//if (player->cmd.buttons & BT_USE && currentSpeed > 4*FRACUNIT)
+			//if (player->cmd.buttons & BT_SPIN && currentSpeed > 4*FRACUNIT)
 			//	currentSpeed -= FRACUNIT/8;
 
 			// Jumping
@@ -11687,7 +11690,7 @@ void P_PlayerThink(player_t *player)
 
 	if ((gametyperules & GTR_RACE) && leveltime < 4*TICRATE)
 	{
-		cmd->buttons &= BT_USE; // Remove all buttons except BT_USE
+		cmd->buttons &= BT_SPIN; // Remove all buttons except BT_SPIN
 		cmd->forwardmove = 0;
 		cmd->sidemove = 0;
 	}
@@ -12057,10 +12060,10 @@ void P_PlayerThink(player_t *player)
 	// check for use
 	if (player->powers[pw_carry] != CR_NIGHTSMODE)
 	{
-		if (cmd->buttons & BT_USE)
-			player->pflags |= PF_USEDOWN;
+		if (cmd->buttons & BT_SPIN)
+			player->pflags |= PF_SPINDOWN;
 		else
-			player->pflags &= ~PF_USEDOWN;
+			player->pflags &= ~PF_SPINDOWN;
 	}
 
 	// IF PLAYER NOT HERE THEN FLASH END IF
diff --git a/src/r_main.c b/src/r_main.c
index 883ac0abfa51acdaa0b140db8fc6b7e39f6a7f6d..3568e211644f0d2b0b9f10a68020950626fe9599 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -102,7 +102,9 @@ extracolormap_t *extra_colormaps = NULL;
 // Render stats
 int rs_prevframetime = 0;
 int rs_rendercalltime = 0;
+int rs_uitime = 0;
 int rs_swaptime = 0;
+int rs_tictime = 0;
 
 int rs_bsptime = 0;
 
@@ -141,31 +143,31 @@ static void FlipCam2_OnChange(void);
 void SendWeaponPref(void);
 void SendWeaponPref2(void);
 
-consvar_t cv_tailspickup = {"tailspickup", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chasecam = {"chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_shadow = {"shadow", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_showhud = {"showhud", "Yes", CV_CALL,  CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-//consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_fov = {"fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_tailspickup = CVAR_INIT ("tailspickup", "On", CV_NETVAR, CV_OnOff, NULL);
+consvar_t cv_chasecam = CVAR_INIT ("chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange);
+consvar_t cv_chasecam2 = CVAR_INIT ("chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange);
+consvar_t cv_flipcam = CVAR_INIT ("flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange);
+consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange);
+
+consvar_t cv_shadow = CVAR_INIT ("shadow", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_skybox = CVAR_INIT ("skybox", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL);
+consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", CV_CALL,  CV_YesNo, R_SetViewSize);
+consvar_t cv_translucenthud = CVAR_INIT ("translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL);
+
+consvar_t cv_translucency = CVAR_INIT ("translucency", "On", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_drawdist = CVAR_INIT ("drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL);
+consvar_t cv_drawdist_nights = CVAR_INIT ("drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL);
+consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL);
+//consvar_t cv_precipdensity = CVAR_INIT ("precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL);
+consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange);
 
 // Okay, whoever said homremoval causes a performance hit should be shot.
-consvar_t cv_homremoval = {"homremoval", "No", CV_SAVE, homremoval_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL);
 
-consvar_t cv_maxportals = {"maxportals", "2", CV_SAVE, maxportals_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
 
-consvar_t cv_renderstats = {"renderstats", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_renderstats = CVAR_INIT ("renderstats", "Off", 0, CV_OnOff, NULL);
 
 void SplitScreen_OnChange(void)
 {
@@ -1074,15 +1076,22 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
 // recalc necessary stuff for mouseaiming
 // slopes are already calculated for the full possible view (which is 4*viewheight).
 // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out)
-static void R_SetupFreelook(void)
+static void R_SetupFreelook(player_t *player, boolean skybox)
 {
 	INT32 dy = 0;
 
+#ifndef HWRENDER
+	(void)player;
+	(void)skybox;
+#endif
+
 	// clip it in the case we are looking a hardware 90 degrees full aiming
 	// (lmps, network and use F12...)
 	if (rendermode == render_soft
 #ifdef HWRENDER
-		|| cv_glshearing.value
+		|| (rendermode == render_opengl
+			&& (cv_glshearing.value == 1
+			|| (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))))
 #endif
 		)
 	{
@@ -1203,7 +1212,7 @@ void R_SetupFrame(player_t *player)
 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
 
-	R_SetupFreelook();
+	R_SetupFreelook(player, false);
 }
 
 void R_SkyboxFrame(player_t *player)
@@ -1340,7 +1349,7 @@ void R_SkyboxFrame(player_t *player)
 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
 
-	R_SetupFreelook();
+	R_SetupFreelook(player, true);
 }
 
 boolean R_ViewpointHasChasecam(player_t *player)
diff --git a/src/r_main.h b/src/r_main.h
index 20d9524c84715a2e46c7c20b8b2b69eab644d86f..e3ea49faa205144ab044dd591b1c69058dd1b6c9 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -82,7 +82,9 @@ extern consvar_t cv_renderstats;
 
 extern int rs_prevframetime;// time when previous frame was rendered
 extern int rs_rendercalltime;
+extern int rs_uitime;
 extern int rs_swaptime;
+extern int rs_tictime;
 
 extern int rs_bsptime;
 
diff --git a/src/r_picformats.c b/src/r_picformats.c
index 078901fab46ea1426fede7bab1cc25df16b38a15..7b44d21f12308f71abb532c15c947521dba525b6 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -54,6 +54,10 @@
 
 static unsigned char imgbuf[1<<26];
 
+#ifdef PICTURE_PNG_USELOOKUP
+static colorlookup_t png_colorlookup;
+#endif
+
 /** Converts a picture between two formats.
   *
   * \param informat Input picture format.
@@ -871,13 +875,26 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext)
 	CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
 }
 
-static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset, size_t size)
+static png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'};
+
+static png_bytep *PNG_Read(
+	const UINT8 *png,
+	INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset,
+	boolean *use_palette, size_t size)
 {
 	png_structp png_ptr;
 	png_infop png_info_ptr;
 	png_uint_32 width, height;
 	int bit_depth, color_type;
 	png_uint_32 y;
+
+	png_colorp palette;
+	int palette_size;
+
+	png_bytep trans;
+	int trans_num;
+	png_color_16p trans_values;
+
 #ifdef PNG_SETJMP_SUPPORTED
 #ifdef USE_FAR_KEYWORD
 	jmp_buf jmpbuf;
@@ -886,8 +903,6 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse
 
 	png_io_t png_io;
 	png_bytep *row_pointers;
-
-	png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'};
 	png_voidp *user_chunk_ptr;
 
 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn);
@@ -914,7 +929,6 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse
 	png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
 #endif
 
-	// set our own read function
 	png_io.buffer = png;
 	png_io.size = size;
 	png_io.position = 0;
@@ -937,10 +951,48 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse
 	if (bit_depth == 16)
 		png_set_strip_16(png_ptr);
 
+	palette = NULL;
+	*use_palette = false;
+
 	if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
 		png_set_gray_to_rgb(png_ptr);
 	else if (color_type == PNG_COLOR_TYPE_PALETTE)
-		png_set_palette_to_rgb(png_ptr);
+	{
+		boolean usepal = false;
+
+		// Lactozilla: Check if the PNG has a palette, and if its color count
+		// matches the color count of SRB2's palette: 256 colors.
+		if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size))
+		{
+			if (palette_size == 256)
+				usepal = true;
+		}
+
+		// If any of the tRNS colors have an alpha lower than 0xFF, and that
+		// color is present on the image, the palette flag is disabled.
+		png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values);
+
+		if (trans && trans_num == 256)
+		{
+			int i;
+			for (i = 0; i < trans_num; i++)
+			{
+				// libpng will transform this image into RGB even if
+				// the transparent index does not exist in the image,
+				// and there is no way around that.
+				if (trans[i] < 0xFF)
+				{
+					usepal = false;
+					break;
+				}
+			}
+		}
+
+		if (usepal)
+			*use_palette = true;
+		else
+			png_set_palette_to_rgb(png_ptr);
+	}
 
 	if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS))
 		png_set_tRNS_to_alpha(png_ptr);
@@ -974,13 +1026,13 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse
 			*topoffset = (INT16)BIGENDIAN_LONG(*offsets);
 	}
 
-	// bye
 	png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
 	if (chunk.data)
 		Z_Free(chunk.data);
 
 	*w = (INT32)width;
 	*h = (INT32)height;
+
 	return row_pointers;
 }
 
@@ -1008,12 +1060,33 @@ void *Picture_PNGConvert(
 	INT32 outbpp;
 	size_t flatsize;
 	png_uint_32 x, y;
-	png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize);
-	png_uint_32 width = *w, height = *h;
+	png_bytep row;
+	boolean palette = false;
+	png_bytep *row_pointers = NULL;
+	png_uint_32 width, height;
+
+	INT32 pngwidth, pngheight;
+	INT16 loffs = 0, toffs = 0;
 
 	if (png == NULL)
 		I_Error("Picture_PNGConvert: picture was NULL!");
 
+	if (w == NULL)
+		w = &pngwidth;
+	if (h == NULL)
+		h = &pngheight;
+	if (topoffset == NULL)
+		topoffset = &toffs;
+	if (leftoffset == NULL)
+		leftoffset = &loffs;
+
+	row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, &palette, insize);
+	width = *w;
+	height = *h;
+
+	if (row_pointers == NULL)
+		I_Error("Picture_PNGConvert: row_pointers was NULL!");
+
 	// Find the output format's bits per pixel amount
 	outbpp = Picture_FormatBPP(outformat);
 
@@ -1041,39 +1114,124 @@ void *Picture_PNGConvert(
 	if (outbpp == PICDEPTH_8BPP)
 		memset(flat, TRANSPARENTPIXEL, (width * height));
 
-	for (y = 0; y < height; y++)
+#ifdef PICTURE_PNG_USELOOKUP
+	if (outbpp != PICDEPTH_32BPP)
+		InitColorLUT(&png_colorlookup, pMasterPalette, false);
+#endif
+
+	if (outbpp == PICDEPTH_32BPP)
 	{
-		png_bytep row = row_pointers[y];
-		for (x = 0; x < width; x++)
+		RGBA_t out;
+		UINT32 *outflat = (UINT32 *)flat;
+
+		if (palette)
 		{
-			png_bytep px = &(row[x * 4]);
-			if ((UINT8)px[3])
+			for (y = 0; y < height; y++)
 			{
-				UINT8 red = (UINT8)px[0];
-				UINT8 green = (UINT8)px[1];
-				UINT8 blue = (UINT8)px[2];
-				UINT8 alpha = (UINT8)px[3];
-				if (outbpp == PICDEPTH_32BPP)
+				row = row_pointers[y];
+				for (x = 0; x < width; x++)
 				{
-					UINT32 *outflat = (UINT32 *)flat;
-					RGBA_t out;
-					out.s.red = red;
-					out.s.green = green;
-					out.s.blue = blue;
-					out.s.alpha = alpha;
+					out = V_GetColor(row[x]);
 					outflat[((y * width) + x)] = out.rgba;
 				}
-				else
+			}
+		}
+		else
+		{
+			for (y = 0; y < height; y++)
+			{
+				row = row_pointers[y];
+				for (x = 0; x < width; x++)
+				{
+					png_bytep px = &(row[x * 4]);
+					if ((UINT8)px[3])
+					{
+						out.s.red = (UINT8)px[0];
+						out.s.green = (UINT8)px[1];
+						out.s.blue = (UINT8)px[2];
+						out.s.alpha = (UINT8)px[3];
+						outflat[((y * width) + x)] = out.rgba;
+					}
+					else
+						outflat[((y * width) + x)] = 0x00000000;
+				}
+			}
+		}
+	}
+	else if (outbpp == PICDEPTH_16BPP)
+	{
+		UINT16 *outflat = (UINT16 *)flat;
+
+		if (palette)
+		{
+			for (y = 0; y < height; y++)
+			{
+				row = row_pointers[y];
+				for (x = 0; x < width; x++)
+					outflat[((y * width) + x)] = (0xFF << 8) | row[x];
+			}
+		}
+		else
+		{
+			for (y = 0; y < height; y++)
+			{
+				row = row_pointers[y];
+				for (x = 0; x < width; x++)
 				{
-					UINT8 palidx = NearestColor(red, green, blue);
-					if (outbpp == PICDEPTH_16BPP)
+					png_bytep px = &(row[x * 4]);
+					UINT8 red = (UINT8)px[0];
+					UINT8 green = (UINT8)px[1];
+					UINT8 blue = (UINT8)px[2];
+					UINT8 alpha = (UINT8)px[3];
+
+					if (alpha)
 					{
-						UINT16 *outflat = (UINT16 *)flat;
-						outflat[((y * width) + x)] = (alpha << 8) | palidx;
+#ifdef PICTURE_PNG_USELOOKUP
+						UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue);
+#else
+						UINT8 palidx = NearestColor(red, green, blue);
+#endif
+						outflat[((y * width) + x)] = (0xFF << 8) | palidx;
 					}
-					else // 8bpp
+					else
+						outflat[((y * width) + x)] = 0x0000;
+				}
+			}
+		}
+	}
+	else // 8bpp
+	{
+		UINT8 *outflat = (UINT8 *)flat;
+
+		if (palette)
+		{
+			for (y = 0; y < height; y++)
+			{
+				row = row_pointers[y];
+				for (x = 0; x < width; x++)
+					outflat[((y * width) + x)] = row[x];
+			}
+		}
+		else
+		{
+			for (y = 0; y < height; y++)
+			{
+				row = row_pointers[y];
+				for (x = 0; x < width; x++)
+				{
+					png_bytep px = &(row[x * 4]);
+					UINT8 red = (UINT8)px[0];
+					UINT8 green = (UINT8)px[1];
+					UINT8 blue = (UINT8)px[2];
+					UINT8 alpha = (UINT8)px[3];
+
+					if (alpha)
 					{
-						UINT8 *outflat = (UINT8 *)flat;
+#ifdef PICTURE_PNG_USELOOKUP
+						UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue);
+#else
+						UINT8 palidx = NearestColor(red, green, blue);
+#endif
 						outflat[((y * width) + x)] = palidx;
 					}
 				}
@@ -1082,6 +1240,8 @@ void *Picture_PNGConvert(
 	}
 
 	// Free the row pointers that we allocated for libpng.
+	for (y = 0; y < height; y++)
+		free(row_pointers[y]);
 	free(row_pointers);
 
 	// But wait, there's more!
@@ -1089,7 +1249,6 @@ void *Picture_PNGConvert(
 	{
 		void *converted;
 		pictureformat_t informat = PICFMT_NONE;
-		INT16 patleftoffset = 0, pattopoffset = 0;
 
 		// Figure out the format of the flat, from the bit depth of the output format
 		switch (outbpp)
@@ -1105,14 +1264,8 @@ void *Picture_PNGConvert(
 				break;
 		}
 
-		// Also find out if leftoffset and topoffset aren't pointing to NULL.
-		if (leftoffset)
-			patleftoffset = *leftoffset;
-		if (topoffset)
-			pattopoffset = *topoffset;
-
 		// Now, convert it!
-		converted = Picture_PatchConvert(informat, flat, outformat, insize, outsize, (INT16)width, (INT16)height, patleftoffset, pattopoffset, flags);
+		converted = Picture_PatchConvert(informat, flat, outformat, insize, outsize, (INT16)width, (INT16)height, *leftoffset, *topoffset, flags);
 		Z_Free(flat);
 		return converted;
 	}
@@ -1126,10 +1279,12 @@ void *Picture_PNGConvert(
   * \param png The PNG image.
   * \param width A pointer to the input picture's width.
   * \param height A pointer to the input picture's height.
+  * \param topoffset A pointer to the input picture's vertical offset.
+  * \param leftoffset A pointer to the input picture's horizontal offset.
   * \param size The input picture's size.
   * \return True if reading the file succeeded, false if it failed.
   */
-boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size)
+boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size)
 {
 	png_structp png_ptr;
 	png_infop png_info_ptr;
@@ -1142,9 +1297,9 @@ boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t si
 #endif
 
 	png_io_t png_io;
+	png_voidp *user_chunk_ptr;
 
-	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
-		PNG_error, PNG_warn);
+	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn);
 	if (!png_ptr)
 		I_Error("Picture_PNGDimensions: Couldn't initialize libpng!");
 
@@ -1168,23 +1323,41 @@ boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t si
 	png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
 #endif
 
-	// set our own read function
 	png_io.buffer = png;
 	png_io.size = size;
 	png_io.position = 0;
 	png_set_read_fn(png_ptr, &png_io, PNG_IOReader);
 
+	memset(&chunk, 0x00, sizeof(png_chunk_t));
+	chunkname = grAb_chunk; // I want to read a grAb chunk
+
+	user_chunk_ptr = png_get_user_chunk_ptr(png_ptr);
+	png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, PNG_ChunkReader);
+	png_set_keep_unknown_chunks(png_ptr, 2, chunkname, 1);
+
 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
 	png_set_user_limits(png_ptr, 2048, 2048);
 #endif
 
 	png_read_info(png_ptr, png_info_ptr);
+	png_get_IHDR(png_ptr, png_info_ptr, &w, &h, &bit_depth, &color_type, NULL, NULL, NULL);
 
-	png_get_IHDR(png_ptr, png_info_ptr, &w, &h, &bit_depth, &color_type,
-	 NULL, NULL, NULL);
+	// Read grAB chunk
+	if ((topoffset || leftoffset) && (chunk.data != NULL))
+	{
+		INT32 *offsets = (INT32 *)chunk.data;
+		// read left offset
+		if (leftoffset != NULL)
+			*leftoffset = (INT16)BIGENDIAN_LONG(*offsets);
+		offsets++;
+		// read top offset
+		if (topoffset != NULL)
+			*topoffset = (INT16)BIGENDIAN_LONG(*offsets);
+	}
 
-	// okay done. stop.
 	png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
+	if (chunk.data)
+		Z_Free(chunk.data);
 
 	*width = (INT32)w;
 	*height = (INT32)h;
diff --git a/src/r_picformats.h b/src/r_picformats.h
index 4f5c60ee18368dcfe1c1758d453aee94e13832e8..e6c4aa17a6bc098955f4280b2853c5c3a8774fae 100644
--- a/src/r_picformats.h
+++ b/src/r_picformats.h
@@ -115,9 +115,11 @@ void *Picture_PNGConvert(
 	INT16 *topoffset, INT16 *leftoffset,
 	size_t insize, size_t *outsize,
 	pictureflags_t flags);
-boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
+boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size);
 #endif
 
+#define PICTURE_PNG_USELOOKUP
+
 // SpriteInfo
 extern spriteinfo_t spriteinfo[NUMSPRITES];
 void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps);
diff --git a/src/r_skins.c b/src/r_skins.c
index a1484a2b3d754c95731620e9d7dfd2cd5818acd7..25904e95e3ff2c1c89e5fcd5c60c564efedaf84b 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -31,12 +31,6 @@
 #include "hardware/hw_md2.h"
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-int	snprintf(char *str, size_t n, const char *fmt, ...);
-//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
 INT32 numskins = 0;
 skin_t skins[MAXSKINS];
 
@@ -292,6 +286,11 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 			else if (playernum == secondarydisplayplayer)
 				CV_StealthSetValue(&cv_playercolor2, skin->prefcolor);
 			player->skincolor = newcolor = skin->prefcolor;
+			if (player->bot && botingame)
+			{
+				botskin = (UINT8)(skinnum + 1);
+				botcolor = skin->prefcolor;
+			}
 		}
 
 		if (player->followmobj)
diff --git a/src/r_textures.c b/src/r_textures.c
index a226afa891712f5057ada8403c39ac76657ba612..9de9649e222a9628f0917592570c899917e62722 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -398,11 +398,7 @@ UINT8 *R_GenerateTexture(size_t texnum)
 
 #ifndef NO_PNG_LUMPS
 		if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
-			// Dummy variables.
-			INT32 pngwidth, pngheight;
-			realpatch = (softwarepatch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_DOOMPATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0);
-		}
+			realpatch = (softwarepatch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 #ifdef WALLFLATS
@@ -801,10 +797,10 @@ Rloadflats (INT32 i, INT32 w)
 #ifndef NO_PNG_LUMPS
 			if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength))
 			{
-				INT16 width, height;
-				Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength);
-				texture->width = width;
-				texture->height = height;
+				INT32 width, height;
+				Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, NULL, NULL, lumplength);
+				texture->width = (INT16)width;
+				texture->height = (INT16)height;
 			}
 			else
 #endif
@@ -899,10 +895,10 @@ Rloadtextures (INT32 i, INT32 w)
 #ifndef NO_PNG_LUMPS
 			if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength))
 			{
-				INT16 width, height;
-				Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength);
-				texture->width = width;
-				texture->height = height;
+				INT32 width, height;
+				Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, NULL, NULL, lumplength);
+				texture->width = (INT16)width;
+				texture->height = (INT16)height;
 			}
 			else
 #endif
diff --git a/src/r_things.c b/src/r_things.c
index e4465dfa964c3b949bafc7a9cad461d6f252f518..a9a5c42fced424cb5574192a923af12509847a90 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -256,6 +256,12 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 	{
 		if (memcmp(lumpinfo[l].name,sprname,4)==0)
 		{
+			INT32 width, height;
+			INT16 topoffset, leftoffset;
+#ifndef NO_PNG_LUMPS
+			boolean isPNG = false;
+#endif
+
 			frame = R_Char2Frame(lumpinfo[l].name[4]);
 			rotation = R_Char2Rotation(lumpinfo[l].name[5]);
 
@@ -271,28 +277,35 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
 
 			// store sprite info in lookup tables
 			//FIXME : numspritelumps do not duplicate sprite replacements
-			W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0);
+
 #ifndef NO_PNG_LUMPS
 			{
 				softwarepatch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC);
 				size_t len = W_LumpLengthPwad(wadnum, l);
-				// lump is a png so convert it
+
 				if (Picture_IsLumpPNG((UINT8 *)png, len))
 				{
-					// Dummy variables.
-					INT32 pngwidth, pngheight;
-					INT16 topoffset, leftoffset;
-					patch_t *converted = (patch_t *)Picture_PNGConvert((UINT8 *)png, PICFMT_DOOMPATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, len, NULL, 0);
-					M_Memcpy(&patch, converted, sizeof(INT16)*4); // only copy the header because that's all we need
-					Z_Free(converted);
+					Picture_PNGDimensions((UINT8 *)png, &width, &height, &topoffset, &leftoffset, len);
+					isPNG = true;
 				}
+
 				Z_Free(png);
 			}
+
+			if (!isPNG)
 #endif
-			spritecachedinfo[numspritelumps].width = SHORT(patch.width)<<FRACBITS;
-			spritecachedinfo[numspritelumps].offset = SHORT(patch.leftoffset)<<FRACBITS;
-			spritecachedinfo[numspritelumps].topoffset = SHORT(patch.topoffset)<<FRACBITS;
-			spritecachedinfo[numspritelumps].height = SHORT(patch.height)<<FRACBITS;
+			{
+				W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0);
+				width = SHORT(patch.width);
+				height = SHORT(patch.height);
+				topoffset = SHORT(patch.topoffset);
+				leftoffset = SHORT(patch.leftoffset);
+			}
+
+			spritecachedinfo[numspritelumps].width = width<<FRACBITS;
+			spritecachedinfo[numspritelumps].offset = leftoffset<<FRACBITS;
+			spritecachedinfo[numspritelumps].topoffset = topoffset<<FRACBITS;
+			spritecachedinfo[numspritelumps].height = height<<FRACBITS;
 
 			//BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
 			if (rendermode != render_none) // not for psprite
diff --git a/src/s_sound.c b/src/s_sound.c
index 072a69f6c13de72fcaa2311f6f4e56f27c9fe150..793794aa7c70bcabbcd02e7fade906e108e39bb1 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -11,16 +11,6 @@
 /// \file  s_sound.c
 /// \brief System-independent sound and music routines
 
-#ifdef MUSSERV
-#include <sys/msg.h>
-struct musmsg
-{
-	long msg_type;
-	char msg_text[12];
-};
-extern INT32 msg_id;
-#endif
-
 #include "doomdef.h"
 #include "doomstat.h"
 #include "command.h"
@@ -70,36 +60,26 @@ static lumpnum_t S_GetMusicLumpNum(const char *mname);
 
 static boolean S_CheckQueue(void);
 
-// commands for music and sound servers
-#ifdef MUSSERV
-consvar_t musserver_cmd = {"musserver_cmd", "musserver", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t musserver_arg = {"musserver_arg", "-t 20 -f -u 0 -i music.dta", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-#endif
-#ifdef SNDSERV
-consvar_t sndserver_cmd = {"sndserver_cmd", "llsndserv", CV_SAVE, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t sndserver_arg = {"sndserver_arg", "-quiet", CV_SAVE, NULL, 0, NULL, NULL, 0, 0, NULL};
-#endif
-
 #if defined (_WINDOWS) && !defined (SURROUND) //&& defined (_X86_)
 #define SURROUND
 #endif
 
 #ifdef _WINDOWS
-consvar_t cv_samplerate = {"samplerate", "44100", 0, CV_Unsigned, NULL, 44100, NULL, NULL, 0, 0, NULL}; //Alam: For easy hacking?
+consvar_t cv_samplerate = CVAR_INIT ("samplerate", "44100", 0, CV_Unsigned, NULL); //Alam: For easy hacking?
 #else
-consvar_t cv_samplerate = {"samplerate", "22050", 0, CV_Unsigned, NULL, 22050, NULL, NULL, 0, 0, NULL}; //Alam: For easy hacking?
+consvar_t cv_samplerate = CVAR_INIT ("samplerate", "22050", 0, CV_Unsigned, NULL); //Alam: For easy hacking?
 #endif
 
 // stereo reverse
-consvar_t stereoreverse = {"stereoreverse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t stereoreverse = CVAR_INIT ("stereoreverse", "Off", CV_SAVE, CV_OnOff, NULL);
 
 // if true, all sounds are loaded at game startup
-static consvar_t precachesound = {"precachesound", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t precachesound = CVAR_INIT ("precachesound", "Off", CV_SAVE, CV_OnOff, NULL);
 
 // actual general (maximum) sound & music volume, saved into the config
-consvar_t cv_soundvolume = {"soundvolume", "18", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_digmusicvolume = {"digmusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_midimusicvolume = {"midimusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "18", CV_SAVE, soundvolume_cons_t, NULL);
+consvar_t cv_digmusicvolume = CVAR_INIT ("digmusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL);
+consvar_t cv_midimusicvolume = CVAR_INIT ("midimusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL);
 
 static void Captioning_OnChange(void)
 {
@@ -108,27 +88,27 @@ static void Captioning_OnChange(void)
 		S_StartSound(NULL, sfx_menu1);
 }
 
-consvar_t cv_closedcaptioning = {"closedcaptioning", "Off", CV_SAVE|CV_CALL, CV_OnOff, Captioning_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_closedcaptioning = CVAR_INIT ("closedcaptioning", "Off", CV_SAVE|CV_CALL, CV_OnOff, Captioning_OnChange);
 
 // number of channels available
-consvar_t cv_numChannels = {"snd_channels", "32", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_numChannels = CVAR_INIT ("snd_channels", "32", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum);
 
-static consvar_t surround = {"surround", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t surround = CVAR_INIT ("surround", "Off", CV_SAVE, CV_OnOff, NULL);
 
-consvar_t cv_resetmusic = {"resetmusic", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_resetmusicbyheader = {"resetmusicbyheader", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_resetmusic = CVAR_INIT ("resetmusic", "Off", CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_resetmusicbyheader = CVAR_INIT ("resetmusicbyheader", "Yes", CV_SAVE, CV_YesNo, NULL);
 
 static CV_PossibleValue_t cons_1upsound_t[] = {
 	{0, "Jingle"},
 	{1, "Sound"},
 	{0, NULL}
 };
-consvar_t cv_1upsound = {"1upsound", "Jingle", CV_SAVE, cons_1upsound_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_1upsound = CVAR_INIT ("1upsound", "Jingle", CV_SAVE, cons_1upsound_t, NULL);
 
 // Sound system toggles, saved into the config
-consvar_t cv_gamedigimusic = {"digimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameDigiMusic_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gamemidimusic = {"midimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameMIDIMusic_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gamesounds = {"sounds", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameSounds_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_gamedigimusic = CVAR_INIT ("digimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameDigiMusic_OnChange);
+consvar_t cv_gamemidimusic = CVAR_INIT ("midimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameMIDIMusic_OnChange);
+consvar_t cv_gamesounds = CVAR_INIT ("sounds", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameSounds_OnChange);
 
 // Music preference
 static CV_PossibleValue_t cons_musicpref_t[] = {
@@ -136,16 +116,16 @@ static CV_PossibleValue_t cons_musicpref_t[] = {
 	{1, "MIDI"},
 	{0, NULL}
 };
-consvar_t cv_musicpref = {"musicpref", "Digital", CV_SAVE|CV_CALL|CV_NOINIT, cons_musicpref_t, MusicPref_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_musicpref = CVAR_INIT ("musicpref", "Digital", CV_SAVE|CV_CALL|CV_NOINIT, cons_musicpref_t, MusicPref_OnChange);
 
 // Window focus sound sytem toggles
-consvar_t cv_playmusicifunfocused = {"playmusicifunfocused", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_playsoundsifunfocused = {"playsoundsifunfocused", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_playmusicifunfocused = CVAR_INIT ("playmusicifunfocused", "No", CV_SAVE, CV_YesNo, NULL);
+consvar_t cv_playsoundsifunfocused = CVAR_INIT ("playsoundsifunfocused", "No", CV_SAVE, CV_YesNo, NULL);
 
 #ifdef HAVE_OPENMPT
 openmpt_module *openmpt_mhandle = NULL;
 static CV_PossibleValue_t interpolationfilter_cons_t[] = {{0, "Default"}, {1, "None"}, {2, "Linear"}, {4, "Cubic"}, {8, "Windowed sinc"}, {0, NULL}};
-consvar_t cv_modfilter = {"modfilter", "0", CV_SAVE|CV_CALL, interpolationfilter_cons_t, ModFilter_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_modfilter = CVAR_INIT ("modfilter", "0", CV_SAVE|CV_CALL, interpolationfilter_cons_t, ModFilter_OnChange);
 #endif
 
 #define S_MAX_VOLUME 127
@@ -292,14 +272,6 @@ void S_RegisterSoundStuff(void)
 	CV_RegisterVar(&stereoreverse);
 	CV_RegisterVar(&precachesound);
 
-#ifdef SNDSERV
-	CV_RegisterVar(&sndserver_cmd);
-	CV_RegisterVar(&sndserver_arg);
-#endif
-#ifdef MUSSERV
-	CV_RegisterVar(&musserver_cmd);
-	CV_RegisterVar(&musserver_arg);
-#endif
 	CV_RegisterVar(&surround);
 	CV_RegisterVar(&cv_samplerate);
 	CV_RegisterVar(&cv_resetmusic);
@@ -322,27 +294,6 @@ void S_RegisterSoundStuff(void)
 
 	COM_AddCommand("tunes", Command_Tunes_f);
 	COM_AddCommand("restartaudio", Command_RestartAudio_f);
-
-#if defined (macintosh) && !defined (HAVE_SDL) // mp3 playlist stuff
-	{
-		INT32 i;
-		for (i = 0; i < PLAYLIST_LENGTH; i++)
-		{
-			user_songs[i].name = malloc(7);
-			if (!user_songs[i].name)
-				I_Error("No more free memory for mp3 playlist");
-			sprintf(user_songs[i].name, "song%d%d",i/10,i%10);
-			user_songs[i].defaultvalue = malloc(sizeof (char));
-			if (user_songs[i].defaultvalue)
-				I_Error("No more free memory for blank mp3 playerlist");
-			*user_songs[i].defaultvalue = 0;
-			user_songs[i].flags = CV_SAVE;
-			user_songs[i].PossibleValue = NULL;
-			CV_RegisterVar(&user_songs[i]);
-		}
-		CV_RegisterVar(&play_mode);
-	}
-#endif
 }
 
 static void SetChannelsNum(void)
@@ -570,6 +521,7 @@ void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan)
 
 void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
 {
+	const INT32 initial_volume = volume;
 	INT32 sep, pitch, priority, cnum;
 	const sfxenum_t actual_id = sfx_id;
 	sfxinfo_t *sfx;
@@ -767,6 +719,7 @@ dontplay:
 
 	// Assigns the handle to one of the channels in the
 	// mix/output buffer.
+	channels[cnum].volume = initial_volume;
 	channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
 }
 
@@ -978,7 +931,7 @@ void S_UpdateSounds(void)
 			if (I_SoundIsPlaying(c->handle))
 			{
 				// initialize parameters
-				volume = 255; // 8 bits internal volume precision
+				volume = c->volume; // 8 bits internal volume precision
 				pitch = NORM_PITCH;
 				sep = NORM_SEP;
 
@@ -1092,7 +1045,6 @@ void S_ClearSfx(void)
 
 static void S_StopChannel(INT32 cnum)
 {
-	INT32 i;
 	channel_t *c = &channels[cnum];
 
 	if (c->sfxinfo)
@@ -1101,17 +1053,12 @@ static void S_StopChannel(INT32 cnum)
 		if (I_SoundIsPlaying(c->handle))
 			I_StopSound(c->handle);
 
-		// check to see
-		//  if other channels are playing the sound
-		for (i = 0; i < numofchannels; i++)
-			if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
-				break;
-
 		// degrade usefulness of sound data
 		c->sfxinfo->usefulness--;
-
 		c->sfxinfo = 0;
 	}
+
+	c->origin = NULL;
 }
 
 //
@@ -1253,15 +1200,12 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v
 	}
 
 	// volume calculation
-	if (approx_dist < S_CLOSE_DIST)
-	{
-		// SfxVolume is now hardware volume
-		*vol = 255; // not snd_SfxVolume
-	}
-	else
+	/* not sure if it should be > (no =), but this matches the old behavior */
+	if (approx_dist >= S_CLOSE_DIST)
 	{
 		// distance effect
-		*vol = (15 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR;
+		INT32 n = (15 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS));
+		*vol = FixedMul(*vol * FRACUNIT / 255, n) / S_ATTENUATOR;
 	}
 
 	return (*vol > 0);
@@ -2230,17 +2174,6 @@ static boolean S_LoadMusic(const char *mname)
 	// load & register it
 	mdata = W_CacheLumpNum(mlumpnum, PU_MUSIC);
 
-#ifdef MUSSERV
-	if (msg_id != -1)
-	{
-		struct musmsg msg_buffer;
-
-		msg_buffer.msg_type = 6;
-		memset(msg_buffer.msg_text, 0, sizeof (msg_buffer.msg_text));
-		sprintf(msg_buffer.msg_text, "d_%s", mname);
-		msgsnd(msg_id, (struct msgbuf*)&msg_buffer, sizeof (msg_buffer.msg_text), IPC_NOWAIT);
-	}
-#endif
 
 	if (I_LoadSong(mdata, W_LumpLength(mlumpnum)))
 	{
@@ -2433,13 +2366,6 @@ void S_PauseAudio(void)
 	if (I_SongPlaying() && !I_SongPaused())
 		I_PauseSong();
 
-	// pause cd music
-#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
-	I_PauseCD();
-#else
-	I_StopCD();
-#endif
-
 	S_SetStackAdjustmentStart();
 }
 
@@ -2451,9 +2377,6 @@ void S_ResumeAudio(void)
 	if (I_SongPlaying() && I_SongPaused())
 		I_ResumeSong();
 
-	// resume cd music
-	I_ResumeCD();
-
 	S_AdjustMusicStackTics();
 }
 
@@ -2474,10 +2397,6 @@ void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume)
 	CV_SetValue(&cv_midimusicvolume, seqvolume&31);
 	actualmidimusicvolume = cv_midimusicvolume.value;   //check for change of var
 
-#ifdef DJGPPDOS
-	digvolume = seqvolume = 31;
-#endif
-
 	switch(I_SongType())
 	{
 		case MU_MID:
diff --git a/src/s_sound.h b/src/s_sound.h
index 35d1c3dc5e57276b0cdae86c34f8fe9cb9db362e..4ac3c70bf0d4a76f759e166ee0db3c682894ee5f 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -61,27 +61,7 @@ extern consvar_t cv_midisoundfontpath;
 extern consvar_t cv_miditimiditypath;
 #endif
 
-#ifdef SNDSERV
-extern consvar_t sndserver_cmd, sndserver_arg;
-#endif
-#ifdef MUSSERV
-extern consvar_t musserver_cmd, musserver_arg;
-#endif
-
 extern CV_PossibleValue_t soundvolume_cons_t[];
-//part of i_cdmus.c
-extern consvar_t cd_volume, cdUpdate;
-
-#if defined (macintosh) && !defined (HAVE_SDL)
-typedef enum
-{
-	music_normal,
-	playlist_random,
-	playlist_normal
-} playmode_t;
-
-extern consvar_t play_mode;
-#endif
 
 typedef enum
 {
@@ -107,6 +87,9 @@ typedef struct
 	// origin of sound
 	const void *origin;
 
+	// initial volume of sound, which is applied after distance and direction
+	INT32 volume;
+
 	// handle of the sound being played
 	INT32 handle;
 
diff --git a/src/screen.c b/src/screen.c
index d460e1f6d948529f61e8ecfc9e5a7d9f0f1326c9..adda4ba2f2cb0beda0c06ebeefea2495e7dfe6a0 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -59,10 +59,10 @@ UINT8 setrenderneeded = 0;
 static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}};
 
 //added : 03-02-98: default screen mode, as loaded/saved in config
-consvar_t cv_scr_width = {"scr_width", "1280", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_scr_width = CVAR_INIT ("scr_width", "1280", CV_SAVE, CV_Unsigned, NULL);
+consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, NULL);
+consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL);
+consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL);
 
 CV_PossibleValue_t cv_renderer_t[] = {
 	{1, "Software"},
@@ -71,11 +71,12 @@ CV_PossibleValue_t cv_renderer_t[] = {
 #endif
 	{0, NULL}
 };
-consvar_t cv_renderer = {"renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_SetTargetRenderer, 0, NULL, NULL, 0, 0, NULL};
+
+consvar_t cv_renderer = CVAR_INIT ("renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_SetTargetRenderer);
 
 static void SCR_ChangeFullscreen(void);
 
-consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_fullscreen = CVAR_INIT ("fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen);
 
 // =========================================================================
 //                           SCREEN VARIABLES
@@ -370,9 +371,6 @@ void SCR_CheckDefaultMode(void)
 		{
 			// Set cv_renderer to the current render mode
 			CV_StealthSetValue(&cv_renderer, rendermode);
-#ifdef HWRENDER
-			CV_StealthSetValue(&cv_newrenderer, rendermode);
-#endif
 		}
 	}
 }
diff --git a/src/screen.h b/src/screen.h
index 3f6c91d05dc55ae2282bf09bacd7716eb85efe11..acc08f00151aa1567d1ef137c7ba90e71550a039 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -174,7 +174,6 @@ extern boolean R_SSE2;
 // ----------------
 // screen variables
 // ----------------
-
 extern viddef_t vid;
 extern INT32 setmodeneeded; // mode number to set if needed, or 0
 extern UINT8 setrenderneeded;
@@ -182,15 +181,12 @@ extern UINT8 setrenderneeded;
 void SCR_ChangeRenderer(void);
 void SCR_SetTargetRenderer(void);
 
+extern CV_PossibleValue_t cv_renderer_t[];
+
 extern INT32 scr_bpp;
 extern UINT8 *scr_borderpatch; // patch used to fill the view borders
 
-extern CV_PossibleValue_t cv_renderer_t[];
-
 extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen;
-#ifdef HWRENDER
-extern consvar_t cv_newrenderer;
-#endif
 // wait for page flipping to end or not
 extern consvar_t cv_vidwait;
 
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index 744b242fa83d15dd9c51cc5a80fa2758f138a1cd..72f78188f2e642dc7ca774e2e1dad1e87008b751 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -36,7 +36,6 @@ set(SRB2_SDL2_SOURCES
 	dosstr.c
 	endtxt.c
 	hwsym_sdl.c
-	i_cdmus.c
 	i_main.c
 	i_net.c
 	i_system.c
@@ -166,6 +165,7 @@ if(${SDL2_FOUND})
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
+			${CURL_LIBRARIES}
 		)
 		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
 	else()
@@ -178,6 +178,7 @@ if(${SDL2_FOUND})
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
+			${CURL_LIBRARIES}
 		)
 
 		if(${CMAKE_SYSTEM} MATCHES Linux)
@@ -259,6 +260,7 @@ if(${SDL2_FOUND})
 		${PNG_INCLUDE_DIRS}
 		${ZLIB_INCLUDE_DIRS}
 		${OPENGL_INCLUDE_DIRS}
+		${CURL_INCLUDE_DIRS}
 	)
 
 	if((${SRB2_HAVE_MIXER}) OR (${SRB2_HAVE_MIXERX}))
diff --git a/src/sdl/Makefile.cfg b/src/sdl/Makefile.cfg
index 05b60f7a328ab917363e0a89d870511179e297d3..45d0d6ba75a666cba5e4e2c3a3f9704987705cb6 100644
--- a/src/sdl/Makefile.cfg
+++ b/src/sdl/Makefile.cfg
@@ -53,28 +53,6 @@ ifndef NOHW
 	OBJS+=$(OBJDIR)/r_opengl.o $(OBJDIR)/ogl_sdl.o
 endif
 
-ifndef NOHS
-ifdef OPENAL
-	OBJS+=$(OBJDIR)/s_openal.o
-	OPTS+=-DSTATIC3DS
-	STATICHS=1
-else
-ifdef FMOD
-	OBJS+=$(OBJDIR)/s_fmod.o
-	OPTS+=-DSTATIC3DS
-	STATICHS=1
-else
-ifdef MINGW
-ifdef DS3D
-	OBJS+=$(OBJDIR)/s_ds3d.o
-	OPTS+=-DSTATIC3DS
-	STATICHS=1
-endif
-endif
-endif
-endif
-endif
-
 ifdef NOMIXER
 	i_sound_o=$(OBJDIR)/sdl_sound.o
 else
@@ -88,6 +66,11 @@ else
 endif
 endif
 
+ifndef NOTHREADS
+	OPTS+=-DHAVE_THREADS
+	OBJS+=$(OBJDIR)/i_threads.o
+endif
+
 ifdef SDL_TTF
 	OPTS+=-DHAVE_TTF
 	SDL_LDFLAGS+=-lSDL2_ttf -lfreetype -lz
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index ce359f739312720b9373f8e1b024a88989cec139..755fa68e6768e84d8ec2563d863591ccac1854ee 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -251,6 +251,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\http-mserv.h" />
     <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
@@ -406,6 +407,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\http-mserv.c" />
     <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index b37f2c6954f6a4fc4a9e0d55aab34c56f30c7928..3bbcd9cb57efeb3f725edacfa05de81ccbc54691 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -297,6 +297,9 @@
     <ClInclude Include="..\mserv.h">
       <Filter>I_Interface</Filter>
     </ClInclude>
+    <ClInclude Include="..\http-mserv.h">
+      <Filter>I_Interface</Filter>
+    </ClInclude>
     <ClInclude Include="..\lua_hook.h">
       <Filter>LUA</Filter>
     </ClInclude>
@@ -687,6 +690,9 @@
     <ClCompile Include="..\mserv.c">
       <Filter>I_Interface</Filter>
     </ClCompile>
+    <ClCompile Include="..\http-mserv.c">
+      <Filter>I_Interface</Filter>
+    </ClCompile>
     <ClCompile Include="..\lua_baselib.c">
       <Filter>LUA</Filter>
     </ClCompile>
diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj
index cfa49ea502873a6dbe393544a61f77c2aed52010..3c430b2b4af5a85ca641d0df1557ff9e90215604 100644
--- a/src/sdl/Srb2SDL-vc9.vcproj
+++ b/src/sdl/Srb2SDL-vc9.vcproj
@@ -2742,6 +2742,50 @@
 				RelativePath="..\mserv.h"
 				>
 			</File>
+			<File
+				RelativePath="..\http-mserv.c"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						AdditionalIncludeDirectories=""
+						PreprocessorDefinitions=""
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\http-mserv.h"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="M_Misc"
diff --git a/src/sdl/i_cdmus.c b/src/sdl/i_cdmus.c
deleted file mode 100644
index 5d086e73a05fdc7d28b23818a9141aa9edc650dc..0000000000000000000000000000000000000000
--- a/src/sdl/i_cdmus.c
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "../command.h"
-#include "../s_sound.h"
-#include "../i_sound.h"
-
-//
-// CD MUSIC I/O
-//
-
-UINT8 cdaudio_started = 0;
-
-consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-
-
-void I_InitCD(void){}
-
-void I_StopCD(void){}
-
-void I_PauseCD(void){}
-
-void I_ResumeCD(void){}
-
-void I_ShutdownCD(void){}
-
-void I_UpdateCD(void){}
-
-void I_PlayCD(UINT8 track, UINT8 looping)
-{
-	(void)track;
-	(void)looping;
-}
-
-FUNCMATH boolean I_SetVolumeCD(int volume)
-{
-	(void)volume;
-	return false;
-}
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index b24ae2814985d04b3674aaf5afa3c09628dcd78c..10c0747bf18b4e8fc725f4cfd3984a9183e79c56 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -173,6 +173,7 @@ static char returnWadPath[256];
 #include "../i_video.h"
 #include "../i_sound.h"
 #include "../i_system.h"
+#include "../i_threads.h"
 #include "../screen.h" //vid.WndParent
 #include "../d_net.h"
 #include "../g_game.h"
@@ -559,14 +560,12 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
 			case VK_TAB:
 				event.data1 = KEY_NULL;
 				break;
-			case VK_SHIFT:
-				event.data1 = KEY_LSHIFT;
-				break;
 			case VK_RETURN:
 				entering_con_command = false;
 				/* FALLTHRU */
 			default:
-				event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
+				//event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
+				event.data1 = evt.uChar.AsciiChar;
 		}
 		if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
 		{
@@ -585,18 +584,6 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
 			}
 		}
 	}
-	else
-	{
-		event.type = ev_keyup;
-		switch (evt.wVirtualKeyCode)
-		{
-			case VK_SHIFT:
-				event.data1 = KEY_LSHIFT;
-				break;
-			default:
-				break;
-		}
-	}
 	if (event.data1) D_PostEvent(&event);
 }
 
@@ -2282,6 +2269,10 @@ INT32 I_StartupSystem(void)
 	SDL_version SDLlinked;
 	SDL_VERSION(&SDLcompiled)
 	SDL_GetVersion(&SDLlinked);
+#ifdef HAVE_THREADS
+	I_start_threads();
+	I_AddExitFunc(I_stop_threads);
+#endif
 	I_StartupConsole();
 #ifdef NEWSIGNALHANDLER
 	I_Fork();
@@ -2328,7 +2319,6 @@ void I_Quit(void)
 	M_FreePlayerSetupColors();
 	I_ShutdownMusic();
 	I_ShutdownSound();
-	I_ShutdownCD();
 	// use this for 1.28 19990220 by Kin
 	I_ShutdownGraphics();
 	I_ShutdownInput();
@@ -2389,16 +2379,14 @@ void I_Error(const char *error, ...)
 		if (errorcount == 3)
 			I_ShutdownSound();
 		if (errorcount == 4)
-			I_ShutdownCD();
-		if (errorcount == 5)
 			I_ShutdownGraphics();
-		if (errorcount == 6)
+		if (errorcount == 5)
 			I_ShutdownInput();
-		if (errorcount == 7)
+		if (errorcount == 6)
 			I_ShutdownSystem();
-		if (errorcount == 8)
+		if (errorcount == 7)
 			SDL_Quit();
-		if (errorcount == 9)
+		if (errorcount == 8)
 		{
 			M_SaveConfig(NULL);
 			G_SaveGameData();
@@ -2446,7 +2434,6 @@ void I_Error(const char *error, ...)
 	M_FreePlayerSetupColors();
 	I_ShutdownMusic();
 	I_ShutdownSound();
-	I_ShutdownCD();
 	// use this for 1.28 19990220 by Kin
 	I_ShutdownGraphics();
 	I_ShutdownInput();
@@ -2601,7 +2588,7 @@ void I_GetDiskFreeSpace(INT64 *freespace)
 	return;
 #else // Both Linux and BSD have this, apparently.
 	struct statfs stfs;
-	if (statfs(".", &stfs) == -1)
+	if (statfs(srb2home, &stfs) == -1)
 	{
 		*freespace = INT32_MAX;
 		return;
@@ -2620,7 +2607,7 @@ void I_GetDiskFreeSpace(INT64 *freespace)
 	}
 	if (pfnGetDiskFreeSpaceEx)
 	{
-		if (pfnGetDiskFreeSpaceEx(NULL, &lfreespace, &usedbytes, NULL))
+		if (pfnGetDiskFreeSpaceEx(srb2home, &lfreespace, &usedbytes, NULL))
 			*freespace = lfreespace.QuadPart;
 		else
 			*freespace = INT32_MAX;
@@ -2726,10 +2713,10 @@ const char *I_ClipboardPaste(void)
 
 	if (!SDL_HasClipboardText())
 		return NULL;
+
 	clipboard_contents = SDL_GetClipboardText();
-	memcpy(clipboard_modified, clipboard_contents, 255);
+	strlcpy(clipboard_modified, clipboard_contents, 256);
 	SDL_free(clipboard_contents);
-	clipboard_modified[255] = 0;
 
 	while (*i)
 	{
diff --git a/src/sdl/i_threads.c b/src/sdl/i_threads.c
new file mode 100644
index 0000000000000000000000000000000000000000..3b1c20b9a3cbb79038253b4bd5b7dbec3df001d7
--- /dev/null
+++ b/src/sdl/i_threads.c
@@ -0,0 +1,356 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 2020 by James R.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  i_threads.c
+/// \brief Multithreading abstraction
+
+#include "../doomdef.h"
+#include "../i_threads.h"
+
+#include <SDL.h>
+
+typedef void * (*Create_fn)(void);
+
+struct Link;
+struct Thread;
+
+typedef struct Link   * Link;
+typedef struct Thread * Thread;
+
+struct Link
+{
+	void * data;
+	Link   next;
+	Link   prev;
+};
+
+struct Thread
+{
+	I_thread_fn   entry;
+	void        * userdata;
+
+	SDL_Thread  * thread;
+};
+
+static Link    i_thread_pool;
+static Link    i_mutex_pool;
+static Link    i_cond_pool;
+
+static I_mutex        i_thread_pool_mutex;
+static I_mutex        i_mutex_pool_mutex;
+static I_mutex        i_cond_pool_mutex;
+
+static SDL_atomic_t   i_threads_running = {1};
+
+static Link
+Insert_link (
+		Link * head,
+		Link   link
+){
+	link->prev = NULL;
+	link->next = (*head);
+	if ((*head))
+		(*head)->prev = link;
+	(*head)    = link;
+	return link;
+}
+
+static void
+Free_link (
+		Link * head,
+		Link   link
+){
+	if (link->prev)
+		link->prev->next = link->next;
+	else
+		(*head) = link->next;
+
+	if (link->next)
+		link->next->prev = link->prev;
+
+	free(link->data);
+	free(link);
+}
+
+static Link
+New_link (void *data)
+{
+	Link link;
+
+	link = malloc(sizeof *link);
+
+	if (! link)
+		abort();
+
+	link->data = data;
+
+	return link;
+}
+
+static void *
+Identity (
+		Link      *  pool_anchor,
+		I_mutex      pool_mutex,
+
+		void      ** anchor,
+
+		Create_fn    create_fn
+){
+	void * id;
+
+	id = SDL_AtomicGetPtr(anchor);
+
+	if (! id)
+	{
+		I_lock_mutex(&pool_mutex);
+		{
+			id = SDL_AtomicGetPtr(anchor);
+
+			if (! id)
+			{
+				id = (*create_fn)();
+
+				if (! id)
+					abort();
+
+				Insert_link(pool_anchor, New_link(id));
+
+				SDL_AtomicSetPtr(anchor, id);
+			}
+		}
+		I_unlock_mutex(pool_mutex);
+	}
+
+	return id;
+}
+
+static int
+Worker (
+		Link link
+){
+	Thread th;
+
+	th = link->data;
+
+	(*th->entry)(th->userdata);
+
+	if (SDL_AtomicGet(&i_threads_running))
+	{
+		I_lock_mutex(&i_thread_pool_mutex);
+		{
+			if (SDL_AtomicGet(&i_threads_running))
+			{
+				SDL_DetachThread(th->thread);
+				Free_link(&i_thread_pool, link);
+			}
+		}
+		I_unlock_mutex(i_thread_pool_mutex);
+	}
+
+	return 0;
+}
+
+void
+I_spawn_thread (
+		const char  * name,
+		I_thread_fn   entry,
+		void        * userdata
+){
+	Link   link;
+	Thread th;
+
+	th = malloc(sizeof *th);
+
+	if (! th)
+		abort();/* this is pretty GNU of me */
+
+	th->entry    = entry;
+	th->userdata = userdata;
+
+	I_lock_mutex(&i_thread_pool_mutex);
+	{
+		link = Insert_link(&i_thread_pool, New_link(th));
+
+		if (SDL_AtomicGet(&i_threads_running))
+		{
+			th->thread = SDL_CreateThread(
+					(SDL_ThreadFunction)Worker,
+					name,
+					link
+			);
+
+			if (! th->thread)
+				abort();
+		}
+	}
+	I_unlock_mutex(i_thread_pool_mutex);
+}
+
+int
+I_thread_is_stopped (void)
+{
+	return ( ! SDL_AtomicGet(&i_threads_running) );
+}
+
+void
+I_start_threads (void)
+{
+	i_thread_pool_mutex = SDL_CreateMutex();
+	i_mutex_pool_mutex  = SDL_CreateMutex();
+	i_cond_pool_mutex   = SDL_CreateMutex();
+
+	if (!(
+				i_thread_pool_mutex &&
+				i_mutex_pool_mutex  &&
+				i_cond_pool_mutex
+	)){
+		abort();
+	}
+}
+
+void
+I_stop_threads (void)
+{
+	Link        link;
+	Link        next;
+
+	Thread      th;
+	SDL_mutex * mutex;
+	SDL_cond  * cond;
+
+	if (i_threads_running.value)
+	{
+		/* rely on the good will of thread-san */
+		SDL_AtomicSet(&i_threads_running, 0);
+
+		I_lock_mutex(&i_thread_pool_mutex);
+		{
+			for (
+					link = i_thread_pool;
+					link;
+					link = next
+			){
+				next = link->next;
+				th   = link->data;
+
+				SDL_WaitThread(th->thread, NULL);
+
+				free(th);
+				free(link);
+			}
+		}
+		I_unlock_mutex(i_thread_pool_mutex);
+
+		for (
+				link = i_mutex_pool;
+				link;
+				link = next
+		){
+			next  = link->next;
+			mutex = link->data;
+
+			SDL_DestroyMutex(mutex);
+
+			free(link);
+		}
+
+		for (
+				link = i_cond_pool;
+				link;
+				link = next
+		){
+			next = link->next;
+			cond = link->data;
+
+			SDL_DestroyCond(cond);
+
+			free(link);
+		}
+
+		SDL_DestroyMutex(i_thread_pool_mutex);
+		SDL_DestroyMutex(i_mutex_pool_mutex);
+		SDL_DestroyMutex(i_cond_pool_mutex);
+	}
+}
+
+void
+I_lock_mutex (
+		I_mutex * anchor
+){
+	SDL_mutex * mutex;
+
+	mutex = Identity(
+			&i_mutex_pool,
+			i_mutex_pool_mutex,
+			anchor,
+			(Create_fn)SDL_CreateMutex
+	);
+
+	if (SDL_LockMutex(mutex) == -1)
+		abort();
+}
+
+void
+I_unlock_mutex (
+		I_mutex id
+){
+	if (SDL_UnlockMutex(id) == -1)
+		abort();
+}
+
+void
+I_hold_cond (
+		I_cond  * cond_anchor,
+		I_mutex   mutex_id
+){
+	SDL_cond * cond;
+
+	cond = Identity(
+			&i_cond_pool,
+			i_cond_pool_mutex,
+			cond_anchor,
+			(Create_fn)SDL_CreateCond
+	);
+
+	if (SDL_CondWait(cond, mutex_id) == -1)
+		abort();
+}
+
+void
+I_wake_one_cond (
+		I_cond * anchor
+){
+	SDL_cond * cond;
+
+	cond = Identity(
+			&i_cond_pool,
+			i_cond_pool_mutex,
+			anchor,
+			(Create_fn)SDL_CreateCond
+	);
+
+	if (SDL_CondSignal(cond) == -1)
+		abort();
+}
+
+void
+I_wake_all_cond (
+		I_cond * anchor
+){
+	SDL_cond * cond;
+
+	cond = Identity(
+			&i_cond_pool,
+			i_cond_pool_mutex,
+			anchor,
+			(Create_fn)SDL_CreateCond
+	);
+
+	if (SDL_CondBroadcast(cond) == -1)
+		abort();
+}
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 3e31e4450e387b114ce6ef742742522b3c7b8045..974b804f3ad04c8bcdd8fa71b3957793600a026d 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -100,9 +100,9 @@ rendermode_t chosenrendermode = render_none; // set by command line arguments
 boolean highcolor = false;
 
 // synchronize page flipping with screen refresh
-consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_stretch = {"stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_alwaysgrabmouse = {"alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
+static consvar_t cv_stretch = CVAR_INIT ("stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL);
+static consvar_t cv_alwaysgrabmouse = CVAR_INIT ("alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL);
 
 UINT8 graphics_started = 0; // Is used in console.c and screen.c
 
@@ -1478,6 +1478,7 @@ static SDL_bool Impl_CreateContext(void)
 
 void VID_CheckGLLoaded(rendermode_t oldrender)
 {
+	(void)oldrender;
 #ifdef HWRENDER
 	if (vid.glstate == VID_GL_LIBRARY_ERROR) // Well, it didn't work the first time anyway.
 	{
@@ -1485,9 +1486,11 @@ void VID_CheckGLLoaded(rendermode_t oldrender)
 		rendermode = oldrender;
 		if (chosenrendermode == render_opengl) // fallback to software
 			rendermode = render_soft;
-
-		CV_StealthSetValue(&cv_renderer, oldrender);
-		CV_StealthSetValue(&cv_newrenderer, oldrender);
+		if (setrenderneeded)
+		{
+			CV_StealthSetValue(&cv_renderer, oldrender);
+			setrenderneeded = 0;
+		}
 	}
 #endif
 }
diff --git a/src/sdl/macosx/Srb2mac.icns b/src/sdl/macosx/Srb2mac.icns
index a3e37aab3ee846900a873610f7d8d66fd34bfda3..2ac2faf33e1ec211c5648e417befedce9b1eece2 100644
Binary files a/src/sdl/macosx/Srb2mac.icns and b/src/sdl/macosx/Srb2mac.icns differ
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index ef34b266df277eefe4bbbb8a19c8139fac7b0523..c64164caafce5b52698e564a2514d57fa7a7eeda 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -196,9 +196,9 @@ static void MidiSoundfontPath_Onchange(void)
 // make sure that s_sound.c does not already verify these
 // which happens when: defined(HAVE_MIXERX) && !defined(HAVE_MIXER)
 static CV_PossibleValue_t midiplayer_cons_t[] = {{MIDI_OPNMIDI, "OPNMIDI"}, {MIDI_Fluidsynth, "Fluidsynth"}, {MIDI_Timidity, "Timidity"}, {MIDI_Native, "Native"}, {0, NULL}};
-consvar_t cv_midiplayer = {"midiplayer", "OPNMIDI" /*MIDI_OPNMIDI*/, CV_CALL|CV_NOINIT|CV_SAVE, midiplayer_cons_t, Midiplayer_Onchange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_midisoundfontpath = {"midisoundfont", "sf2/8bitsf.SF2", CV_CALL|CV_NOINIT|CV_SAVE, NULL, MidiSoundfontPath_Onchange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_miditimiditypath = {"midisoundbank", "./timidity", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_midiplayer = CVAR_INIT ("midiplayer", "OPNMIDI" /*MIDI_OPNMIDI*/, CV_CALL|CV_NOINIT|CV_SAVE, midiplayer_cons_t, Midiplayer_Onchange);
+consvar_t cv_midisoundfontpath = CVAR_INIT ("midisoundfont", "sf2/8bitsf.SF2", CV_CALL|CV_NOINIT|CV_SAVE, NULL, MidiSoundfontPath_Onchange);
+consvar_t cv_miditimiditypath = CVAR_INIT ("midisoundbank", "./timidity", CV_SAVE, NULL, NULL);
 #endif
 
 static void var_cleanup(void)
@@ -220,6 +220,7 @@ static void var_cleanup(void)
 	internal_volume = 100;
 }
 
+#if defined (HAVE_LIBGME) && defined (HAVE_ZLIB)
 static const char* get_zlib_error(int zErr)
 {
 	switch (zErr)
@@ -240,6 +241,7 @@ static const char* get_zlib_error(int zErr)
 			return "unknown error";
 	}
 }
+#endif
 
 /// ------------------------
 /// Audio System
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index edc69b21d5067c264bf16e6df8739fac8b0dced9..04214ad03e3031f2f3de772b5c60aa46b02ebc10 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -167,6 +167,18 @@ boolean OglSdlSurface(INT32 w, INT32 h)
 		GL_DBG_Printf("OpenGL %s\n", gl_version);
 		GL_DBG_Printf("GPU: %s\n", gl_renderer);
 		GL_DBG_Printf("Extensions: %s\n", gl_extensions);
+
+		if (strcmp((const char*)gl_renderer, "GDI Generic") == 0 &&
+			strcmp((const char*)gl_version, "1.1.0") == 0)
+		{
+			// Oh no... Windows gave us the GDI Generic rasterizer, so something is wrong...
+			// The game will crash later on when unsupported OpenGL commands are encountered.
+			// Instead of a nondescript crash, show a more informative error message.
+			// Also set the renderer variable back to software so the next launch won't
+			// repeat this error.
+			CV_StealthSet(&cv_renderer, "Software");
+			I_Error("OpenGL Error: Failed to access the GPU. There may be an issue with your graphics drivers.");
+		}
 	}
 	first_init = true;
 
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 5f3d75f44469991784f4d79f40a780befc3bcb41..45e498323cdb9cd63423b2fbb90d2ad221190db3 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1126,7 +1126,7 @@ static void ST_drawInput(void)
 	V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, hudinfo[HUD_LIVES].f|symb, false)
 
 	drawbutt( 4,-3, BT_JUMP, 'J');
-	drawbutt(15,-3, BT_USE,  'S');
+	drawbutt(15,-3, BT_SPIN, 'S');
 
 	V_DrawFill(x+16+4, y+8, 21, 10, hudinfo[HUD_LIVES].f|20); // sundial backing
 	if (stplyr->mo)
@@ -2195,7 +2195,7 @@ static void ST_drawMatchHUD(void)
 		{
 			sprintf(penaltystr, "-%d", stplyr->ammoremoval);
 			V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y,
-					V_REDMAP, penaltystr);
+				V_REDMAP|V_SNAPTOBOTTOM, penaltystr);
 		}
 
 	}
diff --git a/src/v_video.c b/src/v_video.c
index 89ffea6cf70a785201781e87c7eb7ca155677ac9..9aeded61738cdb8f668c43fadf6a810003f01735 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -43,47 +43,45 @@ UINT8 *screens[5];
 // screens[4] = fade screen end, postimage tempoarary buffer
 
 static CV_PossibleValue_t ticrate_cons_t[] = {{0, "No"}, {1, "Full"}, {2, "Compact"}, {0, NULL}};
-consvar_t cv_ticrate = {"showfps", "No", CV_SAVE, ticrate_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_ticrate = CVAR_INIT ("showfps", "No", CV_SAVE, ticrate_cons_t, NULL);
 
 static void CV_palette_OnChange(void);
 
 static CV_PossibleValue_t gamma_cons_t[] = {{-15, "MIN"}, {5, "MAX"}, {0, NULL}};
-consvar_t cv_globalgamma = {"gamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_globalgamma = CVAR_INIT ("gamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
 
 static CV_PossibleValue_t saturation_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
-consvar_t cv_globalsaturation = {"saturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_globalsaturation = CVAR_INIT ("saturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
 
 #define huecoloursteps 4
 
 static CV_PossibleValue_t hue_cons_t[] = {{0, "MIN"}, {(huecoloursteps*6)-1, "MAX"}, {0, NULL}};
-consvar_t cv_rhue = {"rhue",  "0", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_yhue = {"yhue",  "4", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ghue = {"ghue",  "8", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_chue = {"chue", "12", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_bhue = {"bhue", "16", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mhue = {"mhue", "20", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_rgamma = {"rgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ygamma = {"ygamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ggamma = {"ggamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_cgamma = {"cgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_bgamma = {"bgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_mgamma = {"mgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_rsaturation = {"rsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_ysaturation = {"ysaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_gsaturation = {"gsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_csaturation = {"csaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_bsaturation = {"bsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_msaturation = {"msaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-consvar_t cv_allcaps = {"allcaps", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_rhue = CVAR_INIT ("rhue",  "0", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
+consvar_t cv_yhue = CVAR_INIT ("yhue",  "4", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
+consvar_t cv_ghue = CVAR_INIT ("ghue",  "8", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
+consvar_t cv_chue = CVAR_INIT ("chue", "12", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
+consvar_t cv_bhue = CVAR_INIT ("bhue", "16", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
+consvar_t cv_mhue = CVAR_INIT ("mhue", "20", CV_SAVE|CV_CALL, hue_cons_t, CV_palette_OnChange);
+
+consvar_t cv_rgamma = CVAR_INIT ("rgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
+consvar_t cv_ygamma = CVAR_INIT ("ygamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
+consvar_t cv_ggamma = CVAR_INIT ("ggamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
+consvar_t cv_cgamma = CVAR_INIT ("cgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
+consvar_t cv_bgamma = CVAR_INIT ("bgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
+consvar_t cv_mgamma = CVAR_INIT ("mgamma", "0", CV_SAVE|CV_CALL, gamma_cons_t, CV_palette_OnChange);
+
+consvar_t cv_rsaturation = CVAR_INIT ("rsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
+consvar_t cv_ysaturation = CVAR_INIT ("ysaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
+consvar_t cv_gsaturation = CVAR_INIT ("gsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
+consvar_t cv_csaturation = CVAR_INIT ("csaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
+consvar_t cv_bsaturation = CVAR_INIT ("bsaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
+consvar_t cv_msaturation = CVAR_INIT ("msaturation", "10", CV_SAVE|CV_CALL, saturation_cons_t, CV_palette_OnChange);
 
 static CV_PossibleValue_t constextsize_cons_t[] = {
 	{V_NOSCALEPATCH, "Small"}, {V_SMALLSCALEPATCH, "Medium"}, {V_MEDSCALEPATCH, "Large"}, {0, "Huge"},
 	{0, NULL}};
 static void CV_constextsize_OnChange(void);
-consvar_t cv_constextsize = {"con_textsize", "Medium", CV_SAVE|CV_CALL, constextsize_cons_t, CV_constextsize_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_constextsize = CVAR_INIT ("con_textsize", "Medium", CV_SAVE|CV_CALL, constextsize_cons_t, CV_constextsize_OnChange);
 
 // local copy of the palette for V_GetColor()
 RGBA_t *pLocalPalette = NULL;
@@ -2120,6 +2118,9 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	switch (option & V_SPACINGMASK)
 	{
 		case V_MONOSPACE:
@@ -2233,6 +2234,9 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	charflags = (option & V_CHARCOLORMASK);
 
 	switch (option & V_SPACINGMASK)
@@ -2348,6 +2352,9 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	charflags = (option & V_CHARCOLORMASK);
 
 	switch (option & V_SPACINGMASK)
@@ -2483,6 +2490,9 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string)
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	charflags = (option & V_CHARCOLORMASK);
 
 	switch (option & V_SPACINGMASK)
@@ -2596,6 +2606,9 @@ void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *st
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	charflags = (option & V_CHARCOLORMASK);
 
 	switch (option & V_SPACINGMASK)
@@ -2710,6 +2723,9 @@ void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *str
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	charflags = (option & V_CHARCOLORMASK);
 
 	switch (option & V_SPACINGMASK)
@@ -2824,6 +2840,9 @@ void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	charflags = (option & V_CHARCOLORMASK);
 
 	switch (option & V_SPACINGMASK)
@@ -2917,7 +2936,7 @@ void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num)
 	INT32 w = SHORT(tallnum[0]->width);
 	boolean neg;
 
-	if (flags & V_NOSCALESTART)
+	if (flags & (V_NOSCALESTART|V_NOSCALEPATCH))
 		w *= vid.dupx;
 
 	if ((neg = num < 0))
@@ -2942,7 +2961,7 @@ void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits)
 {
 	INT32 w = SHORT(tallnum[0]->width);
 
-	if (flags & V_NOSCALESTART)
+	if (flags & (V_NOSCALESTART|V_NOSCALEPATCH))
 		w *= vid.dupx;
 
 	if (num < 0)
@@ -2995,6 +3014,9 @@ void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string)
 	else
 		dupx = dupy = 1;
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	for (;;)
 	{
 		c = *ch++;
@@ -3052,6 +3074,9 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	for (;;ch++)
 	{
 		if (!*ch)
@@ -3267,6 +3292,9 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
 		scrwidth -= left;
 	}
 
+	if (option & V_NOSCALEPATCH)
+		scrwidth *= vid.dupx;
+
 	for (;;ch++)
 	{
 		if (!*ch)
@@ -3402,8 +3430,8 @@ INT32 V_StringWidth(const char *string, INT32 option)
 			w += (charwidth ? charwidth : SHORT(hu_font[c]->width));
 	}
 
-	if (option & V_NOSCALESTART)
-	w *= vid.dupx;
+	if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
+		w *= vid.dupx;
 
 	return w;
 }
@@ -3666,28 +3694,51 @@ Unoptimized version
 #endif
 }
 
-// Generates a color look-up table
-// which has up to 64 colors at each channel
-// (see the defines in v_video.h)
-
-UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE];
-
-void InitColorLUT(RGBA_t *palette)
+// Generates a RGB565 color look-up table
+void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors)
 {
-	UINT8 r, g, b;
-	static boolean clutinit = false;
-	static RGBA_t *lastpalette = NULL;
-	if ((!clutinit) || (lastpalette != palette))
+	size_t palsize = (sizeof(RGBA_t) * 256);
+
+	if (!lut->init || memcmp(lut->palette, palette, palsize))
 	{
-		for (r = 0; r < CLUTSIZE; r++)
-			for (g = 0; g < CLUTSIZE; g++)
-				for (b = 0; b < CLUTSIZE; b++)
-					colorlookup[r][g][b] = NearestPaletteColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS, palette);
-		clutinit = true;
-		lastpalette = palette;
+		INT32 i;
+
+		lut->init = true;
+		memcpy(lut->palette, palette, palsize);
+
+		for (i = 0; i < 0xFFFF; i++)
+			lut->table[i] = 0xFFFF;
+
+		if (makecolors)
+		{
+			UINT8 r, g, b;
+
+			for (r = 0; r < 0xFF; r++)
+			for (g = 0; g < 0xFF; g++)
+			for (b = 0; b < 0xFF; b++)
+			{
+				i = CLUTINDEX(r, g, b);
+				if (lut->table[i] == 0xFFFF)
+					lut->table[i] = NearestPaletteColor(r, g, b, palette);
+			}
+		}
 	}
 }
 
+UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b)
+{
+	INT32 i = CLUTINDEX(r, g, b);
+	if (lut->table[i] == 0xFFFF)
+		lut->table[i] = NearestPaletteColor(r, g, b, lut->palette);
+	return lut->table[i];
+}
+
+UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b)
+{
+	INT32 i = CLUTINDEX(r, g, b);
+	return lut->table[i];
+}
+
 // V_Init
 // old software stuff, buffers are allocated at video mode setup
 // here we set the screens[x] pointers accordingly
diff --git a/src/v_video.h b/src/v_video.h
index 96bc7db89ae1fe6ba22d50e309eb5aedef7836d0..8a18f82ad7ab834988e672e3f5c21189764876b6 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -27,12 +27,11 @@
 
 extern UINT8 *screens[5];
 
-extern consvar_t cv_ticrate, cv_constextsize,\
-cv_globalgamma, cv_globalsaturation, \
-cv_rhue, cv_yhue, cv_ghue, cv_chue, cv_bhue, cv_mhue,\
-cv_rgamma, cv_ygamma, cv_ggamma, cv_cgamma, cv_bgamma, cv_mgamma, \
-cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, cv_msaturation,\
-cv_allcaps;
+extern consvar_t cv_ticrate, cv_constextsize,
+cv_globalgamma, cv_globalsaturation,
+cv_rhue, cv_yhue, cv_ghue, cv_chue, cv_bhue, cv_mhue,
+cv_rgamma, cv_ygamma, cv_ggamma, cv_cgamma, cv_bgamma, cv_mgamma,
+cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, cv_msaturation;
 
 // Allocates buffer screens, call before R_Init.
 void V_Init(void);
@@ -41,13 +40,18 @@ void V_Init(void);
 void V_Recalc(void);
 
 // Color look-up table
-#define COLORBITS 6
-#define SHIFTCOLORBITS (8-COLORBITS)
-#define CLUTSIZE (1<<COLORBITS)
-
-extern UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE];
-
-void InitColorLUT(RGBA_t *palette);
+#define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)
+
+typedef struct
+{
+	boolean init;
+	RGBA_t palette[256];
+	UINT16 table[0xFFFF];
+} colorlookup_t;
+
+void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors);
+UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b);
+UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b);
 
 // Set the current RGB palette lookup to use for palettized graphics
 void V_SetPalette(INT32 palettenum);
diff --git a/src/version.h b/src/version.h
index 31cf85bdcdfae7d462bc1786f752bf3bd673eb82..ece084beb2ddaed925f436d78fcfd290d94c57c5 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
-#define SRB2VERSION "2.2.6"/* this must be the first line, for cmake !! */
+#define SRB2VERSION "2.2.8"/* this must be the first line, for cmake !! */
 
 // The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ).
 // DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
@@ -9,4 +9,7 @@
 // it's only for detection of the version the player is using so the MS can alert them of an update.
 // Only set it higher, not lower, obviously.
 // Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1".
-#define MODVERSION 47
+#define MODVERSION 49
+
+// Define this as a prerelease version suffix
+// #define BETAVERSION "RC1"
diff --git a/src/w_wad.c b/src/w_wad.c
index 1a1e08da92b67e2c4417ddab15585b126dce5324..a966fd3241e1bbfa63437ca8cd6f29879519ec84 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -72,12 +72,6 @@
 #include "hardware/hw_glob.h"
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-int	snprintf(char *str, size_t n, const char *fmt, ...);
-//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
 #ifdef _DEBUG
 #include "console.h"
 #endif
@@ -784,6 +778,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
 		if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
 		{
 			CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
+			if (important)
+				packetsizetally -= nameonlylength(filename) + 22;
 			if (handle)
 				fclose(handle);
 			return W_InitFileError(filename, false);
@@ -887,16 +883,13 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
   *
   * \param filenames A null-terminated list of files to use.
   */
-void W_InitMultipleFiles(char **filenames, UINT16 mainfiles)
+void W_InitMultipleFiles(char **filenames)
 {
-	// open all the files, load headers, and count lumps
-	numwadfiles = 0;
-
 	// will be realloced as lumps are added
 	for (; *filenames; filenames++)
 	{
 		//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
-		W_InitFile(*filenames, numwadfiles < mainfiles, true);
+		W_InitFile(*filenames, numwadfiles < mainwads, true);
 	}
 }
 
@@ -1683,8 +1676,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 		if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
 		{
 			size_t newlen;
-			INT32 pngwidth, pngheight; // Dummy variables.
-			void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, &pngwidth, &pngheight, NULL, NULL, len, &newlen, 0);
+			void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &newlen, 0);
 			ptr = Z_Malloc(newlen, PU_STATIC, NULL);
 			M_Memcpy(ptr, converted, newlen);
 			Z_Free(converted);
diff --git a/src/w_wad.h b/src/w_wad.h
index ee3df9cf4e5f8114ededdbcc6a33966d907b49c8..1e86eea5a6b2ac991d26d47b98cf3416f4de5b2b 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -143,7 +143,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors);
 UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup);
 
 // W_InitMultipleFiles exits if a file was not found, but not if all is okay.
-void W_InitMultipleFiles(char **filenames, UINT16 mainfiles);
+void W_InitMultipleFiles(char **filenames);
 
 const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
 const char *W_CheckNameForNum(lumpnum_t lumpnum);
diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg
index 27926b2085cdbd282fe9113d3a0f3346281295df..bf68f8c9793d7baeca356a8ee5fba71d116a257b 100644
--- a/src/win32/Makefile.cfg
+++ b/src/win32/Makefile.cfg
@@ -154,3 +154,12 @@ else
 	LDFLAGS+=-L../libs/miniupnpc/mingw32
 endif #MINGW64
 endif
+
+ifndef NOCURL
+	CURL_CFLAGS+=-I../libs/curl/include
+ifdef MINGW64
+	CURL_LDFLAGS+=-L../libs/curl/lib64 -lcurl
+else
+	CURL_LDFLAGS+=-L../libs/curl/lib32 -lcurl
+endif #MINGW64
+endif
\ No newline at end of file
diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc
index b90947a9ece7d48c1166bad85861374687923048..d5d59922c113a29af52c673700d8600b8be7804f 100644
--- a/src/win32/Srb2win.rc
+++ b/src/win32/Srb2win.rc
@@ -22,6 +22,16 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 #pragma code_page(1252)
 #endif //_WIN32*/
 
+#ifndef RT_MANIFEST
+#define RT_MANIFEST 24
+#endif
+
+#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID
+#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
+#endif
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST srb2win.exe.manifest
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // Icon
@@ -66,8 +76,8 @@ END
 #include "../doomdef.h" // Needed for version string
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,2,6,0
- PRODUCTVERSION 2,2,6,0
+ FILEVERSION 2,2,8,0
+ PRODUCTVERSION 2,2,8,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -85,14 +95,14 @@ BEGIN
             VALUE "Comments", "Visit our web site at www.srb2.org for news and updates!\0"
             VALUE "CompanyName", "Sonic Team Junior\0"
             VALUE "FileDescription", "Sonic Robo Blast 2\0"
-            VALUE "FileVersion", VERSIONSTRING
+            VALUE "FileVersion", VERSIONSTRING_RC
             VALUE "InternalName", "srb2\0"
             VALUE "LegalCopyright", "Copyright 1998-2020 by Sonic Team Junior\0"
             VALUE "LegalTrademarks", "Sonic the Hedgehog and related characters are trademarks of Sega.\0"
             VALUE "OriginalFilename", "srb2win.exe\0"
             VALUE "PrivateBuild", "\0"
             VALUE "ProductName", "Sonic Robo Blast 2\0"
-            VALUE "ProductVersion", VERSIONSTRING
+            VALUE "ProductVersion", VERSIONSTRING_RC
             VALUE "SpecialBuild", "\0"
         END
     END
diff --git a/src/win32/srb2win.exe.manifest b/src/win32/srb2win.exe.manifest
new file mode 100644
index 0000000000000000000000000000000000000000..d3b8355cbdea8194f1d94b8dd70c13509e8511ef
--- /dev/null
+++ b/src/win32/srb2win.exe.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker"/>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!--The ID below indicates application support for Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+      <!--The ID below indicates application support for Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <!--The ID below indicates application support for Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!--The ID below indicates application support for Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+    </application>
+  </compatibility>
+</assembly>
diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c
index 2586b84405649d431e673d1f7c8e4bb3a4d27a9c..324c2492848a4a78e9f1c22542cc6180533a59ab 100644
--- a/src/win32/win_cd.c
+++ b/src/win32/win_cd.c
@@ -161,13 +161,13 @@ static BOOL wasPlaying;
 //static INT     cdVolume = 0;          // current cd volume (0-31)
 
 // 0-31 like Music & Sfx, though CD hardware volume is 0-255.
-consvar_t cd_volume = {"cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cd_volume = CVAR_INIT ("cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL);
 
 // allow Update for next/loop track
 // some crap cd drivers take up to
 // a second for a simple 'busy' check..
 // (on those Update can be disabled)
-consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cdUpdate  = CVAR_INIT ("cd_update","1",CV_SAVE, NULL, NULL);
 
 #if (__GNUC__ > 6)
 #pragma GCC diagnostic push
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index 54526975ef02308228745d8fcb32601191531b34..4743cec34b2e6af738caeec60d7c179e58ec14d1 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -102,7 +102,7 @@ static loadfunc_t hwdFuncTable[] = {
 	{"FinishUpdate@4",      &hwdriver.pfnFinishUpdate},
 	{"Draw2DLine@12",       &hwdriver.pfnDraw2DLine},
 	{"DrawPolygon@16",      &hwdriver.pfnDrawPolygon},
-	{"RenderSkyDome@16",    &hwdriver.pfnRenderSkyDome},
+	{"RenderSkyDome@4",     &hwdriver.pfnRenderSkyDome},
 	{"SetBlend@4",          &hwdriver.pfnSetBlend},
 	{"ClearBuffer@12",      &hwdriver.pfnClearBuffer},
 	{"SetTexture@4",        &hwdriver.pfnSetTexture},
diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c
index a374a2587b0b9d9c01786aa9696a4d58f34b2980..da0d5b47ee3c26699b4d538575a22b8dc7420218 100644
--- a/src/win32/win_sys.c
+++ b/src/win32/win_sys.c
@@ -3658,7 +3658,7 @@ const CPUInfoFlags *I_CPUInfo(void)
 }
 
 static void CPUAffinity_OnChange(void);
-static consvar_t cv_cpuaffinity = {"cpuaffinity", "-1", CV_CALL, NULL, CPUAffinity_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_cpuaffinity = CVAR_INIT ("cpuaffinity", "-1", CV_CALL, NULL, CPUAffinity_OnChange);
 
 typedef HANDLE (WINAPI *p_GetCurrentProcess) (VOID);
 static p_GetCurrentProcess pfnGetCurrentProcess = NULL;
diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c
index 6a74a08d25c9033f3f47d2e5665f2e77095c34b5..7a33e19311f876fe595b72f7552fcf55f0af23fd 100644
--- a/src/win32/win_vid.c
+++ b/src/win32/win_vid.c
@@ -52,9 +52,9 @@ rendermode_t chosenrendermode = render_none; // set by command line arguments
 static void OnTop_OnChange(void);
 // synchronize page flipping with screen refresh
 static CV_PossibleValue_t CV_NeverOnOff[] = {{-1, "Never"}, {0, "Off"}, {1, "On"}, {0, NULL}};
-consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, OnTop_OnChange, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_stretch = {"stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
-static consvar_t cv_ontop = {"ontop", "Never", 0, CV_NeverOnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, OnTop_OnChange);
+static consvar_t cv_stretch = CVAR_INIT ("stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL);
+static consvar_t cv_ontop = CVAR_INIT ("ontop", "Never", 0, CV_NeverOnOff, NULL);
 
 boolean highcolor;
 
diff --git a/src/y_inter.c b/src/y_inter.c
index 961311593f374bd331395d9ded9b14c07d166349..acdf5f8d74c478d81348710e28669e474601634c 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -43,12 +43,6 @@
 #include "hardware/hw_main.h"
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-int	snprintf(char *str, size_t n, const char *fmt, ...);
-//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
 typedef struct
 {
 	char patch[9];
@@ -995,7 +989,7 @@ void Y_Ticker(void)
 			return;
 
 		for (i = 0; i < MAXPLAYERS; i++)
-			if (playeringame[i] && (players[i].cmd.buttons & BT_USE))
+			if (playeringame[i] && (players[i].cmd.buttons & BT_SPIN))
 				skip = true;
 
 		// bonuses count down by 222 each tic
@@ -1072,7 +1066,7 @@ void Y_Ticker(void)
 		for (i = 0; i < MAXPLAYERS; i++)
 			if (playeringame[i])
 			{
-				if (players[i].cmd.buttons & BT_USE)
+				if (players[i].cmd.buttons & BT_SPIN)
 					skip = true;
 				if (players[i].charflags & SF_SUPER)
 					super = true;