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/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 1909cd71afbb5e2acf1efdfd5a218b44cef09316..18f92955a7e3cba7f6b31ef8f929664a3b700770 100644
--- a/src/android/i_video.c
+++ b/src/android/i_video.c
@@ -16,7 +16,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/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 a6de7823d6ab513ebd916decea035bd8b2789eca..a6f43a7d7b6ab1df4f2abc00e110b97c4290a0cd 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -32,13 +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 / 01 - v2.2.7 - 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  "97b440b48139c53fa666b585a4e208f2"
+#define ASSET_HASH_PATCH_PK3  "466cdf60075262b3f5baa5e07f0999e8"
 #endif
 
 #endif
diff --git a/src/console.c b/src/console.c
index 21f660a56bc2914294a52246feb907e6be5c2cd4..3eee67bb843e2479c0b86bcd3734288601cb0417 100644
--- a/src/console.c
+++ b/src/console.c
@@ -124,22 +124,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"},
@@ -151,7 +151,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);
 
@@ -870,9 +870,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)
@@ -1007,7 +1012,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);
 
@@ -1023,6 +1027,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;
 		}
 		// ---
@@ -1091,43 +1103,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 (skips <= com_skips)
+		{
+			cmd = COM_CompleteCommand(completion, skips);
+
+			if (cmd && skips == com_skips)
+			{
+				com_skips  ++;
+				var_skips  ++;
+				alias_skips++;
 			}
 		}
 
-		if (comskips >= 0)
+		if (!cmd && skips <= var_skips)
 		{
-			cmd = COM_CompleteCommand(completion, comskips);
-			if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
-				comskips = -comskips - 1;
+			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;
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 9a636dd45555b901ef415ba56f4b74928fc3653c..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", "Off", 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)
 {
@@ -2513,11 +2519,11 @@ static boolean CL_ServerConnectionSearchTicker(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;
@@ -3161,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
@@ -3667,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);
 
@@ -3777,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;
 
@@ -5433,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;
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index ce8d87adb53079d2eb25e1a29aadd70a65eebac2..adc8a7cc9b090cf4bf5d5881f08070bf34ba1093 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -14,6 +14,7 @@
 #define __D_CLISRV__
 
 #include "d_ticcmd.h"
+#include "d_net.h"
 #include "d_netcmd.h"
 #include "d_net.h"
 #include "tables.h"
@@ -484,7 +485,7 @@ typedef struct
 #pragma pack()
 #endif
 
-#define MAXSERVERLIST 64 // Depends only on the display
+#define MAXSERVERLIST (MAXNETNODES-1)
 typedef struct
 {
 	SINT8 node;
@@ -526,6 +527,10 @@ 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)
diff --git a/src/d_main.c b/src/d_main.c
index ca2f71a588fda02927b6f47c65ce764231dba5fd..c4cde87a30e14527700a116dca7b0bd6a67c8f2e 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -99,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
 
@@ -495,6 +496,8 @@ static void D_Display(void)
 				lastdraw = false;
 			}
 
+			rs_uitime = I_GetTimeMicros();
+
 			if (gamestate == GS_LEVEL)
 			{
 				ST_Drawer();
@@ -504,6 +507,10 @@ static void D_Display(void)
 			else
 				F_TitleScreenDrawer();
 		}
+		else
+		{
+			rs_uitime = I_GetTimeMicros();
+		}
 	}
 
 	// change gamma if needed
@@ -544,6 +551,8 @@ static void D_Display(void)
 
 	CON_Drawer();
 
+	rs_uitime = I_GetTimeMicros() - rs_uitime;
+
 	//
 	// wipe update
 	//
@@ -657,8 +666,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);
@@ -691,8 +704,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);
 			}
 		}
 
@@ -961,12 +978,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);
@@ -976,16 +993,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;
 	}
 }
 
@@ -1070,7 +1087,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);
 
@@ -1081,14 +1098,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)
@@ -1098,7 +1115,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"); \
 		}
@@ -1288,7 +1305,7 @@ void D_SRB2Main(void)
 				{
 					if (!W_VerifyNMUSlumps(s))
 						G_SetGameModified(true);
-					D_AddFile(s);
+					D_AddFile(startuppwads, s);
 				}
 			}
 		}
@@ -1329,8 +1346,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)
 
@@ -1366,8 +1383,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();
@@ -1379,6 +1394,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()"
 
@@ -1567,6 +1589,12 @@ void D_SRB2Main(void)
 		ultimatemode = true;
 	}
 
+	if (M_CheckParm("-splitscreen"))
+	{
+		autostart = true;
+		splitscreen = true;
+	}
+
 	// rei/miru: bootmap (Idea: starts the game on a predefined map)
 	if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm()))
 	{
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 68b8ecfc1ad1ec65d56cd19de46bb62781a9917e..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;
@@ -865,9 +858,6 @@ void D_RegisterClientCommands(void)
 	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);
@@ -1126,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);
 		}
 	}
@@ -1302,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);
@@ -1463,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/dehacked.c b/src/dehacked.c
index 88a633976adab7d7cf4fa3a654e097008dbaf13a..c9a50e6d13a133f85a7e946965937f1360942898 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -9517,6 +9517,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},
diff --git a/src/doomdef.h b/src/doomdef.h
index 22d98d79291b2aa9e59d81e73c678dc20d246422..b9ee1ce5f59cb7bd3c66beab532256533550687b 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -129,11 +129,14 @@ 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!
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 56ead3672ae8ded9510814b20c766061a5d1d668..2b0478220eac8119ec36dff4b0b8a05cf92158fc 100644
--- a/src/dummy/i_video.c
+++ b/src/dummy/i_video.c
@@ -8,7 +8,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 b51e9c9a00b045255821b7985499c1aac3db88d1..57f8a87121dd096b49285f4c98025ad364720f7e 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -531,7 +531,7 @@ static void F_IntroDrawScene(void)
 	{
 		case 0:
 			bgxoffs = 28;
-			break;	
+			break;
 		case 1:
 			background = W_CachePatchName("INTRO1", PU_PATCH);
 			break;
@@ -620,7 +620,7 @@ static void F_IntroDrawScene(void)
 			V_DrawScaledPatch(bgxoffs, 0, 0, background);
 	}
 	else if (intro_scenenum == 0) // STJr presents
-	{	 
+	{
 		if (intro_curtime > 1 && intro_curtime < (INT32)introscenetime[intro_scenenum])
 		{
 			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
@@ -628,13 +628,13 @@ static void F_IntroDrawScene(void)
 				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) 
+			else if (intro_curtime == 2*TICRATE-19)
 			{
 				// 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);
-				
+
 				background = W_CachePatchName(stjrintro, PU_PATCH);
 				wipestyleflags = WSF_FADEIN;
 				F_WipeStartScreen();
@@ -643,7 +643,7 @@ static void F_IntroDrawScene(void)
 				F_WipeEndScreen();
 				F_RunWipe(0,true);
 			}
-			
+
 			if (!WipeInAction) // Draw the patch if not in a wipe
 			{
 				background = W_CachePatchName(stjrintro, PU_PATCH);
@@ -863,7 +863,7 @@ void F_IntroDrawer(void)
 				F_WipeEndScreen();
 				F_RunWipe(99,true);
 			}
-		
+
 			S_ChangeMusicInternal("_intro", false);
 		}
 		else if (intro_scenenum == 10)
@@ -1067,60 +1067,56 @@ 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\"",
@@ -1130,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",
@@ -1142,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\"",
@@ -1155,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",
@@ -1184,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\"",
@@ -1225,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",
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 b969eb4a4f2627c04f8e215dea33c71d3893cb9e..1ea7cd0809a4cfdf59242812421636b79cfc6bb9 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
@@ -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)
@@ -2013,7 +2019,7 @@ boolean G_Responder(event_t *ev)
 		if (F_CreditResponder(ev))
 		{
 			// Skip credits for everyone
-			if (! serverrunning)/* hahahahahaha */
+			if (! netgame)
 				F_StartGameEvaluation();
 			else if (server || IsPlayerAdmin(consoleplayer))
 				SendNetXCmd(XD_EXITLEVEL, NULL, 0);
@@ -2345,6 +2351,11 @@ void G_Ticker(boolean run)
 
 		if (camtoggledelay2)
 			camtoggledelay2--;
+
+		if (gametic % NAMECHANGERATE == 0)
+		{
+			memset(player_name_changes, 0, sizeof player_name_changes);
+		}
 	}
 }
 
@@ -3507,7 +3518,7 @@ INT32 G_GetGametypeByName(const char *gametypestr)
 //
 boolean G_IsSpecialStage(INT32 mapnum)
 {
-	if (gametype != GT_COOP || modeattacking == ATTACKING_RECORD)
+	if (modeattacking == ATTACKING_RECORD)
 		return false;
 	if (mapnum >= sstage_start && mapnum <= sstage_end)
 		return true;
@@ -3808,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)
 		{
@@ -3860,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)))
@@ -3881,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 1cf6990c92dd1b3b3c938aa64e84e66bc15cb619..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
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index bf99c584ed55733eae87b5afa37968a886bd0bcc..8c85c5112b09aa38ebd619b13c7c7b07a147e92f 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -109,12 +109,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
@@ -512,11 +506,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 = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0);
-		}
+			realpatch = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 #ifdef WALLFLATS
@@ -558,12 +548,7 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm
 	// lump is a png so convert it
 	size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum);
 	if ((patch != NULL) && Picture_IsLumpPNG((const UINT8 *)patch, len))
-	{
-		// Dummy variables.
-		INT32 pngwidth, pngheight;
-		INT16 topoffset, leftoffset;
-		patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, len, NULL, 0);
-	}
+		patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, NULL, 0);
 #endif
 
 	// don't do it twice (like a cache)
@@ -885,7 +870,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_main.c b/src/hardware/hw_main.c
index cbfcfff870e3ed4b181f989218d55e852bb8c0e2..991b51aee23accaccb9fe7fb68b23ea1c05ba6e6 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -1958,7 +1958,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)
 {
@@ -5997,34 +5997,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_md2.c b/src/hardware/hw_md2.c
index fa5156758e50a7b2bd1c1e4cef68ab0812f8b9bd..5f513089618c63fb4198afaf1d7ba3d1b214c7e5 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1177,6 +1177,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, GLPatch_t *gpatch)
 {
 	int i;
@@ -1185,24 +1186,35 @@ static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch)
 		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;
 }
 
 //
@@ -1226,6 +1238,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
@@ -1330,10 +1346,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 || !gpatch->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
@@ -1344,10 +1363,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
@@ -1391,6 +1406,14 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		{
 			// Sprite
 			gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
+			// 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(&(gpatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 ||
+				memcmp(&(gpatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0)
+				adjustTextureCoords(md2->model, gpatch);
 			HWR_GetMappedPatch(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 83087bbbb8d758727d74142c520d6cc57fe8693d..6286da3a3c50944b569d85417e386bcc45ab5b93 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -2535,6 +2535,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
@@ -2678,6 +2680,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++)
@@ -2694,13 +2705,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
 			{
@@ -2736,21 +2757,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
index 1e8d35648c1a0d7b0b258073ec1d6f2314700b36..7c7d04495cd8f5641bd7c6f236c47bd0eb344c64 100644
--- a/src/http-mserv.c
+++ b/src/http-mserv.c
@@ -36,20 +36,23 @@ Documentation available here.
 
 static void MasterServer_Debug_OnChange (void);
 
-consvar_t cv_masterserver_timeout = {
-	"masterserver_timeout", "5", CV_SAVE, CV_Unsigned,
-	NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
-};
-
-consvar_t cv_masterserver_debug = {
+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, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
-};
+	MasterServer_Debug_OnChange
+);
 
-consvar_t cv_masterserver_token = {
-	"masterserver_token", "", CV_SAVE, NULL,
-	NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
-};
+consvar_t cv_masterserver_token = CVAR_INIT
+(
+		"masterserver_token", "", CV_SAVE, NULL,
+		NULL
+);
 
 #ifdef MASTERSERVER
 
@@ -472,6 +475,7 @@ HMS_list_servers (void)
 {
 	struct HMS_buffer *hms;
 
+	char *list;
 	char *p;
 
 	hms = HMS_connect("servers");
@@ -481,11 +485,17 @@ HMS_list_servers (void)
 
 	if (HMS_do(hms))
 	{
-		p = &hms->buffer[strlen(hms->buffer)];
-		while (*--p == '\n')
-			;
+		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");
+		}
 
-		CONS_Printf("%s\n", hms->buffer);
+		curl_free(list);
 	}
 
 	HMS_end(hms);
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 1a184ea575c6a0045846bb3392f3f8a3bca8bd93..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)
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..e753c5af3ef833ee694a8060e5a45ff64f2e06b1 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;
 }
 
@@ -1715,6 +1730,18 @@ static int lib_pFloorzAtPos(lua_State *L)
 	return 1;
 }
 
+static int lib_pCeilingzAtPos(lua_State *L)
+{
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
+	fixed_t z = luaL_checkfixed(L, 3);
+	fixed_t height = luaL_checkfixed(L, 4);
+	//HUDSAFE
+	INLEVEL
+	lua_pushfixed(L, P_CeilingzAtPos(x, y, z, height));
+	return 1;
+}
+
 static int lib_pDoSpring(lua_State *L)
 {
 	mobj_t *spring = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@@ -2586,30 +2613,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 +2671,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 +2685,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 +2941,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 +2963,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;
 }
@@ -3560,6 +3616,7 @@ static luaL_Reg lib[] = {
 	{"P_CheckHoopPosition",lib_pCheckHoopPosition},
 	{"P_RadiusAttack",lib_pRadiusAttack},
 	{"P_FloorzAtPos",lib_pFloorzAtPos},
+	{"P_CeilingzAtPos",lib_pCeilingzAtPos},
 	{"P_DoSpring",lib_pDoSpring},
 
 	// p_inter
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 4aa70574b3802b62b22cbc4772fb11aa216cdd61..6b87dc93034060d5af15ff1d7a5687cb3fcb8b12 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -992,6 +992,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);
@@ -1142,6 +1155,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 8143bda89a3928812d7be8611d1a512d56ddffda..5e5a1dbc4029ba27f338c525340570e2b9141c7a 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -25,6 +25,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[];
@@ -165,6 +166,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
@@ -371,6 +374,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);
 	{
@@ -455,6 +460,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);
 
@@ -533,6 +540,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);
 
@@ -587,6 +596,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);
 
@@ -686,6 +697,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));
@@ -906,6 +919,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);
@@ -1006,6 +1021,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));
@@ -1173,6 +1190,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);
@@ -1295,6 +1314,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)) {
@@ -1376,6 +1397,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);
 
@@ -1443,6 +1466,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.
 
@@ -1523,6 +1548,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));
@@ -1542,8 +1569,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
 			{
@@ -1633,8 +1662,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
 		{
@@ -1707,6 +1738,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 7c2bb359e081645e6ded76ec1a0f2b4b140f60e2..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
diff --git a/src/m_cheat.c b/src/m_cheat.c
index ab1454503be6ccf116f06bdb95288a7e8b504410..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;
 }
 
@@ -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;
+		player->mo->z += player->mo->scale*cv_speed.value;
 	else if (cmd->buttons & BT_SPIN)
-		player->mo->z -= FRACUNIT*cv_speed.value;
+		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 49e8211d0a66738de9d7be2296d4d9815ebb29f9..6e0d520aea0c998c0b07f0ce29b598c6d757bc08 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -406,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"},
@@ -447,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
@@ -476,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.
@@ -1347,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
@@ -2458,46 +2450,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 =
@@ -8483,7 +8435,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);
 
@@ -11279,7 +11231,7 @@ 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;
 	}
 
diff --git a/src/m_misc.c b/src/m_misc.c
index 42890cb08a26e34e54eb2f904615ff214c5c018c..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_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_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 = 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
 
diff --git a/src/mserv.c b/src/mserv.c
index 27d479797de6d5222360ed6db79ef5a7ab4b7069..fa646b8996776ff17474a9c2f8e6a986626453fd 100644
--- a/src/mserv.c
+++ b/src/mserv.c
@@ -61,10 +61,10 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
 	{0,NULL}
 };
 
-consvar_t cv_masterserver = {"masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
-consvar_t cv_servername = {"servername", "SRB2 server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
+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);
 
-consvar_t cv_masterserver_update_rate = {"masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
+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);
 
 INT16 ms_RoomId = -1;
 
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..8a508496208b82699b4bdde458f7639f7823805e 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);
@@ -426,6 +428,7 @@ void P_Initsecnode(void);
 void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype, boolean sightcheck);
 
 fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height);
+fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height);
 boolean PIT_PushableMoved(mobj_t *thing);
 
 boolean P_DoSpring(mobj_t *spring, mobj_t *object);
diff --git a/src/p_map.c b/src/p_map.c
index 74c2790f754b961442f8614fa0832f53aa55da84..cb06f7d775d22d2ed5dce42cc3371154fb41e38b 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -4963,7 +4963,7 @@ void P_MapEnd(void)
 }
 
 // P_FloorzAtPos
-// Returns the floorz of the XYZ position // TODO: Need ceilingpos function too
+// Returns the floorz of the XYZ position
 // Tails 05-26-2003
 fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
 {
@@ -5007,3 +5007,47 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
 
 	return floorz;
 }
+
+// P_CeilingZAtPos
+// Returns the ceilingz of the XYZ position
+fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
+{
+	sector_t *sec = R_PointInSubsector(x, y)->sector;
+	fixed_t ceilingz = P_GetSectorCeilingZAt(sec, x, y);
+
+	if (sec->ffloors)
+	{
+		ffloor_t *rover;
+		fixed_t delta1, delta2, thingtop = z + height;
+
+		for (rover = sec->ffloors; rover; rover = rover->next)
+		{
+			fixed_t topheight, bottomheight;
+			if (!(rover->flags & FF_EXISTS))
+				continue;
+
+			if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE)))
+				continue;
+
+			topheight    = P_GetFFloorTopZAt   (rover, x, y);
+			bottomheight = P_GetFFloorBottomZAt(rover, x, y);
+
+			if (rover->flags & FF_QUICKSAND)
+			{
+				if (thingtop > bottomheight && topheight > z)
+				{
+					if (ceilingz > z)
+						ceilingz = z;
+				}
+				continue;
+			}
+
+			delta1 = z - (bottomheight + ((topheight - bottomheight)/2));
+			delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
+			if (bottomheight < ceilingz && abs(delta1) > abs(delta2))
+				ceilingz = bottomheight;
+		}
+	}
+
+	return ceilingz;
+}
\ No newline at end of file
diff --git a/src/p_mobj.c b/src/p_mobj.c
index fcba1f690d58e115de9b1c5c5305c6d2a3afc2c7..ffa24705363d8fd7f74c62d385b49a158c27600c 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++)
@@ -11956,9 +11956,6 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
 			return MT_SCORE1K_BOX; // 1,000
 	}
 
-	if (mariomode && i == MT_ROSY)
-		return MT_TOAD; // don't remove on penalty of death
-
 	return i;
 }
 
diff --git a/src/p_setup.c b/src/p_setup.c
index 996e9ec30d7e42eb04d9b0261f14d78f11fcdd46..55840a0f29d61618d6fa91f2f99a7dbc29c781a2 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -4187,9 +4187,9 @@ boolean P_LoadLevel(boolean fromnetsave)
 	nextmapoverride = 0;
 	skipstats = 0;
 
-	if (!(netgame || multiplayer) && (!modifiedgame || savemoddata))
+	if (!(netgame || multiplayer || demoplayback) && (!modifiedgame || savemoddata))
 		mapvisited[gamemap-1] |= MV_VISITED;
-	else
+	else if (netgame || multiplayer)
 		mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently
 
 	levelloading = false;
diff --git a/src/p_spec.c b/src/p_spec.c
index 2b2a5884af304907d379008b96cb6a2e67e7eedf..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
diff --git a/src/p_user.c b/src/p_user.c
index 4d0252c63cc8d1574e10c527d27be679bd68562a..dda682b6d17f1786f54d2a7e74544a426f66a74d 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -5015,7 +5015,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
 	mobj_t *lockonshield = NULL;
 
 	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->secondjump == UINT8_MAX)))) // thokked is optional if you're bubblewrapped
+		&& ((!(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)
 		{
@@ -5498,6 +5498,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);
@@ -9645,45 +9647,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),
 
 	}
 };
diff --git a/src/r_main.c b/src/r_main.c
index eb566601330177458a5048ab0cd398caf45de5f2..9613e2ac16e6cb6e0c74e828622fc5884dcd3462 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 ddd19fac65228f692e3339687ed0975f43f2772d..89b359c5514805c012104524ab7390a98b2cc7ce 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 d48bbaaf2f1ff6eba4c0f172cb3fcf3ce0e68e3d..95fe23aeb11e6e355ed84644e3b9aa1b421b2f7c 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -798,6 +798,8 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext)
 	CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
 }
 
+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,
@@ -824,8 +826,6 @@ static png_bytep *PNG_Read(
 
 	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);
@@ -852,7 +852,6 @@ static png_bytep *PNG_Read(
 	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;
@@ -896,7 +895,7 @@ static png_bytep *PNG_Read(
 		// 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_num == 256)
+		if (trans && trans_num == 256)
 		{
 			int i;
 			for (i = 0; i < trans_num; i++)
@@ -950,7 +949,6 @@ static png_bytep *PNG_Read(
 			*topoffset = (INT16)BIGENDIAN_LONG(*offsets);
 	}
 
-	// bye
 	png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
 	if (chunk.data)
 		Z_Free(chunk.data);
@@ -987,12 +985,28 @@ void *Picture_PNGConvert(
 	png_uint_32 x, y;
 	png_bytep row;
 	boolean palette = false;
-	png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, &palette, insize);
-	png_uint_32 width = *w, height = *h;
+	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!");
 
@@ -1158,7 +1172,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)
@@ -1174,14 +1187,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;
 	}
@@ -1195,10 +1202,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;
@@ -1211,9 +1220,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!");
 
@@ -1237,23 +1246,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;
@@ -1634,11 +1661,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 		lumplength = W_LumpLength(lump);
 
 		if (Picture_IsLumpPNG((const UINT8 *)patch, lumplength))
-		{
-			INT32 pngwidth, pngheight;
-			INT16 toffs, loffs;
-			patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &toffs, &loffs, lumplength, NULL, 0);
-		}
+			patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 		// Because there's something wrong with SPR_DFLM, I guess
diff --git a/src/r_picformats.h b/src/r_picformats.h
index 32754d64ea9048fa759f6fed309ba2d511b2e798..3ee76a92f1bf2c521ef92372429543e7de10cba8 100644
--- a/src/r_picformats.h
+++ b/src/r_picformats.h
@@ -110,7 +110,7 @@ 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
diff --git a/src/r_skins.c b/src/r_skins.c
index a4fe1982f72f1cf0a31fc4181719987c89c4f0f0..25904e95e3ff2c1c89e5fcd5c60c564efedaf84b 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -286,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 ef45863a2ff94239abe1226a0cea758fda2a5559..a34c29c728c79395d56ad93864b32c575032d5aa 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -397,11 +397,7 @@ UINT8 *R_GenerateTexture(size_t texnum)
 
 #ifndef NO_PNG_LUMPS
 		if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
-			// Dummy variables.
-			INT32 pngwidth, pngheight;
-			realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0);
-		}
+			realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
 		else
 #endif
 #ifdef WALLFLATS
@@ -800,10 +796,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
@@ -898,10 +894,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 a3ce90991af9c627fbd26ac9276e578f19a2ca47..382eed5608b372d7a2d3c83191d20fa9f0626f66 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -259,6 +259,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]);
 
@@ -274,28 +280,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
 			{
 				patch_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_PATCH, &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 0442c6219ee5996f9b200b81791cd643de849c18..793794aa7c70bcabbcd02e7fade906e108e39bb1 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -65,21 +65,21 @@ static boolean S_CheckQueue(void);
 #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)
 {
@@ -88,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[] = {
@@ -116,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
@@ -521,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;
@@ -718,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);
 }
 
@@ -929,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;
 
@@ -1043,7 +1045,6 @@ void S_ClearSfx(void)
 
 static void S_StopChannel(INT32 cnum)
 {
-	INT32 i;
 	channel_t *c = &channels[cnum];
 
 	if (c->sfxinfo)
@@ -1052,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;
 }
 
 //
@@ -1204,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);
diff --git a/src/s_sound.h b/src/s_sound.h
index 6e3de6101189b036f33184a11bff8813ff174120..4ac3c70bf0d4a76f759e166ee0db3c682894ee5f 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -87,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 e7ff9e73555a35f146b78974f40d25eb4736299b..048480fb27d8d6a54024cac0ff5664f72862e711 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -58,24 +58,24 @@ 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);
 
 static void SCR_ActuallyChangeRenderer(void);
-CV_PossibleValue_t cv_renderer_t[] = {
+static CV_PossibleValue_t cv_renderer_t[] = {
 	{1, "Software"},
 #ifdef HWRENDER
 	{2, "OpenGL"},
 #endif
 	{0, NULL}
 };
-consvar_t cv_renderer = {"renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_ChangeRenderer, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_renderer = CVAR_INIT ("renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_ChangeRenderer);
 
 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
@@ -499,9 +499,6 @@ void SCR_ChangeRendererCVars(INT32 mode)
 		CV_StealthSetValue(&cv_renderer, 1);
 	else if (mode == render_opengl)
 		CV_StealthSetValue(&cv_renderer, 2);
-#ifdef HWRENDER
-	CV_StealthSetValue(&cv_newrenderer, cv_renderer.value);
-#endif
 }
 
 boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
diff --git a/src/screen.h b/src/screen.h
index 91ec175f426cb53d723a2a0539c8611ed0cfaa17..2cb2cf839160ab6e73e1544d6f7f6869ac4bdbb9 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -168,7 +168,6 @@ extern boolean R_SSE2;
 // ----------------
 // screen variables
 // ----------------
-
 extern viddef_t vid;
 extern INT32 setmodeneeded; // mode number to set if needed, or 0
 
@@ -179,12 +178,7 @@ extern UINT8 setrenderneeded;
 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/i_system.c b/src/sdl/i_system.c
index c2be5153958fa2ae682ce1018c4269f8bde2adcd..10c0747bf18b4e8fc725f4cfd3984a9183e79c56 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -560,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))
 		{
@@ -586,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);
 }
 
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 5c5b6119c60824541156a28188d6cdb96d82ff16..749dab4fa7a863e71f5641734a5f4362edbd799b 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -100,9 +100,9 @@ static rendermode_t chosenrendermode = render_soft; // set by command line argum
 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
 INT32 vid_opengl_state = 0;
@@ -1489,7 +1489,6 @@ void VID_CheckGLLoaded(rendermode_t oldrender)
 		if (setrenderneeded)
 		{
 			CV_StealthSetValue(&cv_renderer, oldrender);
-			CV_StealthSetValue(&cv_newrenderer, oldrender);
 			setrenderneeded = 0;
 		}
 	}
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 25e7fde8981c01755b7a77972b1114db09730ef4..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)
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/v_video.c b/src/v_video.c
index 74659d45ca7208df66f2d98b06888b4b1cb03fcb..9c91261de6eb3247945e33eec33384145e99ea6a 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -43,45 +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_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;
@@ -2118,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:
@@ -2231,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)
@@ -2346,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)
@@ -2481,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)
@@ -2594,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)
@@ -2708,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)
@@ -2822,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)
@@ -2915,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))
@@ -2940,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)
@@ -2993,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++;
@@ -3050,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)
@@ -3265,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)
@@ -3400,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;
 }
diff --git a/src/version.h b/src/version.h
index 2ef7116bb66d2f600917e47e56ef011926aea55a..ece084beb2ddaed925f436d78fcfd290d94c57c5 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
-#define SRB2VERSION "2.2.7"/* 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,7 +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 48
+#define MODVERSION 49
 
 // Define this as a prerelease version suffix
-#define BETAVERSION "RC1"
+// #define BETAVERSION "RC1"
diff --git a/src/w_wad.c b/src/w_wad.c
index 29c5764f99e16e17644bb511cdf184ff34b14f2b..11679b8f4f797564a815efb841f00b5c91115ea3 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -777,6 +777,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);
@@ -885,16 +887,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);
 	}
 }
 
@@ -1686,10 +1685,8 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 		// lump is a png so convert it
 		if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
 		{
-			// Dummy variables.
 			size_t newlen;
-			INT32 pngwidth, pngheight;
-			srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, len, &newlen, 0);
+			srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, &newlen, 0);
 			ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]);
 			M_Memcpy(ptr, srcdata, newlen);
 			Z_Free(srcdata);
diff --git a/src/w_wad.h b/src/w_wad.h
index fddc65529de1dbc8a31f3c730eda7fbb556889f1..41232cba1c5f5e006c33ed8496462c98a1ccf2f4 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -150,7 +150,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/Srb2win.rc b/src/win32/Srb2win.rc
index 293dd29bdfc6441d131bd21605d386cbffe5b063..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,7,0
- PRODUCTVERSION 2,2,7,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_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 716f380890f965d420d2121a3e84bfbe6ff9e665..931e006eb35416dc251e5fbf7bd2ade432154f5c 100644
--- a/src/win32/win_vid.c
+++ b/src/win32/win_vid.c
@@ -51,9 +51,9 @@ rendermode_t rendermode = render_soft;
 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;
 int vid_opengl_state = 0;