diff --git a/dep/.gitignore b/dep/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..fb941664fc5718a31185a0cf67ccd2cfd68a2be8
--- /dev/null
+++ b/dep/.gitignore
@@ -0,0 +1,2 @@
+#All folders
+*.d
diff --git a/dep/FreeBSD/SDL/Debug/.gitignore b/dep/FreeBSD/SDL/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/FreeBSD/SDL/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/FreeBSD/SDL/Release/.gitignore b/dep/FreeBSD/SDL/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/FreeBSD/SDL/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Linux/SDL/Debug/.gitignore b/dep/Linux/SDL/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Linux/SDL/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Linux/SDL/Release/.gitignore b/dep/Linux/SDL/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Linux/SDL/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Linux64/SDL/Debug/.gitignore b/dep/Linux64/SDL/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Linux64/SDL/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Linux64/SDL/Release/.gitignore b/dep/Linux64/SDL/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Linux64/SDL/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/MasterClient/.gitignore b/dep/MasterClient/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/MasterClient/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/MasterServer/.gitignore b/dep/MasterServer/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/MasterServer/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw/Debug/.gitignore b/dep/Mingw/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw/Release/.gitignore b/dep/Mingw/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw/SDL/Debug/.gitignore b/dep/Mingw/SDL/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw/SDL/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw/SDL/Release/.gitignore b/dep/Mingw/SDL/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw/SDL/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw64/Debug/.gitignore b/dep/Mingw64/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw64/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw64/Release/.gitignore b/dep/Mingw64/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw64/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw64/SDL/Debug/.gitignore b/dep/Mingw64/SDL/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw64/SDL/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/Mingw64/SDL/Release/.gitignore b/dep/Mingw64/SDL/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/Mingw64/SDL/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/SDL/Release/.gitignore b/dep/SDL/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/SDL/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/VC/.gitignore b/dep/VC/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/VC/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/VC9/.gitignore b/dep/VC9/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/VC9/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/cygwin/Debug/.gitignore b/dep/cygwin/Debug/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/cygwin/Debug/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/cygwin/Release/.gitignore b/dep/cygwin/Release/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/cygwin/Release/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/dep/dummy/.gitignore b/dep/dummy/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42c6dc2c662642792a8860e166dfd81126695e8f
--- /dev/null
+++ b/dep/dummy/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index 0ea452155181cfd080a65a0713afd8e966531196..113c1a4c26eb08a7109da2afeba747dfb1cdda14 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -1247,6 +1247,7 @@ patterns
 		sprite = "SPHRA0";
 		width = 96;
 		height = 192;
+	}
 	609
 	{
 		title = "Circle of Rings and Spheres (Big)";
diff --git a/src/Makefile b/src/Makefile
index 1314161bd8b5f573732459c1f1cd080c3a35b7b3..9518942b2b67bfbd2cbdaa4d45a4133438483cfb 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2,7 +2,7 @@
 #     GNU Make makefile for SRB2
 #############################################################################
 # Copyright (C) 1998-2000 by DooM Legacy Team.
-# Copyright (C) 2003-2020 by Sonic Team Junior.
+# Copyright (C) 2003-2021 by Sonic Team Junior.
 #
 # This program is free software distributed under the
 # terms of the GNU General Public License, version 2.
@@ -24,7 +24,9 @@
 #     clean
 #       Remove all object files
 #     cleandep
-#       Remove depend.dep
+#       Remove dependency files
+#     distclean
+#       Remove autogenerated files
 #     dll
 #       compile primary HW render DLL/SO
 #     all_dll
@@ -79,6 +81,17 @@
 #
 #############################################################################
 
+,=,
+
+ifeq (,$(filter-out cleandep clean distclean,$(or $(MAKECMDGOALS),all)))
+CLEANONLY=1
+else ifndef SILENT
+echo=@echo "$(1)"
+ifndef MAKE_RESTARTS
+print=$(info $(1))
+endif
+endif
+
 ALL_SYSTEMS=\
 	PANDORA\
 	LINUX64\
@@ -98,7 +111,7 @@ ALL_SYSTEMS=\
 ifeq (,$(filter $(ALL_SYSTEMS),$(.VARIABLES)))
 ifeq ($(OS),Windows_NT) # all windows are Windows_NT...
 
- $(info Detected a Windows system, compiling for 32-bit MinGW SDL2...)
+ $(call print,Detected a Windows system$(,) compiling for 32-bit MinGW SDL2...)
 
  # go for a 32-bit sdl mingw exe by default
  MINGW=1
@@ -123,7 +136,7 @@ else # if you on the *nix
  new_system:=$(new_system)64
  endif
 
- $(info Detected $(system) ($(new_system))...)
+ $(call print,Detected $(system) ($(new_system))...)
  $(new_system)=1
 
 endif
@@ -237,6 +250,12 @@ endif
 
 MSGFMT?=msgfmt
 
+ifdef WINDOWSHELL
+	COMPTIME=-..\comptime.bat
+else
+	COMPTIME=-../comptime.sh
+endif
+
 ifndef ECHO
 	NASM:=@$(NASM)
 	REMOVE:=@$(REMOVE)
@@ -251,6 +270,7 @@ ifndef ECHO
 	MSGFMT:=@$(MSGFMT)
 	UPX:=@$(UPX)
 	UPX_OPTS+=-q
+	COMPTIME:=@$(COMPTIME)
 endif
 
 ifdef NONET
@@ -415,7 +435,7 @@ ifdef GCC48
 else
 	CFLAGS+=-O0
 endif
-	CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
+	CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP
 else
 
 
@@ -455,7 +475,6 @@ DBGNAME?=$(EXENAME).debug
 
 # not too sophisticated dependency
 OBJS:=$(i_main_o) \
-		$(OBJDIR)/comptime.o \
 		$(OBJDIR)/string.o   \
 		$(OBJDIR)/d_main.o   \
 		$(OBJDIR)/d_clisrv.o \
@@ -542,7 +561,10 @@ OBJS:=$(i_main_o) \
 		$(i_sound_o)    \
 		$(OBJS)
 
+DEPS:=$(patsubst $(OBJDIR)/%.o,$(DEPDIR)/%.d,$(filter %.o,$(OBJS)))
+OBJS+=$(OBJDIR)/comptime.o
 
+ifndef SILENT
 ifndef ECHO
 ifndef NOECHOFILENAMES
 define echoName =
@@ -550,6 +572,7 @@ define echoName =
 endef
 endif
 endif
+endif
 
 # List of languages to compile.
 # For reference, this is the command I use to build a srb2.pot file from the source code.
@@ -562,12 +585,12 @@ OPTS+=-DGETTEXT
 endif
 
 ifdef PANDORA
-all:	pre-build $(BIN)/$(PNDNAME)
+all: $(BIN)/$(PNDNAME)
 endif
 
 
 ifdef SDL
-all:	 pre-build $(BIN)/$(EXENAME)
+all: $(BIN)/$(EXENAME)
 endif
 
 ifdef DUMMY
@@ -575,20 +598,15 @@ all:	$(BIN)/$(EXENAME)
 endif
 
 cleandep:
-	$(REMOVE) $(OBJDIR)/depend.dep
+	$(REMOVE) $(DEPS)
 	$(REMOVE) comptime.h
 
-pre-build:
-ifdef WINDOWSHELL
-	-..\comptime.bat .
-else
-	-@../comptime.sh .
-endif
-
 clean:
 	$(REMOVE) *~ *.flc
 	$(REMOVE) $(OBJDIR)/*.o
 
+distclean: clean cleandep
+
 ifdef MINGW
 	$(REMOVE) $(OBJDIR)/*.res
 endif
@@ -608,11 +626,11 @@ asm:
 
 $(BIN)/$(EXENAME): $(POS) $(OBJS)
 	-$(MKDIR) $(BIN)
-	@echo Linking $(EXENAME)...
+	$(call echo,Linking $(EXENAME)...)
 	$(LD) $(LDFLAGS) $(OBJS) -o $(BIN)/$(EXENAME) $(LIBS)
 ifndef VALGRIND
 ifndef NOOBJDUMP
-	@echo Dumping debugging info
+	$(call echo,Dumping debugging info)
 	$(OBJDUMP) $(OBJDUMP_OPTS) $(BIN)/$(EXENAME) > $(BIN)/$(DBGNAME).txt
 ifdef WINDOWSHELL
 	-$(GZIP) $(GZIP_OPTS) $(BIN)/$(DBGNAME).txt
@@ -631,10 +649,10 @@ ifndef NOUPX
 	-$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME)
 endif
 endif
-	@echo Build is done, please look for $(EXENAME) in $(BIN), \(checking for post steps\)
+	$(call echo,Build is done$(,) please look for $(EXENAME) in $(BIN)$(,) (checking for post steps))
 
 reobjdump:
-	@echo Redumping debugging info
+	$(call echo,Redumping debugging info)
 	$(OBJDUMP) $(OBJDUMP_OPTS) $(BIN)/$(DBGNAME) > $(BIN)/$(DBGNAME).txt
 ifdef WINDOWSHELL
 	-$(GZIP) $(GZIP_OPTS) $(BIN)/$(DBGNAME).txt
@@ -670,24 +688,40 @@ endif
 endif
 
 #dependecy made by gcc itself !
-$(OBJS):
 ifndef DUMMY
--include $(OBJDIR)/depend.dep
+ifndef CLEANONLY
+$(call print,Checking dependency files...)
+-include $(DEPS)
+endif
 endif
 
-$(OBJDIR)/depend.dep:
-	@echo "Creating dependency file, depend.dep"
-	@echo > comptime.h
-	-$(MKDIR) $(OBJDIR)
-	$(CC) $(CFLAGS) -MM *.c > $(OBJDIR)/depend.ped
-	$(CC) $(CFLAGS) -MM $(INTERFACE)/*.c >> $(OBJDIR)/depend.ped
-ifndef NOHW
-	$(CC) $(CFLAGS) -MM hardware/*.c >> $(OBJDIR)/depend.ped
+undefine deps_rule
+
+# windows makes it too hard !
+ifndef WINDOWSHELL
+ifdef echoName
+define deps_rule =
+	@printf "%-20.20s\r" $<
+
+endef
 endif
-	$(CC) $(CFLAGS) -MM blua/*.c >> $(OBJDIR)/depend.ped
-	@sed -e 's,\(.*\)\.o: ,$(subst /,\/,$(OBJDIR))\/&,g' < $(OBJDIR)/depend.ped > $(OBJDIR)/depend.dep
-	$(REMOVE) $(OBJDIR)/depend.ped
-	@echo "Created dependency file, depend.dep"
+endif
+
+define deps_rule +=
+	$(CC) $(CFLAGS) -M -MF $@ -MT $(OBJDIR)/$< $<
+endef
+
+$(DEPDIR)/%.d: %.c
+	$(deps_rule)
+
+$(DEPDIR)/%.d: $(INTERFACE)/%.c
+	$(deps_rule)
+
+$(DEPDIR)/%.d: hardware/%.c
+	$(deps_rule)
+
+$(DEPDIR)/%.d: blua/%.c
+	$(deps_rule)
 
 ifdef VALGRIND
 $(OBJDIR)/z_zone.o: z_zone.c
@@ -695,9 +729,12 @@ $(OBJDIR)/z_zone.o: z_zone.c
 	$(CC) $(CFLAGS) $(WFLAGS) -DHAVE_VALGRIND $(VALGRIND_CFLAGS) -c $< -o $@
 endif
 
-$(OBJDIR)/comptime.o: comptime.c pre-build
-	$(echoName)
-	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
+$(OBJDIR)/comptime.o::
+ifdef echoName
+	@echo -- comptime.c ...
+endif
+	$(COMPTIME) .
+	$(CC) $(CFLAGS) $(WFLAGS) -c comptime.c -o $@
 
 $(BIN)/%.mo: locale/%.po
 	-$(MKDIR) $(BIN)
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index f081eacdfaaf795bec1d2635a71afdd920630f00..075cd2d3a8defa3fd7d11feb431d2ad9cc67a704 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -47,7 +47,8 @@ ifdef MACOSX
 endif
 
 # Automatically set version flag, but not if one was manually set
-ifeq   (,$(filter GCC%,$(.VARIABLES)))
+# And don't bother if this is a clean only run
+ifeq   (,$(filter GCC% CLEANONLY,$(.VARIABLES)))
  version:=$(shell $(CC) --version)
  # check if this is in fact GCC
  ifneq (,$(or $(findstring gcc,$(version)),$(findstring GCC,$(version))))
@@ -60,12 +61,14 @@ ifeq   (,$(filter GCC%,$(.VARIABLES)))
 
   # If this version is not in the list, default to the latest supported
   ifeq (,$(filter $(v),$(SUPPORTED_GCC_VERSIONS)))
-   $(info\
-		Your compiler version, GCC $(version), is not supported by the Makefile.\
-		The Makefile will assume GCC $(LATEST_GCC_VERSION).)
+	define line =
+	Your compiler version, GCC $(version), is not supported by the Makefile.
+	The Makefile will assume GCC $(LATEST_GCC_VERSION).))
+	endef
+   $(call print,$(line))
    GCC$(subst .,,$(LATEST_GCC_VERSION))=1
   else
-   $(info Detected GCC $(version) (GCC$(v)))
+   $(call print,Detected GCC $(version) (GCC$(v)))
    GCC$(v)=1
   endif
  endif
@@ -361,6 +364,7 @@ i_main_o=$(OBJDIR)/i_main.o
 #set OBJDIR and BIN's starting place
 OBJDIR=../objs
 BIN=../bin
+DEPDIR=../dep
 #Nasm ASM and rm
 ifdef YASM
 NASM?=yasm
@@ -383,6 +387,7 @@ ifdef DUMMY
 	INTERFACE=dummy
 	OBJDIR:=$(OBJDIR)/dummy
 	BIN:=$(BIN)/dummy
+	DEPDIR:=$(DEPDIR)/dummy
 else
 ifdef LINUX
 	NASMFORMAT=elf -DLINUX
@@ -390,9 +395,11 @@ ifdef LINUX
 ifdef LINUX64
 	OBJDIR:=$(OBJDIR)/Linux64
 	BIN:=$(BIN)/Linux64
+	DEPDIR:=$(DEPDIR)/Linux64
 else
 	OBJDIR:=$(OBJDIR)/Linux
 	BIN:=$(BIN)/Linux
+	DEPDIR:=$(DEPDIR)/Linux
 endif
 else
 ifdef FREEBSD
@@ -402,6 +409,7 @@ ifdef FREEBSD
 
 	OBJDIR:=$(OBJDIR)/FreeBSD
 	BIN:=$(BIN)/FreeBSD
+	DEPDIR:=$(DEPDIR)/Linux
 else
 ifdef SOLARIS
 	INTERFACE=sdl
@@ -410,6 +418,7 @@ ifdef SOLARIS
 
 	OBJDIR:=$(OBJDIR)/Solaris
 	BIN:=$(BIN)/Solaris
+	DEPDIR:=$(DEPDIR)/Solaris
 else
 ifdef CYGWIN32
 	INTERFACE=sdl
@@ -418,18 +427,21 @@ ifdef CYGWIN32
 
 	OBJDIR:=$(OBJDIR)/cygwin
 	BIN:=$(BIN)/Cygwin
+	DEPDIR:=$(DEPDIR)/Cygwin
 else
 ifdef MINGW64
 	#NASMFORMAT=win64
 	SDL=1
 	OBJDIR:=$(OBJDIR)/Mingw64
 	BIN:=$(BIN)/Mingw64
+	DEPDIR:=$(DEPDIR)/Mingw64
 else
 ifdef MINGW
 	NASMFORMAT=win32
 	SDL=1
 	OBJDIR:=$(OBJDIR)/Mingw
 	BIN:=$(BIN)/Mingw
+	DEPDIR:=$(DEPDIR)/Mingw
 endif
 endif
 endif
@@ -441,6 +453,7 @@ endif
 ifdef ARCHNAME
 	OBJDIR:=$(OBJDIR)/$(ARCHNAME)
 	BIN:=$(BIN)/$(ARCHNAME)
+	DEPDIR:=$(DEPDIR)/$(ARCHNAME)
 endif
 
 OBJDUMP_OPTS?=--wide --source --line-numbers
@@ -449,14 +462,17 @@ LD=$(CC)
 ifdef SDL
 	INTERFACE=sdl
 	OBJDIR:=$(OBJDIR)/SDL
+	DEPDIR:=$(DEPDIR)/SDL
 endif
 
 ifndef DUMMY
 ifdef DEBUGMODE
 	OBJDIR:=$(OBJDIR)/Debug
 	BIN:=$(BIN)/Debug
+	DEPDIR:=$(DEPDIR)/Debug
 else
 	OBJDIR:=$(OBJDIR)/Release
 	BIN:=$(BIN)/Release
+	DEPDIR:=$(DEPDIR)/Release
 endif
 endif
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 4fdc7e7eea49df2cf128023784bbd4c5b44f742d..7c2dec6a119739b729e33fd5025fe42263fd0272 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -3112,7 +3112,7 @@ consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxpl
 static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}};
 consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL);
 static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}};
-consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "Off", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL);
+consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|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 = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL);
@@ -4480,70 +4480,73 @@ static INT16 Consistancy(void)
 		ret += P_GetRandSeed();
 
 #ifdef MOBJCONSISTANCY
-	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
+	if (gamestate == GS_LEVEL)
 	{
-		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
-			continue;
-
-		mo = (mobj_t *)th;
-
-		if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY))
+		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
-			ret -= mo->type;
-			ret += mo->x;
-			ret -= mo->y;
-			ret += mo->z;
-			ret -= mo->momx;
-			ret += mo->momy;
-			ret -= mo->momz;
-			ret += mo->angle;
-			ret -= mo->flags;
-			ret += mo->flags2;
-			ret -= mo->eflags;
-			if (mo->target)
-			{
-				ret += mo->target->type;
-				ret -= mo->target->x;
-				ret += mo->target->y;
-				ret -= mo->target->z;
-				ret += mo->target->momx;
-				ret -= mo->target->momy;
-				ret += mo->target->momz;
-				ret -= mo->target->angle;
-				ret += mo->target->flags;
-				ret -= mo->target->flags2;
-				ret += mo->target->eflags;
-				ret -= mo->target->state - states;
-				ret += mo->target->tics;
-				ret -= mo->target->sprite;
-				ret += mo->target->frame;
-			}
-			else
-				ret ^= 0x3333;
-			if (mo->tracer && mo->tracer->type != MT_OVERLAY)
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+	
+			mo = (mobj_t *)th;
+	
+			if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY))
 			{
-				ret += mo->tracer->type;
-				ret -= mo->tracer->x;
-				ret += mo->tracer->y;
-				ret -= mo->tracer->z;
-				ret += mo->tracer->momx;
-				ret -= mo->tracer->momy;
-				ret += mo->tracer->momz;
-				ret -= mo->tracer->angle;
-				ret += mo->tracer->flags;
-				ret -= mo->tracer->flags2;
-				ret += mo->tracer->eflags;
-				ret -= mo->tracer->state - states;
-				ret += mo->tracer->tics;
-				ret -= mo->tracer->sprite;
-				ret += mo->tracer->frame;
+				ret -= mo->type;
+				ret += mo->x;
+				ret -= mo->y;
+				ret += mo->z;
+				ret -= mo->momx;
+				ret += mo->momy;
+				ret -= mo->momz;
+				ret += mo->angle;
+				ret -= mo->flags;
+				ret += mo->flags2;
+				ret -= mo->eflags;
+				if (mo->target)
+				{
+					ret += mo->target->type;
+					ret -= mo->target->x;
+					ret += mo->target->y;
+					ret -= mo->target->z;
+					ret += mo->target->momx;
+					ret -= mo->target->momy;
+					ret += mo->target->momz;
+					ret -= mo->target->angle;
+					ret += mo->target->flags;
+					ret -= mo->target->flags2;
+					ret += mo->target->eflags;
+					ret -= mo->target->state - states;
+					ret += mo->target->tics;
+					ret -= mo->target->sprite;
+					ret += mo->target->frame;
+				}
+				else
+					ret ^= 0x3333;
+				if (mo->tracer && mo->tracer->type != MT_OVERLAY)
+				{
+					ret += mo->tracer->type;
+					ret -= mo->tracer->x;
+					ret += mo->tracer->y;
+					ret -= mo->tracer->z;
+					ret += mo->tracer->momx;
+					ret -= mo->tracer->momy;
+					ret += mo->tracer->momz;
+					ret -= mo->tracer->angle;
+					ret += mo->tracer->flags;
+					ret -= mo->tracer->flags2;
+					ret += mo->tracer->eflags;
+					ret -= mo->tracer->state - states;
+					ret += mo->tracer->tics;
+					ret -= mo->tracer->sprite;
+					ret += mo->tracer->frame;
+				}
+				else
+					ret ^= 0xAAAA;
+				ret -= mo->state - states;
+				ret += mo->tics;
+				ret -= mo->sprite;
+				ret += mo->frame;
 			}
-			else
-				ret ^= 0xAAAA;
-			ret -= mo->state - states;
-			ret += mo->tics;
-			ret -= mo->sprite;
-			ret += mo->frame;
 		}
 	}
 #endif
diff --git a/src/d_main.c b/src/d_main.c
index a89f4ed2dc93af3efc4fd3acd59647b1dd208668..23a2c0133ce6f77316704b455a32b4d2a3c547b3 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -61,7 +61,7 @@
 #include "p_local.h" // chasecam
 #include "mserv.h" // ms_RoomId
 #include "m_misc.h" // screenshot functionality
-#include "dehacked.h" // Dehacked list test
+#include "deh_tables.h" // Dehacked list test
 #include "m_cond.h" // condition initialization
 #include "fastcmp.h"
 #include "keys.h"
@@ -1072,7 +1072,7 @@ void D_SRB2Main(void)
 	G_LoadGameSettings();
 
 	// Test Dehacked lists
-	DEH_Check();
+	DEH_TableCheck();
 
 	// Netgame URL special case: change working dir to EXE folder.
 	ChangeDirForUrlHandler();
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 0acbec928ad524f5d47708390c8972fba0384b86..09f9d46514b12bc7e987fecbd3cf2f81e95fc88b 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -2130,7 +2130,7 @@ static void Command_Pause(void)
 
 	if (cv_pause.value || server || (IsPlayerAdmin(consoleplayer)))
 	{
-		if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
+		if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) || (marathonmode && gamestate == GS_INTERMISSION))
 		{
 			CONS_Printf(M_GetText("You can't pause here.\n"));
 			return;
diff --git a/src/deh_tables.c b/src/deh_tables.c
index 3039bf7dec22dfecc241bd253ef5175d83aee026..dd6d7d69ff722bedd843456a4b5a7963889a1269 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -5457,3 +5457,27 @@ struct int_const_s const INT_CONST[] = {
 
 	{NULL,0}
 };
+
+// For this to work compile-time without being in this file,
+// this function would need to check sizes at runtime, without sizeof
+void DEH_TableCheck(void)
+{
+#if defined(_DEBUG) || defined(PARANOIA)
+	const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*);
+	const size_t dehmobjs  = sizeof(MOBJTYPE_LIST)/sizeof(const char*);
+	const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*);
+	const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*);
+
+	if (dehstates != S_FIRSTFREESLOT)
+		I_Error("You forgot to update the Dehacked states list, you dolt!\n(%d states defined, versus %s in the Dehacked list)\n", S_FIRSTFREESLOT, sizeu1(dehstates));
+
+	if (dehmobjs != MT_FIRSTFREESLOT)
+		I_Error("You forgot to update the Dehacked mobjtype list, you dolt!\n(%d mobj types defined, versus %s in the Dehacked list)\n", MT_FIRSTFREESLOT, sizeu1(dehmobjs));
+
+	if (dehpowers != NUMPOWERS)
+		I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers));
+
+	if (dehcolors != SKINCOLOR_FIRSTFREESLOT)
+		I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors));
+#endif
+}
diff --git a/src/deh_tables.h b/src/deh_tables.h
index 2c6b3e20407ec454a47a9b301fcf5003cb4220a8..d094bcbad4e74b736aa6aa423cfe94a408dc18f2 100644
--- a/src/deh_tables.h
+++ b/src/deh_tables.h
@@ -72,4 +72,7 @@ extern const char *const MENUTYPES_LIST[];
 
 extern struct int_const_s const INT_CONST[];
 
+// Moved to this file because it can't work compile-time otherwise
+void DEH_TableCheck(void);
+
 #endif
diff --git a/src/dehacked.c b/src/dehacked.c
index b4266326759b822ed91e17211f639c052a9af2bb..c2ea28d27cef95d623c480b0259940e390f7cd2f 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -645,25 +645,3 @@ void DEH_LoadDehackedLump(lumpnum_t lumpnum)
 {
 	DEH_LoadDehackedLumpPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum), false);
 }
-
-void DEH_Check(void)
-{
-#if defined(_DEBUG) || defined(PARANOIA)
-	const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*);
-	const size_t dehmobjs  = sizeof(MOBJTYPE_LIST)/sizeof(const char*);
-	const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*);
-	const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*);
-
-	if (dehstates != S_FIRSTFREESLOT)
-		I_Error("You forgot to update the Dehacked states list, you dolt!\n(%d states defined, versus %s in the Dehacked list)\n", S_FIRSTFREESLOT, sizeu1(dehstates));
-
-	if (dehmobjs != MT_FIRSTFREESLOT)
-		I_Error("You forgot to update the Dehacked mobjtype list, you dolt!\n(%d mobj types defined, versus %s in the Dehacked list)\n", MT_FIRSTFREESLOT, sizeu1(dehmobjs));
-
-	if (dehpowers != NUMPOWERS)
-		I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers));
-
-	if (dehcolors != SKINCOLOR_FIRSTFREESLOT)
-		I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors));
-#endif
-}
diff --git a/src/dehacked.h b/src/dehacked.h
index d5256be23f0b05b9b51e80faf12823e3a43e0366..1620314caaba5bbabafded19233b0c162f148f84 100644
--- a/src/dehacked.h
+++ b/src/dehacked.h
@@ -30,8 +30,6 @@ typedef enum
 void DEH_LoadDehackedLump(lumpnum_t lumpnum);
 void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump, boolean mainfile);
 
-void DEH_Check(void);
-
 fixed_t get_number(const char *word);
 FUNCPRINTF void deh_warning(const char *first, ...);
 void deh_strlcpy(char *dst, const char *src, size_t size, const char *warntext);
diff --git a/src/f_finale.c b/src/f_finale.c
index 2232b669f643a44918c021b91ea1e62f5115c42c..fdcfad2795f94f5c656345caa0921191084c135f 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -2546,28 +2546,28 @@ static void F_UnloadAlacroixGraphics(SINT8 oldttscale)
 	oldttscale--; // zero-based index
 	for (i = 0; i < TTMAX_ALACROIX; i++)
 	{
-		if(ttembl[oldttscale][i]) { Z_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; }
-		if(ttribb[oldttscale][i]) { Z_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; }
-		if(ttsont[oldttscale][i]) { Z_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; }
-		if(ttrobo[oldttscale][i]) { Z_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; }
-		if(tttwot[oldttscale][i]) { Z_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; }
-		if(ttrbtx[oldttscale][i]) { Z_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; }
-		if(ttsoib[oldttscale][i]) { Z_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; }
-		if(ttsoif[oldttscale][i]) { Z_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; }
-		if(ttsoba[oldttscale][i]) { Z_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; }
-		if(ttsobk[oldttscale][i]) { Z_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; }
-		if(ttsodh[oldttscale][i]) { Z_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; }
-		if(tttaib[oldttscale][i]) { Z_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; }
-		if(tttaif[oldttscale][i]) { Z_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; }
-		if(tttaba[oldttscale][i]) { Z_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; }
-		if(tttabk[oldttscale][i]) { Z_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; }
-		if(tttabt[oldttscale][i]) { Z_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; }
-		if(tttaft[oldttscale][i]) { Z_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; }
-		if(ttknib[oldttscale][i]) { Z_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; }
-		if(ttknif[oldttscale][i]) { Z_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; }
-		if(ttknba[oldttscale][i]) { Z_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; }
-		if(ttknbk[oldttscale][i]) { Z_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; }
-		if(ttkndh[oldttscale][i]) { Z_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; }
+		if(ttembl[oldttscale][i]) { Patch_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; }
+		if(ttribb[oldttscale][i]) { Patch_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; }
+		if(ttsont[oldttscale][i]) { Patch_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; }
+		if(ttrobo[oldttscale][i]) { Patch_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; }
+		if(tttwot[oldttscale][i]) { Patch_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; }
+		if(ttrbtx[oldttscale][i]) { Patch_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; }
+		if(ttsoib[oldttscale][i]) { Patch_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; }
+		if(ttsoif[oldttscale][i]) { Patch_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; }
+		if(ttsoba[oldttscale][i]) { Patch_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; }
+		if(ttsobk[oldttscale][i]) { Patch_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; }
+		if(ttsodh[oldttscale][i]) { Patch_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; }
+		if(tttaib[oldttscale][i]) { Patch_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; }
+		if(tttaif[oldttscale][i]) { Patch_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; }
+		if(tttaba[oldttscale][i]) { Patch_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; }
+		if(tttabk[oldttscale][i]) { Patch_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; }
+		if(tttabt[oldttscale][i]) { Patch_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; }
+		if(tttaft[oldttscale][i]) { Patch_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; }
+		if(ttknib[oldttscale][i]) { Patch_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; }
+		if(ttknif[oldttscale][i]) { Patch_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; }
+		if(ttknba[oldttscale][i]) { Patch_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; }
+		if(ttknbk[oldttscale][i]) { Patch_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; }
+		if(ttkndh[oldttscale][i]) { Patch_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; }
 	}
 	ttloaded[oldttscale] = false;
 }
diff --git a/src/g_game.c b/src/g_game.c
index f1cae8cf5e588c4d08780ac78689f472736cf573..2b304b4fdd054d03061613d47313f147004d35b3 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1678,7 +1678,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
 	// At this point, cmd doesn't contain the final angle yet,
 	// So we need to temporarily transform it so Lua scripters
 	// don't need to handle it differently than in other hooks.
-	if (gamestate == GS_LEVEL)
+	if (addedtogame && gamestate == GS_LEVEL)
 	{
 		INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn;
 		INT16 origangle = cmd->angleturn;
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 43fdc89f080bf2465747e698a96bc23a73c4aaf0..83a4e2e03d9b56cd503092762b7ac48fe52a5611 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -866,7 +866,7 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum)
 }
 
 // Download a Doom 'flat' to the hardware cache and make it ready for use
-void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum)
+void HWR_GetRawFlat(lumpnum_t flatlumpnum)
 {
 	GLMipmap_t *grmip;
 	patch_t *patch;
@@ -895,7 +895,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 		return;
 
 	if (levelflat->type == LEVELFLAT_FLAT)
-		HWR_LiterallyGetFlat(levelflat->u.flat.lumpnum);
+		HWR_GetRawFlat(levelflat->u.flat.lumpnum);
 	else if (levelflat->type == LEVELFLAT_TEXTURE)
 	{
 		GLMapTexture_t *grtex;
@@ -934,15 +934,17 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 #ifndef NO_PNG_LUMPS
 	else if (levelflat->type == LEVELFLAT_PNG)
 	{
-		INT32 pngwidth = 0, pngheight = 0;
 		GLMipmap_t *mipmap = levelflat->mipmap;
-		UINT8 *flat;
-		size_t size;
 
 		// Cache the picture.
-		if (!levelflat->picture)
+		if (!levelflat->mippic)
 		{
-			levelflat->picture = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0);
+			INT32 pngwidth = 0, pngheight = 0;
+			void *pic = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0);
+
+			Z_ChangeTag(pic, PU_LEVEL);
+			Z_SetUser(pic, &levelflat->mippic);
+
 			levelflat->width = (UINT16)pngwidth;
 			levelflat->height = (UINT16)pngheight;
 		}
@@ -950,7 +952,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 		// Make the mipmap.
 		if (mipmap == NULL)
 		{
-			mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_LEVEL, NULL);
+			mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_STATIC, NULL);
 			mipmap->format = GL_TEXFMT_P_8;
 			mipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
 			levelflat->mipmap = mipmap;
@@ -958,17 +960,22 @@ void HWR_GetLevelFlat(levelflat_t *levelflat)
 
 		if (!mipmap->data && !mipmap->downloaded)
 		{
+			UINT8 *flat;
+			size_t size;
+
+			if (levelflat->mippic == NULL)
+				I_Error("HWR_GetLevelFlat: levelflat->mippic == NULL");
+
 			mipmap->width = levelflat->width;
 			mipmap->height = levelflat->height;
+
 			size = (mipmap->width * mipmap->height);
 			flat = Z_Malloc(size, PU_LEVEL, &mipmap->data);
-			if (levelflat->picture == NULL)
-				I_Error("HWR_GetLevelFlat: levelflat->picture == NULL");
-			M_Memcpy(flat, levelflat->picture, size);
+			M_Memcpy(flat, levelflat->mippic, size);
 		}
 
 		// Tell the hardware driver to bind the current texture to the flat's mipmap
-		HWD.pfnSetTexture(mipmap);
+		HWR_SetCurrentTexture(mipmap);
 	}
 #endif
 	else // set no texture
@@ -1084,7 +1091,6 @@ void HWR_UnlockCachedPatch(GLPatch_t *gpatch)
 		return;
 
 	Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
-	Z_ChangeTag(gpatch, PU_HWRPATCHINFO_UNLOCKED);
 }
 
 static const INT32 picmode2GR[] =
diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h
index 11e41b18ac335a961c6fcff0d1b3dfff70659f49..7e56a14d0f71b9d575046ccb9877487169c3877d 100644
--- a/src/hardware/hw_data.h
+++ b/src/hardware/hw_data.h
@@ -48,44 +48,43 @@ struct GLColormap_s
 typedef struct GLColormap_s GLColormap_t;
 
 
-// data holds the address of the graphics data cached in heap memory
-//                NULL if the texture is not in Doom heap cache.
+// Texture information (misleadingly named "mipmap" all over the code.)
+// The *data pointer holds the address of the graphics data cached in heap memory.
+// NULL if the texture is not in SRB2's heap cache.
 struct GLMipmap_s
 {
-	// for TexDownloadMipMap
+	// for UpdateTexture
 	GLTextureFormat_t     format;
 	void                 *data;
 
 	UINT32                flags;
 	UINT16                height;
 	UINT16                width;
-	UINT32                downloaded;     // The GPU has this texture.
+	UINT32                downloaded; // The GPU has this texture.
 
 	struct GLMipmap_s    *nextcolormap;
 	struct GLColormap_s  *colormap;
-
-	struct GLMipmap_s    *nextmipmap; // Linked list of all textures
 };
 typedef struct GLMipmap_s GLMipmap_t;
 
 
 //
-// Doom texture info, as cached for hardware rendering
+// Level textures, as cached for hardware rendering.
 //
 struct GLMapTexture_s
 {
 	GLMipmap_t  mipmap;
-	float       scaleX;             //used for scaling textures on walls
+	float       scaleX; // Used for scaling textures on walls
 	float       scaleY;
 };
 typedef struct GLMapTexture_s GLMapTexture_t;
 
 
-// a cached patch as converted to hardware format
+// Patch information for the hardware renderer.
 struct GLPatch_s
 {
-	float               max_s,max_t;
-	GLMipmap_t          *mipmap;
+	GLMipmap_t *mipmap; // Texture data. Allocated whenever the patch is.
+	float       max_s, max_t;
 };
 typedef struct GLPatch_s GLPatch_t;
 
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index a782762a38c46dbb4161468b43b3041d215e8d2e..bd6afc74fa8631bd912664470d9f137652f1a4a8 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -255,7 +255,16 @@ enum ETextureFlags
 	TF_TRANSPARENT = 0x00000040,        // texture with some alpha == 0
 };
 
-typedef struct GLMipmap_s FTextureInfo;
+struct FTextureInfo
+{
+	UINT32 width, height;
+	UINT32 downloaded;
+	UINT32 format;
+
+	struct GLMipmap_s *texture;
+	struct FTextureInfo *prev, *next;
+};
+typedef struct FTextureInfo FTextureInfo;
 
 // jimita 14032019
 struct FLightInfo
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index c5d362520a56ea249aadade297ae7f4f68a232df..ba4923d10e76149cf0dd088aa7633db43e4a8ff0 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -437,18 +437,9 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 
 		if (!(option & V_SCALEPATCHMASK))
 		{
-			// if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
-			// cx and cy are possibly *slightly* off from float maths
-			// This is done before here compared to software because we directly alter cx and cy to centre
-			if (cx >= -0.1f && cx <= 0.1f && gpatch->width == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && gpatch->height == BASEVIDHEIGHT)
-			{
-				const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0]));
-				if (!column->topdelta)
-				{
-					const UINT8 *source = (const UINT8 *)(column) + 3;
-					HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
-				}
-			}
+			// if it's meant to cover the whole screen, black out the rest
+			// no the patch is cropped do not do this ever
+
 			// centre screen
 			if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
 			{
@@ -470,11 +461,11 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 	fwidth = w;
 	fheight = h;
 
-	if (fwidth > gpatch->width)
-		fwidth = gpatch->width;
+	if (sx + w > gpatch->width)
+		fwidth = gpatch->width - sx;
 
-	if (fheight > gpatch->height)
-		fheight = gpatch->height;
+	if (sy + h > gpatch->height)
+		fheight = gpatch->height - sy;
 
 	if (pscale != FRACUNIT)
 	{
@@ -506,13 +497,13 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
 
 	v[0].s = v[3].s = ((sx)/(float)(gpatch->width))*hwrPatch->max_s;
 	if (sx + w > gpatch->width)
-		v[2].s = v[1].s = hwrPatch->max_s - ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s;
+		v[2].s = v[1].s = hwrPatch->max_s;
 	else
 		v[2].s = v[1].s = ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s;
 
 	v[0].t = v[1].t = ((sy)/(float)(gpatch->height))*hwrPatch->max_t;
 	if (sy + h > gpatch->height)
-		v[2].t = v[3].t = hwrPatch->max_t - ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t;
+		v[2].t = v[3].t = hwrPatch->max_t;
 	else
 		v[2].t = v[3].t = ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t;
 
@@ -639,7 +630,7 @@ void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum
 	v[0].t = v[1].t = (float)((y & flatflag)/dflatsize);
 	v[2].t = v[3].t = (float)(v[0].t + h/dflatsize);
 
-	HWR_LiterallyGetFlat(flatlumpnum);
+	HWR_GetRawFlat(flatlumpnum);
 
 	//Hurdler: Boris, the same comment as above... but maybe for pics
 	// it not a problem since they don't have any transparent pixel
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index 5a2e0e44eaeb13ffc0465403fdd606e2f556fe2e..da4ee861435dee90e9cf7dc87ec22009b66128ff 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -40,13 +40,12 @@ EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutV
 EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky);
 EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags);
 EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor);
-EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo);
-EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo);
-EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *TexInfo);
+EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo);
+EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo);
+EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo);
 EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data);
 EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip);
 EXPORT void HWRAPI(ClearMipMapCache) (void);
-EXPORT void HWRAPI(ClearCacheList) (void);
 
 //Hurdler: added for backward compatibility
 EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
@@ -101,7 +100,6 @@ struct hwdriver_s
 	ReadRect            pfnReadRect;
 	GClipRect           pfnGClipRect;
 	ClearMipMapCache    pfnClearMipMapCache;
-	ClearCacheList      pfnClearCacheList;
 	SetSpecialState     pfnSetSpecialState;//Hurdler: added for backward compatibility
 	DrawModel           pfnDrawModel;
 	CreateModelVBOs     pfnCreateModelVBOs;
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 87405d3d457080e1fccd86206ac2d0dfb9b97db4..2aba622481d618a4e8f5d2d499e420e74123b9ce 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -118,7 +118,7 @@ patch_t *HWR_GetPic(lumpnum_t lumpnum);
 
 GLMapTexture_t *HWR_GetTexture(INT32 tex);
 void HWR_GetLevelFlat(levelflat_t *levelflat);
-void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum);
+void HWR_GetRawFlat(lumpnum_t flatlumpnum);
 
 void HWR_FreeTexture(patch_t *patch);
 void HWR_FreeTextureData(patch_t *patch);
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index a7e37d231a1d6401f99203e11bc97b8161f1a46b..c2d617eaf01eed55c4c7240a4cddd87b6196c2b8 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -3665,7 +3665,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
 static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts, const boolean precip)
 {
 	if (cv_glspritebillboarding.value
-		&& spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)
+		&& spr && spr->mobj && !R_ThingIsPaperSprite(spr->mobj)
 		&& wallVerts)
 	{
 		float basey = FIXED_TO_FLOAT(spr->mobj->z);
@@ -3707,7 +3707,6 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 	FBITFIELD blend = 0;
 	FBITFIELD occlusion;
 	boolean use_linkdraw_hack = false;
-	boolean splat = R_ThingIsFloorSprite(spr->mobj);
 	UINT8 alpha;
 
 	INT32 i;
@@ -3766,22 +3765,19 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 		baseWallVerts[0].t = baseWallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t;
 	}
 
-	if (!splat)
-	{
-		// if it has a dispoffset, push it a little towards the camera
-		if (spr->dispoffset) {
-			float co = -gl_viewcos*(0.05f*spr->dispoffset);
-			float si = -gl_viewsin*(0.05f*spr->dispoffset);
-			baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si;
-			baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si;
-			baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co;
-			baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co;
-		}
-
-		// Let dispoffset work first since this adjust each vertex
-		HWR_RotateSpritePolyToAim(spr, baseWallVerts, false);
+	// if it has a dispoffset, push it a little towards the camera
+	if (spr->dispoffset) {
+		float co = -gl_viewcos*(0.05f*spr->dispoffset);
+		float si = -gl_viewsin*(0.05f*spr->dispoffset);
+		baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si;
+		baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si;
+		baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co;
+		baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co;
 	}
 
+	// Let dispoffset work first since this adjust each vertex
+	HWR_RotateSpritePolyToAim(spr, baseWallVerts, false);
+
 	realtop = top = baseWallVerts[3].y;
 	realbot = bot = baseWallVerts[0].y;
 	ttop = baseWallVerts[3].t;
@@ -3914,7 +3910,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 
 		// The x and y only need to be adjusted in the case that it's not a papersprite
 		if (cv_glspritebillboarding.value
-			&& spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE))
+			&& spr->mobj && !R_ThingIsPaperSprite(spr->mobj))
 		{
 			// Get the x and z of the vertices so billboarding draws correctly
 			realheight = realbot - realtop;
@@ -3983,7 +3979,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
 static void HWR_DrawSprite(gl_vissprite_t *spr)
 {
 	FOutVector wallVerts[4];
-	patch_t *gpatch; // sprite patch converted to hardware
+	patch_t *gpatch;
 	FSurfaceInfo Surf;
 	const boolean splat = R_ThingIsFloorSprite(spr->mobj);
 
@@ -4284,7 +4280,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
 {
 	FBITFIELD blend = 0;
 	FOutVector wallVerts[4];
-	patch_t *gpatch; // sprite patch converted to hardware
+	patch_t *gpatch;
 	FSurfaceInfo Surf;
 
 	if (!spr->mobj)
@@ -4337,7 +4333,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
 			// Always use the light at the top instead of whatever I was doing before
 			INT32 light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false);
 
-			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+			if (!R_ThingIsFullBright(spr->mobj))
 				lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
 
 			if (*sector->lightlist[light].extra_colormap)
@@ -4345,7 +4341,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
 		}
 		else
 		{
-			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+			if (!R_ThingIsFullBright(spr->mobj))
 				lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
 
 			if (sector->extra_colormap)
@@ -4921,8 +4917,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
 
 	angle_t ang;
 	INT32 heightsec, phs;
-	const boolean papersprite = R_ThingIsPaperSprite(thing);
 	const boolean splat = R_ThingIsFloorSprite(thing);
+	const boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat);
 	angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
 	float z1, z2;
 
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 2e944d3e601c03f541bdf65d3ed57fda4c81d4a1..5caf344f75a3859751919338d8cea8b6badf1f92 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -158,7 +158,7 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_
 	jmp_buf jmpbuf;
 #endif
 #endif
-	png_FILE_p png_FILE;
+	volatile png_FILE_p png_FILE;
 	//Filename checking fixed ~Monster Iestyn and Golden
 	char *pngfilename = va("%s"PATHSEP"models"PATHSEP"%s", srb2home, filename);
 
@@ -1314,7 +1314,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 
 			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
 
-			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+			if (!R_ThingIsFullBright(spr->mobj))
 				lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
 
 			if (*sector->lightlist[light].extra_colormap)
@@ -1322,7 +1322,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		}
 		else
 		{
-			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+			if (!R_ThingIsFullBright(spr->mobj))
 				lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
 
 			if (sector->extra_colormap)
@@ -1340,10 +1340,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 		GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL;
 		INT32 durs = spr->mobj->state->tics;
 		INT32 tics = spr->mobj->tics;
-		//mdlframe_t *next = NULL;
-		const boolean papersprite = (spr->mobj->frame & FF_PAPERSPRITE);
-		const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP));
-		const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !(spr->mobj->frame & FF_HORIZONTALFLIP));
+		const boolean papersprite = (R_ThingIsPaperSprite(spr->mobj) && !R_ThingIsFloorSprite(spr->mobj));
+		const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj));
+		const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj));
 		spritedef_t *sprdef;
 		spriteframe_t *sprframe;
 		spriteinfo_t *sprinfo;
@@ -1405,6 +1404,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
 			|| ((!hwrBlendPatch->mipmap->format || !hwrBlendPatch->mipmap->downloaded) && !md2->noblendfile)))
 			md2_loadBlendTexture(md2);
 
+		// Load it again, because it isn't being loaded into blendgpatch after md2_loadblendtexture...
+		blendgpatch = md2->blendgrpatch;
+		if (blendgpatch)
+			hwrBlendPatch = ((GLPatch_t *)blendgpatch->hardware);
+
 		if (md2->error)
 			return false; // we already failed loading this before :(
 		if (!md2->model)
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 8cd948eeadf57a34fa1290479b2f84d26210ba28..6967bab7472599a3d36dfef195aeb5fcf0bb8b6f 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -58,8 +58,9 @@ static  GLuint      tex_downloaded  = 0;
 static  GLfloat     fov             = 90.0f;
 static  FBITFIELD   CurrentPolyFlags;
 
-static  FTextureInfo *gl_cachetail = NULL;
-static  FTextureInfo *gl_cachehead = NULL;
+// Linked list of all textures.
+static FTextureInfo *TexCacheTail = NULL;
+static FTextureInfo *TexCacheHead = NULL;
 
 RGBA_t  myPaletteData[256];
 GLint   screen_width    = 0;               // used by Draw2DLine()
@@ -961,8 +962,6 @@ EXPORT boolean HWRAPI(CompileShaders) (void)
 		}
 	}
 
-	SetShader(SHADER_DEFAULT);
-
 	return true;
 #else
 	return false;
@@ -1287,10 +1286,30 @@ void SetStates(void)
 // -----------------+
 // DeleteTexture    : Deletes a texture from the GPU and frees its data
 // -----------------+
-EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *pTexInfo)
+EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *pTexInfo)
 {
-	if (pTexInfo->downloaded)
+	FTextureInfo *head = TexCacheHead;
+
+	if (!pTexInfo)
+		return;
+	else if (pTexInfo->downloaded)
 		pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded);
+
+	while (head)
+	{
+		if (head->downloaded == pTexInfo->downloaded)
+		{
+			if (head->next)
+				head->next->prev = head->prev;
+			if (head->prev)
+				head->prev->next = head->next;
+			free(head);
+			break;
+		}
+
+		head = head->next;
+	}
+
 	pTexInfo->downloaded = 0;
 }
 
@@ -1303,23 +1322,26 @@ void Flush(void)
 {
 	//GL_DBG_Printf ("HWR_Flush()\n");
 
-	while (gl_cachehead)
+	while (TexCacheHead)
 	{
-		DeleteTexture(gl_cachehead);
-		gl_cachehead = gl_cachehead->nextmipmap;
-	}
+		FTextureInfo *pTexInfo = TexCacheHead;
+		GLMipmap_t *texture = pTexInfo->texture;
 
-	ClearCacheList(); //Hurdler: well, gl_cachehead is already NULL
-	tex_downloaded = 0;
-}
+		if (pTexInfo->downloaded)
+		{
+			pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded);
+			pTexInfo->downloaded = 0;
+		}
 
+		if (texture)
+			texture->downloaded = 0;
 
-// -----------------+
-// ClearCacheList   : Clears the texture cache tail and head
-// -----------------+
-EXPORT void HWRAPI(ClearCacheList) (void)
-{
-	gl_cachetail = gl_cachehead = NULL;
+		TexCacheHead = pTexInfo->next;
+		free(pTexInfo);
+	}
+
+	TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL
+	tex_downloaded = 0;
 }
 
 
@@ -1718,7 +1740,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags)
 // -----------------+
 // UpdateTexture    : Updates the texture data.
 // -----------------+
-EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo)
+EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
 {
 	// Download a mipmap
 	boolean updatemipmap = true;
@@ -1920,7 +1942,7 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo)
 // -----------------+
 // SetTexture       : The mipmap becomes the current texture source
 // -----------------+
-EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
+EXPORT void HWRAPI(SetTexture) (GLMipmap_t *pTexInfo)
 {
 	if (!pTexInfo)
 	{
@@ -1937,17 +1959,25 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo)
 	}
 	else
 	{
+		FTextureInfo *newTex = calloc(1, sizeof (*newTex));
+
 		UpdateTexture(pTexInfo);
-		pTexInfo->nextmipmap = NULL;
+
+		newTex->texture = pTexInfo;
+		newTex->downloaded = (UINT32)pTexInfo->downloaded;
+		newTex->width = (UINT32)pTexInfo->width;
+		newTex->height = (UINT32)pTexInfo->height;
+		newTex->format = (UINT32)pTexInfo->format;
 
 		// insertion at the tail
-		if (gl_cachetail)
+		if (TexCacheTail)
 		{
-			gl_cachetail->nextmipmap = pTexInfo;
-			gl_cachetail = pTexInfo;
+			newTex->prev = TexCacheTail;
+			TexCacheTail->next = newTex;
+			TexCacheTail = newTex;
 		}
 		else // initialization of the linked list
-			gl_cachetail = gl_cachehead = pTexInfo;
+			TexCacheTail = TexCacheHead = newTex;
 	}
 }
 
@@ -3011,7 +3041,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
 
 EXPORT INT32  HWRAPI(GetTextureUsed) (void)
 {
-	FTextureInfo *tmp = gl_cachehead;
+	FTextureInfo *tmp = TexCacheHead;
 	INT32 res = 0;
 
 	while (tmp)
@@ -3028,7 +3058,7 @@ EXPORT INT32  HWRAPI(GetTextureUsed) (void)
 
 		// Add it up!
 		res += tmp->height*tmp->width*bpp;
-		tmp = tmp->nextmipmap;
+		tmp = tmp->next;
 	}
 
 	return res;
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 0b24d06906cb66224a4ef3349cf6d12249d913eb..7c4f1acf1124b1087dcd7a90cf61b2f883434f18 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -98,6 +98,7 @@ patch_t *emeraldpics[3][8]; // 0 = normal, 1 = tiny, 2 = coinbox
 static patch_t *emblemicon;
 patch_t *tokenicon;
 static patch_t *exiticon;
+static patch_t *nopingicon;
 
 //-------------------------------------------
 //              misc vars
@@ -286,6 +287,7 @@ void HU_LoadGraphics(void)
 	emblemicon = W_CachePatchName("EMBLICON", PU_HUDGFX);
 	tokenicon = W_CachePatchName("TOKNICON", PU_HUDGFX);
 	exiticon = W_CachePatchName("EXITICON", PU_HUDGFX);
+	nopingicon = W_CachePatchName("NOPINGICON", PU_HUDGFX);
 
 	emeraldpics[0][0] = W_CachePatchName("CHAOS1", PU_HUDGFX);
 	emeraldpics[0][1] = W_CachePatchName("CHAOS2", PU_HUDGFX);
@@ -2246,8 +2248,8 @@ void HU_Erase(void)
 //
 void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags)
 {
-	UINT8 numbars = 1; // how many ping bars do we draw?
-	UINT8 barcolor = 35; // color we use for the bars (green, yellow or red)
+	UINT8 numbars = 0; // how many ping bars do we draw?
+	UINT8 barcolor = 31; // color we use for the bars (green, yellow, red or black)
 	SINT8 i = 0;
 	SINT8 yoffset = 6;
 	INT32 dx = x+1 - (V_SmallStringWidth(va("%dms", ping),
@@ -2260,11 +2262,16 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags)
 	}
 	else if (ping < 256)
 	{
-		numbars = 2; // Apparently ternaries w/ multiple statements don't look good in C so I decided against it.
+		numbars = 2;
 		barcolor = 73;
 	}
+	else if (ping < UINT32_MAX)
+	{
+		numbars = 1;
+		barcolor = 35;
+	}
 
-	if (!notext || vid.width >= 640) // how sad, we're using a shit resolution.
+	if (ping < UINT32_MAX && (!notext || vid.width >= 640)) // how sad, we're using a shit resolution.
 		V_DrawSmallString(dx, y+4, V_ALLOWLOWERCASE|flags, va("%dms", ping));
 
 	for (i=0; (i<3); i++) // Draw the ping bar
@@ -2275,6 +2282,9 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags)
 
 		yoffset -= 2;
 	}
+
+	if (ping == UINT32_MAX)
+		V_DrawSmallScaledPatch(x + 4 - nopingicon->width/2, y + 9 - nopingicon->height/2, 0, nopingicon);
 }
 
 //
@@ -2301,16 +2311,17 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
 
 		if (!splitscreen) // don't draw it on splitscreen,
 		{
-			if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
-				HU_drawPing(x+ 253, y, playerpingtable[tab[i].num], false, 0);
+			if (tab[i].num != serverplayer)
+				HU_drawPing(x + 253, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0);
 			//else
 			//	V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER");
 		}
 
-		V_DrawString(x + 20, y,
-		             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-		             | (greycheck ? V_60TRANS : 0)
-		             | V_ALLOWLOWERCASE, tab[i].name);
+		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
+			V_DrawString(x + 20, y,
+		                 ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
+		                 | (greycheck ? V_60TRANS : 0)
+		                 | V_ALLOWLOWERCASE, tab[i].name);
 
 		// Draw emeralds
 		if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1))
@@ -2458,10 +2469,11 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		supercheck = supercheckdef;
 
 		strlcpy(name, tab[i].name, 8);
-		V_DrawString(x + 10, y,
-		             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-		             | (greycheck ? 0 : V_TRANSLUCENT)
-		             | V_ALLOWLOWERCASE, name);
+		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
+			V_DrawString(x + 10, y,
+			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
+			             | (greycheck ? 0 : V_TRANSLUCENT)
+			             | V_ALLOWLOWERCASE, name);
 
 		if (gametyperules & GTR_TEAMFLAGS)
 		{
@@ -2500,10 +2512,10 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		V_DrawRightAlignedThinString(x+128, y, ((players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
 		if (!splitscreen)
 		{
-			if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
-				HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
-		//else
-			//V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
+			if (tab[i].num != serverplayer)
+				HU_drawPing(x + 135, y+1, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], true, 0);
+			//else
+				//V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
 		}
 	}
 }
@@ -2586,10 +2598,11 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		supercheck = supercheckdef;
 
 		strlcpy(name, tab[i].name, 7);
-		V_DrawString(x + 20, y,
-		             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-		             | (greycheck ? V_TRANSLUCENT : 0)
-		             | V_ALLOWLOWERCASE, name);
+		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
+			V_DrawString(x + 20, y,
+			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
+			             | (greycheck ? V_TRANSLUCENT : 0)
+			             | V_ALLOWLOWERCASE, name);
 
 		if (gametyperules & GTR_TEAMFLAGS)
 		{
@@ -2624,10 +2637,10 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
 		if (!splitscreen)
 		{
-			if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
-				HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
-		//else
-		//	V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
+			if (tab[i].num != serverplayer)
+				HU_drawPing(x+ 113, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0);
+			//else
+			//	V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
 		}
 	}
 }
@@ -2655,15 +2668,16 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
 		supercheck = supercheckdef;
 
 		strlcpy(name, tab[i].name, 7);
-		if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
-			HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
+		if (tab[i].num != serverplayer)
+			HU_drawPing(x+ 113, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0);
 		//else
 		//	V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
 
-		V_DrawString(x + 20, y,
-		             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-		             | (greycheck ? V_TRANSLUCENT : 0)
-		             | V_ALLOWLOWERCASE, name);
+		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
+			V_DrawString(x + 20, y,
+			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
+			             | (greycheck ? V_TRANSLUCENT : 0)
+			             | V_ALLOWLOWERCASE, name);
 
 		if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
 			V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives));
@@ -2763,16 +2777,17 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
 		strlcpy(name, tab[i].name, 7);
 		if (!splitscreen) // don't draw it on splitscreen,
 		{
-			if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
-				HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0);
-		//else
-		//	V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
+			if (tab[i].num != serverplayer)
+				HU_drawPing(x+ 135, y+1, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], true, 0);
+			//else
+			//	V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
 		}
 
-		V_DrawString(x + 10, y,
-		             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-		             | (greycheck ? 0 : V_TRANSLUCENT)
-		             | V_ALLOWLOWERCASE, name);
+		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
+			V_DrawString(x + 10, y,
+			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
+			             | (greycheck ? 0 : V_TRANSLUCENT)
+			             | V_ALLOWLOWERCASE, name);
 
 		if (G_GametypeUsesLives()) //show lives
 			V_DrawRightAlignedThinString(x-1, y, V_ALLOWLOWERCASE, va("%d", players[tab[i].num].lives));
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 2405915064f99986cb53e05453825f83b6a6d8d7..d432348b0350fd4312b8cb01617617f73aa51ea7 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -432,7 +432,7 @@ static int lib_pAproxDistance(lua_State *L)
 	fixed_t dx = luaL_checkfixed(L, 1);
 	fixed_t dy = luaL_checkfixed(L, 2);
 	//HUDSAFE
-	lua_pushfixed(L, P_AproxDistance(dx, dy));
+	lua_pushfixed(L, R_PointToDist2(0, 0, dx, dy));
 	return 1;
 }
 
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 6a9091cc949f364c8e01fd19d2b3e0eb740d44c8..0161417960fc30556b1fdf11e112c4a7c6f5215f 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -583,7 +583,7 @@ static int sector_get(lua_State *L)
 		lua_pushinteger(L, sector->special);
 		return 1;
 	case sector_tag:
-		lua_pushinteger(L, Tag_FGet(&sector->tags));
+		lua_pushinteger(L, (UINT16)Tag_FGet(&sector->tags));
 		return 1;
 	case sector_taglist:
 		LUA_PushUserdata(L, &sector->tags, META_SECTORTAGLIST);
@@ -828,6 +828,17 @@ static int line_get(lua_State *L)
 		lua_pushinteger(L, line->special);
 		return 1;
 	case line_tag:
+		// HELLO
+		// THIS IS LJ SONIC
+		// HOW IS YOUR DAY?
+		// BY THE WAY WHEN 2.3 OR 3.0 OR 4.0 OR SRB3 OR SRB4 OR WHATEVER IS OUT
+		// YOU SHOULD REMEMBER TO CHANGE THIS SO IT ALWAYS RETURNS A UNSIGNED VALUE
+		// HAVE A NICE DAY
+		//
+		//
+		//
+		//
+		// you are ugly
 		lua_pushinteger(L, Tag_FGet(&line->tags));
 		return 1;
 	case line_taglist:
diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c
index 10ba42ee0b78e2f834a4748edcd4deb6176fab4f..b6046ab53b2d37948bc6fdb40c540a49d148be57 100644
--- a/src/lua_mathlib.c
+++ b/src/lua_mathlib.c
@@ -15,6 +15,7 @@
 #include "tables.h"
 #include "p_local.h"
 #include "doomstat.h" // for ALL7EMERALDS
+#include "r_main.h" // for R_PointToDist2
 
 #include "lua_script.h"
 #include "lua_libs.h"
@@ -129,7 +130,7 @@ static int lib_fixedsqrt(lua_State *L)
 
 static int lib_fixedhypot(lua_State *L)
 {
-	lua_pushfixed(L, FixedHypot(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
+	lua_pushfixed(L, R_PointToDist2(0, 0, luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
 	return 1;
 }
 
diff --git a/src/lua_polyobjlib.c b/src/lua_polyobjlib.c
index 365d970563dd504cc896abaac756fffd6cd2458f..2a5bcfbf19a54458e63960d5b06c1466f96487de 100644
--- a/src/lua_polyobjlib.c
+++ b/src/lua_polyobjlib.c
@@ -417,7 +417,7 @@ static int lib_getPolyObject(lua_State *L)
 	{
 		i = luaL_checkinteger(L, 2);
 		if (i < 0 || i >= numPolyObjects)
-			return luaL_error(L, "PolyObjects[] index %d out of range (0 - %d)", i, numPolyObjects-1);
+			return luaL_error(L, "polyobjects[] index %d out of range (0 - %d)", i, numPolyObjects-1);
 		LUA_PushUserdata(L, &PolyObjects[i], META_POLYOBJ);
 		return 1;
 	}
@@ -481,6 +481,6 @@ int LUA_PolyObjLib(lua_State *L)
 			lua_pushcfunction(L, lib_numPolyObjects);
 			lua_setfield(L, -2, "__len");
 		lua_setmetatable(L, -2);
-	lua_setglobal(L, "PolyObjects");
+	lua_setglobal(L, "polyobjects");
 	return 0;
 }
diff --git a/src/lua_script.c b/src/lua_script.c
index bc88928f3f2e0e786d12c9e941e87dc875d3ce48..7fd5a98e6f71620ad4c89eff58e71e222773b622 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -333,7 +333,7 @@ int LUA_PushGlobals(lua_State *L, const char *word)
 		return 1;
 	// local player variables, by popular request
 	} else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1)
-		if (consoleplayer < 0 || !playeringame[consoleplayer])
+		if (!addedtogame || consoleplayer < 0 || !playeringame[consoleplayer])
 			return 0;
 		LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
 		return 1;
diff --git a/src/m_menu.c b/src/m_menu.c
index 05c819c3751e19312f689243de60b7995fbaf48f..516bd34c159be9be23acf7f18fc6579646a89edb 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -1612,53 +1612,54 @@ static menuitem_t OP_ServerOptionsMenu[] =
 	{IT_STRING | IT_CVAR,    NULL, "Max Players",                      &cv_maxplayers,          21},
 	{IT_STRING | IT_CVAR,    NULL, "Allow Add-on Downloading",         &cv_downloading,         26},
 	{IT_STRING | IT_CVAR,    NULL, "Allow players to join",            &cv_allownewplayer,      31},
+	{IT_STRING | IT_CVAR,    NULL, "Minutes for reconnecting",         &cv_rejointimeout,       36},
 #endif
-	{IT_STRING | IT_CVAR,    NULL, "Map progression",                  &cv_advancemap,          36},
-	{IT_STRING | IT_CVAR,    NULL, "Intermission Timer",               &cv_inttime,             41},
+	{IT_STRING | IT_CVAR,    NULL, "Map progression",                  &cv_advancemap,          41},
+	{IT_STRING | IT_CVAR,    NULL, "Intermission Timer",               &cv_inttime,             46},
 
-	{IT_HEADER, NULL, "Characters", NULL, 50},
-	{IT_STRING | IT_CVAR,    NULL, "Force a character",                &cv_forceskin,           56},
-	{IT_STRING | IT_CVAR,    NULL, "Restrict character changes",       &cv_restrictskinchange,  61},
+	{IT_HEADER, NULL, "Characters", NULL, 55},
+	{IT_STRING | IT_CVAR,    NULL, "Force a character",                &cv_forceskin,           61},
+	{IT_STRING | IT_CVAR,    NULL, "Restrict character changes",       &cv_restrictskinchange,  66},
 
-	{IT_HEADER, NULL, "Items", NULL, 70},
-	{IT_STRING | IT_CVAR,    NULL, "Item respawn delay",               &cv_itemrespawntime,     76},
-	{IT_STRING | IT_SUBMENU, NULL, "Mystery Item Monitor Toggles...",  &OP_MonitorToggleDef,    81},
+	{IT_HEADER, NULL, "Items", NULL, 75},
+	{IT_STRING | IT_CVAR,    NULL, "Item respawn delay",               &cv_itemrespawntime,     81},
+	{IT_STRING | IT_SUBMENU, NULL, "Mystery Item Monitor Toggles...",  &OP_MonitorToggleDef,    86},
 
-	{IT_HEADER, NULL, "Cooperative", NULL, 90},
-	{IT_STRING | IT_CVAR,    NULL, "Players required for exit",        &cv_playersforexit,      96},
-	{IT_STRING | IT_CVAR,    NULL, "Starposts",                        &cv_coopstarposts,      101},
-	{IT_STRING | IT_CVAR,    NULL, "Life sharing",                     &cv_cooplives,          106},
-	{IT_STRING | IT_CVAR,    NULL, "Post-goal free roaming",           &cv_exitmove,           111},
+	{IT_HEADER, NULL, "Cooperative", NULL, 95},
+	{IT_STRING | IT_CVAR,    NULL, "Players required for exit",        &cv_playersforexit,     101},
+	{IT_STRING | IT_CVAR,    NULL, "Starposts",                        &cv_coopstarposts,      106},
+	{IT_STRING | IT_CVAR,    NULL, "Life sharing",                     &cv_cooplives,          111},
+	{IT_STRING | IT_CVAR,    NULL, "Post-goal free roaming",           &cv_exitmove,           116},
 
-	{IT_HEADER, NULL, "Race, Competition", NULL, 120},
-	{IT_STRING | IT_CVAR,    NULL, "Level completion countdown",       &cv_countdowntime,      126},
-	{IT_STRING | IT_CVAR,    NULL, "Item Monitors",                    &cv_competitionboxes,   131},
+	{IT_HEADER, NULL, "Race, Competition", NULL, 125},
+	{IT_STRING | IT_CVAR,    NULL, "Level completion countdown",       &cv_countdowntime,      131},
+	{IT_STRING | IT_CVAR,    NULL, "Item Monitors",                    &cv_competitionboxes,   136},
 
-	{IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 140},
-	{IT_STRING | IT_CVAR,    NULL, "Time Limit",                       &cv_timelimit,          146},
-	{IT_STRING | IT_CVAR,    NULL, "Score Limit",                      &cv_pointlimit,         151},
-	{IT_STRING | IT_CVAR,    NULL, "Overtime on Tie",                  &cv_overtime,           156},
-	{IT_STRING | IT_CVAR,    NULL, "Player respawn delay",             &cv_respawntime,        161},
+	{IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 145},
+	{IT_STRING | IT_CVAR,    NULL, "Time Limit",                       &cv_timelimit,          151},
+	{IT_STRING | IT_CVAR,    NULL, "Score Limit",                      &cv_pointlimit,         156},
+	{IT_STRING | IT_CVAR,    NULL, "Overtime on Tie",                  &cv_overtime,           161},
+	{IT_STRING | IT_CVAR,    NULL, "Player respawn delay",             &cv_respawntime,        166},
 
-	{IT_STRING | IT_CVAR,    NULL, "Item Monitors",                    &cv_matchboxes,         171},
-	{IT_STRING | IT_CVAR,    NULL, "Weapon Rings",                     &cv_specialrings,       176},
-	{IT_STRING | IT_CVAR,    NULL, "Power Stones",                     &cv_powerstones,        181},
+	{IT_STRING | IT_CVAR,    NULL, "Item Monitors",                    &cv_matchboxes,         176},
+	{IT_STRING | IT_CVAR,    NULL, "Weapon Rings",                     &cv_specialrings,       181},
+	{IT_STRING | IT_CVAR,    NULL, "Power Stones",                     &cv_powerstones,        186},
 
-	{IT_STRING | IT_CVAR,    NULL, "Flag respawn delay",               &cv_flagtime,           191},
-	{IT_STRING | IT_CVAR,    NULL, "Hiding time",                      &cv_hidetime,           196},
+	{IT_STRING | IT_CVAR,    NULL, "Flag respawn delay",               &cv_flagtime,           196},
+	{IT_STRING | IT_CVAR,    NULL, "Hiding time",                      &cv_hidetime,           201},
 
-	{IT_HEADER, NULL, "Teams", NULL, 205},
-	{IT_STRING | IT_CVAR,    NULL, "Autobalance sizes",                &cv_autobalance,        211},
-	{IT_STRING | IT_CVAR,    NULL, "Scramble on Map Change",           &cv_scrambleonchange,   216},
+	{IT_HEADER, NULL, "Teams", NULL, 210},
+	{IT_STRING | IT_CVAR,    NULL, "Autobalance sizes",                &cv_autobalance,        216},
+	{IT_STRING | IT_CVAR,    NULL, "Scramble on Map Change",           &cv_scrambleonchange,   221},
 
 #ifndef NONET
-	{IT_HEADER, NULL, "Advanced", NULL, 225},
-	{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server",        &cv_masterserver,       231},
+	{IT_HEADER, NULL, "Advanced", NULL, 230},
+	{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server",        &cv_masterserver,       236},
 
-	{IT_STRING | IT_CVAR,    NULL, "Join delay",                       &cv_joindelay,          246},
-	{IT_STRING | IT_CVAR,    NULL, "Attempts to resynchronise",        &cv_resynchattempts,    251},
+	{IT_STRING | IT_CVAR,    NULL, "Join delay",                       &cv_joindelay,          251},
+	{IT_STRING | IT_CVAR,    NULL, "Attempts to resynchronise",        &cv_resynchattempts,    256},
 
-	{IT_STRING | IT_CVAR,    NULL, "Show IP Address of Joiners",       &cv_showjoinaddress,    256},
+	{IT_STRING | IT_CVAR,    NULL, "Show IP Address of Joiners",       &cv_showjoinaddress,    261},
 #endif
 };
 
diff --git a/src/m_misc.c b/src/m_misc.c
index ad2d133ab1dd8e6f743c4c2bab8adecd35d699e7..17a398b83f9b26a19d756a5fdfafe8b8a63652c5 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -165,7 +165,9 @@ consvar_t cv_zlib_window_bitsa = CVAR_INIT ("apng_window_size", "32k", CV_SAVE,
 consvar_t cv_apng_delay = CVAR_INIT ("apng_speed", "1x", CV_SAVE, apng_delay_t, NULL);
 consvar_t cv_apng_downscale = CVAR_INIT ("apng_downscale", "On", CV_SAVE, CV_OnOff, NULL);
 
+#ifdef USE_APNG
 static boolean apng_downscale = false; // So nobody can do something dumb like changing cvars mid output
+#endif
 
 boolean takescreenshot = false; // Take a screenshot this tic
 
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 203e04af12e58ade1431aa872b5eb5785f752e87..59176d6cc8ba44cc31d710ef6a87da801a1e62d8 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1834,7 +1834,7 @@ void A_SnailerThink(mobj_t *actor)
 			fixed_t dist;
 			fixed_t dx, dy;
 
-			dist = R_PointToDist2(0, 0, actor->x - actor->target->x, actor->y - actor->target->y);
+			dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y);
 
 			if (an > ANGLE_45 && an <= ANGLE_90) // fire at 45 degrees to the left
 			{
@@ -4912,7 +4912,7 @@ void A_ThrownRing(mobj_t *actor)
 		}
 
 		if (actor->tracer && (actor->tracer->health)
-			&& (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow.
+			&& (actor->tracer->player && actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow.
 		{
 			const INT32 temp = actor->threshold;
 			actor->threshold = 32000;
@@ -5920,13 +5920,18 @@ void A_DetonChase(mobj_t *actor)
 
 	if (actor->reactiontime == -42)
 	{
-		fixed_t xyspeed;
+		fixed_t xyspeed, speed;
+
+		if (actor->target->player)
+			speed = actor->target->player->normalspeed;
+		else
+			speed = actor->target->info->speed;
 
 		actor->reactiontime = -42;
 
 		exact = actor->movedir>>ANGLETOFINESHIFT;
-		xyspeed = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINECOSINE(exact));
-		actor->momz = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINESINE(exact));
+		xyspeed = FixedMul(FixedMul(speed,3*FRACUNIT/4), FINECOSINE(exact));
+		actor->momz = FixedMul(FixedMul(speed,3*FRACUNIT/4), FINESINE(exact));
 
 		exact = actor->angle>>ANGLETOFINESHIFT;
 		actor->momx = FixedMul(xyspeed, FINECOSINE(exact));
@@ -7521,7 +7526,7 @@ void A_Boss2PogoTarget(mobj_t *actor)
 	}
 
 	// Target hit, retreat!
-	if (actor->target->player->powers[pw_flashing] > TICRATE || actor->flags2 & MF2_FRET)
+	if ((actor->target->player && actor->target->player->powers[pw_flashing] > TICRATE) || actor->flags2 & MF2_FRET)
 	{
 		UINT8 prandom = P_RandomByte();
 		actor->z++; // unstick from the floor
@@ -7532,7 +7537,7 @@ void A_Boss2PogoTarget(mobj_t *actor)
 	// Try to land on top of the player.
 	else if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(512*FRACUNIT, actor->scale))
 	{
-		fixed_t airtime, gravityadd, zoffs;
+		fixed_t airtime, gravityadd, zoffs, height;
 
 		// check gravity in the sector (for later math)
 		P_CheckGravity(actor, true);
@@ -7554,7 +7559,13 @@ void A_Boss2PogoTarget(mobj_t *actor)
 		// Remember, kids!
 		// Reduced down Calculus lets you avoid bad 'logic math' loops!
 		//airtime = FixedDiv(-actor->momz<<1, gravityadd)<<1; // going from 0 to 0 is much simpler
-		zoffs = (P_GetPlayerHeight(actor->target->player)>>1) + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height,
+
+		if (actor->target->player)
+			height = P_GetPlayerHeight(actor->target->player) >> 1;
+		else
+			height = actor->target->height >> 1;
+
+		zoffs = height + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height,
 		airtime = FixedDiv((-actor->momz - FixedSqrt(FixedMul(actor->momz,actor->momz)+zoffs)), gravityadd)<<1; // to try and land on their head rather than on their feet
 
 		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
@@ -9868,22 +9879,23 @@ void A_Custom3DRotate(mobj_t *actor)
 	if (LUA_CallAction(A_CUSTOM3DROTATE, actor))
 		return;
 
-	if (actor->target->health == 0)
+	if (!actor->target) // Ensure we actually have a target first.
 	{
+		CONS_Printf("Error: A_Custom3DRotate: Object has no target.\n");
 		P_RemoveMobj(actor);
 		return;
 	}
 
-	if (!actor->target) // This should NEVER happen.
+	if (actor->target->health == 0)
 	{
-		if (cv_debug)
-			CONS_Printf("Error: Object has no target\n");
 		P_RemoveMobj(actor);
 		return;
 	}
+
 	if (hspeed==0 && vspeed==0)
 	{
-		CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n");
+		if (cv_debug)
+			CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n");
 		return;
 	}
 
diff --git a/src/p_local.h b/src/p_local.h
index 9359290fae06fc000daece09423260b70a565ac7..8caab0d2716f97f376580b7fc53f6660e5e7082d 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -279,7 +279,6 @@ 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);
-void P_SetMobjSpawnDefaults(mobj_t *mobj);
 
 void P_RecalcPrecipInSector(sector_t *sector);
 void P_PrecipitationEffects(void);
diff --git a/src/p_map.c b/src/p_map.c
index b934e3255323e86a7ae572342fa27f3a84db516c..a1cad524e14e2739af074b9ea24887b0d077eb95 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -2257,6 +2257,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 			{
 				if (!P_BlockThingsIterator(bx, by, PIT_CheckThing))
 					blockval = false;
+				else
+					tmhitthing = tmfloorthing;
 				if (P_MobjWasRemoved(tmthing))
 					return false;
 			}
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 5cde1639c8022909351df40a73bcaddb0bab1029..49db6daee9916632abb3a9fedb3c18a6f6871e82 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -10443,7 +10443,44 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 	mobj->x = x;
 	mobj->y = y;
 
-	P_SetMobjSpawnDefaults(mobj);
+	mobj->radius = info->radius;
+	mobj->height = info->height;
+	mobj->flags = info->flags;
+
+	mobj->health = (info->spawnhealth ? info->spawnhealth : 1);
+
+	mobj->reactiontime = info->reactiontime;
+
+	mobj->lastlook = -1; // stuff moved in P_enemy.P_LookForPlayer
+
+	// do not set the state with P_SetMobjState,
+	// because action routines can not be called yet
+	st = &states[info->spawnstate];
+
+	mobj->state = st;
+	mobj->tics = st->tics;
+	mobj->sprite = st->sprite;
+	mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits..
+	P_SetupStateAnimation(mobj, st);
+
+	mobj->friction = ORIG_FRICTION;
+
+	mobj->movefactor = FRACUNIT;
+
+	// All mobjs are created at 100% scale.
+	mobj->scale = FRACUNIT;
+	mobj->destscale = mobj->scale;
+	mobj->scalespeed = FRACUNIT/12;
+
+	// TODO: Make this a special map header
+	if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN))
+		mobj->destscale = FRACUNIT/2;
+
+	// Sprite rendering
+	mobj->blendmode = AST_TRANSLUCENT;
+	mobj->spritexscale = mobj->spriteyscale = mobj->scale;
+	mobj->spritexoffset = mobj->spriteyoffset = 0;
+	mobj->floorspriteslope = NULL;
 
 	// set subsector and/or block links
 	P_SetThingPosition(mobj);
@@ -10750,8 +10787,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 		mobj->frame &= ~FF_FRAMEMASK;
 	}
 
-	st = &states[info->spawnstate];
-
 	// Call action functions when the state is set
 	if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC))
 	{
@@ -10782,52 +10817,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 	return mobj;
 }
 
-void P_SetMobjSpawnDefaults(mobj_t *mobj)
-{
-	const mobjinfo_t *info = mobj->info;
-	state_t *st = &states[info->spawnstate];
-
-	mobj->radius = info->radius;
-	mobj->height = info->height;
-	mobj->flags = info->flags;
-
-	mobj->health = (info->spawnhealth ? info->spawnhealth : 1);
-
-	mobj->reactiontime = info->reactiontime;
-
-	mobj->lastlook = -1; // stuff moved in P_enemy.P_LookForPlayer
-
-	// do not set the state with P_SetMobjState,
-	// because action routines can not be called yet
-	mobj->state = st;
-	mobj->tics = st->tics;
-	mobj->sprite = st->sprite;
-	mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits..
-	P_SetupStateAnimation(mobj, st);
-
-	mobj->friction = ORIG_FRICTION;
-
-	mobj->movefactor = FRACUNIT;
-
-	// All mobjs are created at 100% scale.
-	mobj->scale = FRACUNIT;
-	mobj->destscale = mobj->scale;
-	mobj->scalespeed = FRACUNIT/12;
-
-	// TODO: Make this a special map header
-	if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN))
-		mobj->destscale = FRACUNIT/2;
-
-	// Make sure scale matches destscale immediately when spawned
-	P_SetScale(mobj, mobj->destscale);
-
-	// Sprite rendering
-	mobj->blendmode = AST_TRANSLUCENT;
-	mobj->spritexscale = mobj->spriteyscale = FRACUNIT;
-	mobj->spritexoffset = mobj->spriteyoffset = 0;
-	mobj->floorspriteslope = NULL;
-}
-
 static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 {
 	state_t *st;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index c1364e08fc4400349dac9e7325b4d2ee0b8ca8a4..03229e740bc0b5cddc3940ee8df0b96d1843347d 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -2692,10 +2692,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 		}
 		mobj->type = i;
 	}
-
 	mobj->info = &mobjinfo[mobj->type];
-	P_SetMobjSpawnDefaults(mobj);
-
 	if (diff & MD_POS)
 	{
 		mobj->x = READFIXED(save_p);
@@ -2721,21 +2718,35 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 
 	if (diff & MD_RADIUS)
 		mobj->radius = READFIXED(save_p);
+	else
+		mobj->radius = mobj->info->radius;
 	if (diff & MD_HEIGHT)
 		mobj->height = READFIXED(save_p);
+	else
+		mobj->height = mobj->info->height;
 	if (diff & MD_FLAGS)
 		mobj->flags = READUINT32(save_p);
+	else
+		mobj->flags = mobj->info->flags;
 	if (diff & MD_FLAGS2)
 		mobj->flags2 = READUINT32(save_p);
 	if (diff & MD_HEALTH)
 		mobj->health = READINT32(save_p);
+	else
+		mobj->health = mobj->info->spawnhealth;
 	if (diff & MD_RTIME)
 		mobj->reactiontime = READINT32(save_p);
+	else
+		mobj->reactiontime = mobj->info->reactiontime;
 
 	if (diff & MD_STATE)
 		mobj->state = &states[READUINT16(save_p)];
+	else
+		mobj->state = &states[mobj->info->spawnstate];
 	if (diff & MD_TICS)
 		mobj->tics = READINT32(save_p);
+	else
+		mobj->tics = mobj->state->tics;
 	if (diff & MD_SPRITE) {
 		mobj->sprite = READUINT16(save_p);
 		if (mobj->sprite == SPR_PLAY)
@@ -2751,6 +2762,11 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 		mobj->frame = READUINT32(save_p);
 		mobj->anim_duration = READUINT16(save_p);
 	}
+	else
+	{
+		mobj->frame = mobj->state->frame;
+		mobj->anim_duration = (UINT16)mobj->state->var2;
+	}
 	if (diff & MD_EFLAGS)
 		mobj->eflags = READUINT16(save_p);
 	if (diff & MD_PLAYER)
@@ -2767,14 +2783,20 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 		mobj->threshold = READINT32(save_p);
 	if (diff & MD_LASTLOOK)
 		mobj->lastlook = READINT32(save_p);
+	else
+		mobj->lastlook = -1;
 	if (diff & MD_TARGET)
 		mobj->target = (mobj_t *)(size_t)READUINT32(save_p);
 	if (diff & MD_TRACER)
 		mobj->tracer = (mobj_t *)(size_t)READUINT32(save_p);
 	if (diff & MD_FRICTION)
 		mobj->friction = READFIXED(save_p);
+	else
+		mobj->friction = ORIG_FRICTION;
 	if (diff & MD_MOVEFACTOR)
 		mobj->movefactor = READFIXED(save_p);
+	else
+		mobj->movefactor = FRACUNIT;
 	if (diff & MD_FUSE)
 		mobj->fuse = READINT32(save_p);
 	if (diff & MD_WATERTOP)
@@ -2783,10 +2805,16 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 		mobj->waterbottom = READFIXED(save_p);
 	if (diff & MD_SCALE)
 		mobj->scale = READFIXED(save_p);
+	else
+		mobj->scale = FRACUNIT;
 	if (diff & MD_DSCALE)
 		mobj->destscale = READFIXED(save_p);
+	else
+		mobj->destscale = mobj->scale;
 	if (diff2 & MD2_SCALESPEED)
 		mobj->scalespeed = READFIXED(save_p);
+	else
+		mobj->scalespeed = FRACUNIT/12;
 	if (diff2 & MD2_CUSVAL)
 		mobj->cusval = READINT32(save_p);
 	if (diff2 & MD2_CVMEM)
@@ -2817,10 +2845,16 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 		mobj->renderflags = READUINT32(save_p);
 	if (diff2 & MD2_BLENDMODE)
 		mobj->blendmode = READINT32(save_p);
+	else
+		mobj->blendmode = AST_TRANSLUCENT;
 	if (diff2 & MD2_SPRITEXSCALE)
 		mobj->spritexscale = READFIXED(save_p);
+	else
+		mobj->spritexscale = FRACUNIT;
 	if (diff2 & MD2_SPRITEYSCALE)
 		mobj->spriteyscale = READFIXED(save_p);
+	else
+		mobj->spriteyscale = FRACUNIT;
 	if (diff2 & MD2_SPRITEXOFFSET)
 		mobj->spritexoffset = READFIXED(save_p);
 	if (diff2 & MD2_SPRITEYOFFSET)
diff --git a/src/p_setup.h b/src/p_setup.h
index 34de9c93da1c4a91f7c46cc25af8107136df530e..5d13ae7d429d94d5c1fed55b08ff275fe3d3b353 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -80,6 +80,7 @@ typedef struct
 	UINT8 *picture;
 #ifdef HWRENDER
 	void *mipmap;
+	void *mippic;
 #endif
 } levelflat_t;
 
diff --git a/src/p_user.c b/src/p_user.c
index a70dceb8b12ed25fbcc5777544455013f9e0c488..02592053d051eef2d72cc34de5a4f3cb4237b1fa 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -190,7 +190,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move)
 boolean P_AutoPause(void)
 {
 	// Don't pause even on menu-up or focus-lost in netgames or record attack
-	if (netgame || modeattacking || gamestate == GS_TITLESCREEN)
+	if (netgame || modeattacking || gamestate == GS_TITLESCREEN || (marathonmode && gamestate == GS_INTERMISSION))
 		return false;
 
 	return (menuactive || ( window_notinfocus && cv_pauseifunfocused.value ));
@@ -4499,7 +4499,7 @@ void P_DoJump(player_t *player, boolean soundandstate)
 	if (twodlevel || (player->mo->flags2 & MF2_TWOD))
 		factor += player->jumpfactor / 10;
 
-	if (player->charflags & SF_MULTIABILITY && player->charability == CA_DOUBLEJUMP)
+	if (player->charflags & SF_MULTIABILITY && player->charability == CA_DOUBLEJUMP && (player->actionspd >> FRACBITS) != -1)
 		factor -= max(0, player->secondjump * player->jumpfactor / ((player->actionspd >> FRACBITS) + 1)); // Reduce the jump height each time
 
 	//if (maptol & TOL_NIGHTS)
@@ -4880,22 +4880,28 @@ void P_DoBubbleBounce(player_t *player)
 //
 void P_DoAbilityBounce(player_t *player, boolean changemomz)
 {
-	fixed_t prevmomz;
 	if (player->mo->state-states == S_PLAY_BOUNCE_LANDING)
 		return;
+
 	if (changemomz)
 	{
-		fixed_t minmomz;
-		prevmomz = player->mo->momz;
+		fixed_t prevmomz = player->mo->momz, minmomz;
+
 		if (P_MobjFlip(player->mo)*prevmomz < 0)
 			prevmomz = 0;
 		else if (player->mo->eflags & MFE_UNDERWATER)
 			prevmomz /= 2;
+
 		P_DoJump(player, false);
 		player->pflags &= ~(PF_STARTJUMP|PF_JUMPED);
 		minmomz = FixedMul(player->mo->momz, 3*FRACUNIT/2);
-		player->mo->momz = max(minmomz, (minmomz + prevmomz)/2);
+
+		if (player->mo->eflags & MFE_VERTICALFLIP) // Use "min" or "max" depending on if the player is flipped
+			player->mo->momz = min(minmomz, (minmomz + prevmomz)/2);
+		else
+			player->mo->momz = max(minmomz, (minmomz + prevmomz)/2);
 	}
+
 	S_StartSound(player->mo, sfx_boingf);
 	P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE_LANDING);
 	player->pflags |= PF_BOUNCING|PF_THOKKED;
@@ -5924,7 +5930,7 @@ static void P_3dMovement(player_t *player)
 	player->rmomy = player->mo->momy - player->cmomy;
 
 	// Calculates player's speed based on distance-of-a-line formula
-	player->speed = R_PointToDist2(0, 0, player->rmomx, player->rmomy);
+	player->speed = P_AproxDistance(player->rmomx, player->rmomy);
 
 	// Monster Iestyn - 04-11-13
 	// Quadrants are stupid, excessive and broken, let's do this a much simpler way!
diff --git a/src/r_draw.c b/src/r_draw.c
index d9ea942a2f22b301bdbd1762e0635f31ba085d6e..c3d4efae39a89c296bef158ca488ea1c138c487e 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -134,9 +134,43 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
 #define DEFAULT_STARTTRANSCOLOR 96
 #define NUM_PALETTE_ENTRIES 256
 
-static UINT8** translationtablecache[MAXSKINS + 7] = {NULL};
+static UINT8 **translationtablecache[MAXSKINS + 7] = {NULL};
 UINT8 skincolor_modified[MAXSKINCOLORS];
 
+static INT32 SkinToCacheIndex(INT32 skinnum)
+{
+	switch (skinnum)
+	{
+		case TC_DEFAULT:    return DEFAULT_TT_CACHE_INDEX;
+		case TC_BOSS:       return BOSS_TT_CACHE_INDEX;
+		case TC_METALSONIC: return METALSONIC_TT_CACHE_INDEX;
+		case TC_ALLWHITE:   return ALLWHITE_TT_CACHE_INDEX;
+		case TC_RAINBOW:    return RAINBOW_TT_CACHE_INDEX;
+		case TC_BLINK:      return BLINK_TT_CACHE_INDEX;
+		case TC_DASHMODE:   return DASHMODE_TT_CACHE_INDEX;
+		     default:       break;
+	}
+
+	return skinnum;
+}
+
+static INT32 CacheIndexToSkin(INT32 ttc)
+{
+	switch (ttc)
+	{
+		case DEFAULT_TT_CACHE_INDEX:    return TC_DEFAULT;
+		case BOSS_TT_CACHE_INDEX:       return TC_BOSS;
+		case METALSONIC_TT_CACHE_INDEX: return TC_METALSONIC;
+		case ALLWHITE_TT_CACHE_INDEX:   return TC_ALLWHITE;
+		case RAINBOW_TT_CACHE_INDEX:    return TC_RAINBOW;
+		case BLINK_TT_CACHE_INDEX:      return TC_BLINK;
+		case DASHMODE_TT_CACHE_INDEX:   return TC_DASHMODE;
+		     default:                   break;
+	}
+
+	return ttc;
+}
+
 CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
 
 #define TRANSTAB_AMTMUL10 (256.0f / 10.0f)
@@ -308,7 +342,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
 /**	\brief	Generates a translation colormap.
 
 	\param	dest_colormap	colormap to populate
-	\param	skinnum		number of skin, TC_DEFAULT or TC_BOSS
+	\param	skinnum		skin number, or a translation mode
 	\param	color		translation color
 
 	\return	void
@@ -412,6 +446,9 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 	if (color >= numskincolors)
 		I_Error("Invalid skin color #%hu.", (UINT16)color);
 
+	if (skinnum < 0 && skinnum > TC_DEFAULT)
+		I_Error("Invalid translation colormap index %d.", skinnum);
+
 	starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR;
 
 	if (starttranscolor >= NUM_PALETTE_ENTRIES)
@@ -448,25 +485,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags)
 {
 	UINT8* ret;
-	INT32 skintableindex;
+	INT32 skintableindex = SkinToCacheIndex(skinnum); // Adjust if we want the default colormap
 	INT32 i;
 
-	// Adjust if we want the default colormap
-	switch (skinnum)
-	{
-		case TC_DEFAULT:    skintableindex = DEFAULT_TT_CACHE_INDEX; break;
-		case TC_BOSS:       skintableindex = BOSS_TT_CACHE_INDEX; break;
-		case TC_METALSONIC: skintableindex = METALSONIC_TT_CACHE_INDEX; break;
-		case TC_ALLWHITE:   skintableindex = ALLWHITE_TT_CACHE_INDEX; break;
-		case TC_RAINBOW:    skintableindex = RAINBOW_TT_CACHE_INDEX; break;
-		case TC_BLINK:      skintableindex = BLINK_TT_CACHE_INDEX; break;
-		case TC_DASHMODE:   skintableindex = DASHMODE_TT_CACHE_INDEX; break;
-		     default:       skintableindex = skinnum; break;
-	}
-
 	if (flags & GTC_CACHE)
 	{
-
 		// Allocate table for skin if necessary
 		if (!translationtablecache[skintableindex])
 			translationtablecache[skintableindex] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL);
@@ -479,7 +502,8 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags
 		{
 			for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++)
 				if (translationtablecache[i] && translationtablecache[i][color])
-					R_GenerateTranslationColormap(translationtablecache[i][color], i>=MAXSKINS ? MAXSKINS-i-1 : i, color);
+					R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToSkin(i), color);
+
 			skincolor_modified[color] = false;
 		}
 	}
diff --git a/src/r_segs.c b/src/r_segs.c
index c79071e9b53afff41f19ad2cc167e9ae534931b8..a6772f9646af9451e4cdeb2f2cdb9f7b4bdd2749 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -1649,23 +1649,26 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		// left
 		temp = xtoviewangle[start]+viewangle;
 
+#define FIXED_TO_DOUBLE(x) (((double)(x)) / ((double)FRACUNIT))
+#define DOUBLE_TO_FIXED(x) (fixed_t)((x) * ((double)FRACUNIT))
+
 		{
 			// Both lines can be written in slope-intercept form, so figure out line intersection
-			float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
-			///TODO: convert to FPU
+			double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
+			///TODO: convert to fixed point
 
-			a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y);
-			b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x);
-			c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y);
+			a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y);
+			b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x);
+			c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y);
 
-			a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT));
-			b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT));
-			c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy);
+			a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT));
+			b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT));
+			c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy);
 
 			det = a1*b2 - a2*b1;
 
-			ds_p->leftpos.x = segleft.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det);
-			ds_p->leftpos.y = segleft.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det);
+			ds_p->leftpos.x = segleft.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det);
+			ds_p->leftpos.y = segleft.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det);
 		}
 
 		// right
@@ -1673,22 +1676,26 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 		{
 			// Both lines can be written in slope-intercept form, so figure out line intersection
-			float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
-			///TODO: convert to FPU
+			double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
+			///TODO: convert to fixed point
 
-			a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y);
-			b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x);
-			c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y);
+			a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y);
+			b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x);
+			c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y);
 
-			a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT));
-			b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT));
-			c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy);
+			a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT));
+			b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT));
+			c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy);
 
 			det = a1*b2 - a2*b1;
 
-			ds_p->rightpos.x = segright.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det);
-			ds_p->rightpos.y = segright.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det);
+			ds_p->rightpos.x = segright.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det);
+			ds_p->rightpos.y = segright.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det);
 		}
+
+#undef FIXED_TO_DOUBLE
+#undef DOUBLE_TO_FIXED
+
 	}
 
 
diff --git a/src/r_things.c b/src/r_things.c
index 30bf15f85379baacbb96bb102179f022f683bacc..14eed9cf25638af355c66320404c0e06c0f79988 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -796,7 +796,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
 	INT32 pwidth;
 	fixed_t frac;
 	patch_t *patch = vis->patch;
-	fixed_t this_scale = vis->mobj->scale;
+	fixed_t this_scale = vis->thingscale;
 	INT32 x1, x2;
 	INT64 overflow_test;
 
@@ -1332,6 +1332,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
 
 	shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000
 	shadow->scale = FixedMul(yscale, shadowyscale);
+	shadow->thingscale = thing->scale;
 	shadow->sector = vis->sector;
 	shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS);
 	shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS);
@@ -1423,7 +1424,7 @@ static void R_ProjectSprite(mobj_t *thing)
 
 	fixed_t sheartan = 0;
 	fixed_t shadowscale = FRACUNIT;
-	fixed_t basetx; // drop shadows
+	fixed_t basetx, basetz; // drop shadows
 
 	boolean shadowdraw, shadoweffects, shadowskew;
 	boolean splat = R_ThingIsFloorSprite(thing);
@@ -1453,7 +1454,7 @@ static void R_ProjectSprite(mobj_t *thing)
 	tr_x = thing->x - viewx;
 	tr_y = thing->y - viewy;
 
-	tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
+	basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
 
 	// thing is behind view plane?
 	if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later
@@ -1975,6 +1976,7 @@ static void R_ProjectSprite(mobj_t *thing)
 
 	vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000
 	vis->scale = FixedMul(spriteyscale, yscale); //<<detailshift;
+	vis->thingscale = oldthing->scale;
 
 	vis->spritexscale = spritexscale;
 	vis->spriteyscale = spriteyscale;
@@ -2052,7 +2054,7 @@ static void R_ProjectSprite(mobj_t *thing)
 		R_SplitSprite(vis);
 
 	if (oldthing->shadowscale && cv_shadow.value)
-		R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, tz);
+		R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz);
 
 	// Debug
 	++objectsdrawn;
diff --git a/src/r_things.h b/src/r_things.h
index f960089a114aef9821588b003f69ffd32dd9be6b..708b6c24cd1f287d64368c91754f77a1703a42c4 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -155,7 +155,8 @@ typedef struct vissprite_s
 	fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors
 
 	fixed_t startfrac; // horizontal position of x1
-	fixed_t scale;
+	fixed_t xscale, scale; // projected horizontal and vertical scales
+	fixed_t thingscale; // the object's scale
 	fixed_t sortscale; // sortscale only differs from scale for paper sprites, floor sprites, and MF2_LINKDRAW
 	fixed_t sortsplat; // the sortscale from behind the floor sprite
 	fixed_t scalestep; // only for paper sprites, 0 otherwise
@@ -183,8 +184,6 @@ typedef struct vissprite_s
 
 	extracolormap_t *extra_colormap; // global colormaps
 
-	fixed_t xscale;
-
 	// Precalculated top and bottom screen coords for the sprite.
 	fixed_t thingheight; // The actual height of the thing (for 3D floors)
 	sector_t *sector; // The sector containing the thing.
diff --git a/src/screen.c b/src/screen.c
index 9d36eee39cb1da8c2ce14e5fc1392344a9dbefc9..744523dab0552c3212e74c15f9362f8d9c1fae78 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -217,7 +217,7 @@ void SCR_SetMode(void)
 
 	// Set the video mode in the video interface.
 	if (setmodeneeded)
-		VID_SetMode(--setmodeneeded);
+		VID_SetMode(setmodeneeded - 1);
 
 	V_SetPalette(0);
 
diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c
index 3985086626c4d17f157a63668627d210737d1546..96e3d7d6926ef23771c8dcf489b4d8d2a16c0a1c 100644
--- a/src/sdl/hwsym_sdl.c
+++ b/src/sdl/hwsym_sdl.c
@@ -90,7 +90,6 @@ void *hwSym(const char *funcName,void *handle)
 	GETFUNC(ReadRect);
 	GETFUNC(GClipRect);
 	GETFUNC(ClearMipMapCache);
-	GETFUNC(ClearCacheList);
 	GETFUNC(SetSpecialState);
 	GETFUNC(GetTextureUsed);
 	GETFUNC(DrawModel);
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index d2c819c37093ffbeaa6156f6561d2ffb7db9df50..a0dd6e1da707a1e521f53623d2de42b01e6f7dfa 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -137,6 +137,12 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #include <errno.h>
 #endif
 
+#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
+#include <execinfo.h>
+#include <time.h>
+#define UNIXBACKTRACE
+#endif
+
 // Locations for searching the srb2.pk3
 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
 #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2"
@@ -238,6 +244,71 @@ SDL_bool framebuffer = SDL_FALSE;
 
 UINT8 keyboard_started = false;
 
+#ifdef UNIXBACKTRACE
+#define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string)
+#define CRASHLOG_WRITE(string) if (fd != -1) write(fd, string, strlen(string))
+#define CRASHLOG_STDERR_WRITE(string) \
+	if (fd != -1)\
+		write(fd, string, strlen(string));\
+	I_OutputMsg("%s", string)
+
+static void write_backtrace(INT32 signal)
+{
+	int fd = -1;
+	size_t size;
+	time_t rawtime;
+	struct tm timeinfo;
+
+	enum { BT_SIZE = 1024, STR_SIZE = 32 };
+	void *array[BT_SIZE];
+	char timestr[STR_SIZE];
+
+	const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n";
+	const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr.
+
+	fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
+
+	if (fd == -1)
+		I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n");
+
+	// Get the current time as a string.
+	time(&rawtime);
+	localtime_r(&rawtime, &timeinfo);
+	strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo);
+
+	CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator
+
+	CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs.
+	CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message
+	STDERR_WRITE(error2); // Tell the user where the crash log is.
+
+	// Tell the log when we crashed.
+	CRASHLOG_WRITE("Time of crash: ");
+	CRASHLOG_WRITE(timestr);
+	CRASHLOG_WRITE("\n");
+
+	// Give the crash log the cause and a nice 'Backtrace:' thing
+	// The signal is given to the user when the parent process sees we crashed.
+	CRASHLOG_WRITE("Cause: ");
+	CRASHLOG_WRITE(strsignal(signal));
+	CRASHLOG_WRITE("\n"); // Newline for the signal name
+
+	CRASHLOG_STDERR_WRITE("\nBacktrace:\n");
+
+	// Flood the output and log with the backtrace
+	size = backtrace(array, BT_SIZE);
+	backtrace_symbols_fd(array, size, fd);
+	backtrace_symbols_fd(array, size, STDERR_FILENO);
+
+	CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :)
+
+	close(fd);
+}
+#undef STDERR_WRITE
+#undef CRASHLOG_WRITE
+#undef CRASHLOG_STDERR_WRITE
+#endif // UNIXBACKTRACE
+
 static void I_ReportSignal(int num, int coredumped)
 {
 	//static char msg[] = "oh no! back to reality!\r\n";
@@ -297,6 +368,9 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
 {
 	D_QuitNetGame(); // Fix server freezes
 	CL_AbortDownloadResume();
+#ifdef UNIXBACKTRACE
+	write_backtrace(num);
+#endif
 	I_ReportSignal(num, 0);
 	I_ShutdownSystem();
 	signal(num, SIG_DFL);               //default signal action
@@ -687,6 +761,28 @@ static void I_RegisterSignals (void)
 #endif
 }
 
+#ifdef NEWSIGNALHANDLER
+static void signal_handler_child(INT32 num)
+{
+#ifdef UNIXBACKTRACE
+	write_backtrace(num);
+#endif
+
+	signal(num, SIG_DFL);               //default signal action
+	raise(num);
+}
+
+static void I_RegisterChildSignals(void)
+{
+	// If these defines don't exist,
+	// then compilation would have failed above us...
+	signal(SIGILL , signal_handler_child);
+	signal(SIGSEGV , signal_handler_child);
+	signal(SIGABRT , signal_handler_child);
+	signal(SIGFPE , signal_handler_child);
+}
+#endif
+
 //
 //I_OutputMsg
 //
@@ -2123,6 +2219,7 @@ static void I_Fork(void)
 			newsignalhandler_Warn("fork()");
 			break;
 		case 0:
+			I_RegisterChildSignals();
 			break;
 		default:
 			if (logstream)
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 5ebff87001f962d8a63bc5a8a6c5b6535176523d..0ed10463fc79734e004abdfdb960d56630168abf 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -1862,7 +1862,6 @@ void VID_StartupOpenGL(void)
 		HWD.pfnReadRect         = hwSym("ReadRect",NULL);
 		HWD.pfnGClipRect        = hwSym("GClipRect",NULL);
 		HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL);
-		HWD.pfnClearCacheList   = hwSym("ClearCacheList",NULL);
 		HWD.pfnSetSpecialState  = hwSym("SetSpecialState",NULL);
 		HWD.pfnSetPalette       = hwSym("SetPalette",NULL);
 		HWD.pfnGetTextureUsed   = hwSym("GetTextureUsed",NULL);
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 5cae480772f31e232213c4467eb4928f5db65d6f..412a21ea0098415b46eea3565630f6f9ce99bfe8 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -1298,7 +1298,7 @@ boolean I_PlaySong(boolean looping)
 	if (gme)
 	{
 		gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
-#if GME_VERSION >= 0x000603
+#if defined (GME_VERSION) && GME_VERSION >= 0x000603
 		if (looping)
 			gme_set_autoload_playback_limit(gme, 0);
 #endif        
diff --git a/src/w_wad.c b/src/w_wad.c
index 6566800c03ce0594898d4bb50026b5bc55eb3f67..91c8331f7f39135a817a0412b43cdfb308f76577 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -821,7 +821,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
 	}
 
 	if (important && !mainfile)
-		G_SetGameModified(true);
+		//G_SetGameModified(true);
+		modifiedgame = true; // avoid savemoddata being set to false
 
 	//
 	// link wad file to search files
@@ -1682,26 +1683,12 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 
 		// read the lump in full
 		W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
+		ptr = lumpdata;
 
 #ifndef NO_PNG_LUMPS
-		// lump is a png so convert it
 		if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
-		{
-			size_t newlen;
-			void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &newlen, 0);
-			ptr = Z_Malloc(newlen, PU_STATIC, NULL);
-			M_Memcpy(ptr, converted, newlen);
-			Z_Free(converted);
-			len = newlen;
-		}
-		else // just copy it into the patch cache
+			ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
 #endif
-		{
-			ptr = Z_Malloc(len, PU_STATIC, NULL);
-			M_Memcpy(ptr, lumpdata, len);
-		}
-
-		Z_Free(lumpdata);
 
 		dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
 		Patch_Create(ptr, len, dest);
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index d942d8cd406ad55b85b0e1bdd768631588f244ec..4743cec34b2e6af738caeec60d7c179e58ec14d1 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -111,7 +111,6 @@ static loadfunc_t hwdFuncTable[] = {
 	{"ReadRect@24",         &hwdriver.pfnReadRect},
 	{"GClipRect@20",        &hwdriver.pfnGClipRect},
 	{"ClearMipMapCache@0",  &hwdriver.pfnClearMipMapCache},
-	{"ClearCacheList@0",    &hwdriver.pfnClearCacheList},
 	{"SetSpecialState@8",   &hwdriver.pfnSetSpecialState},
 	{"DrawModel@16",        &hwdriver.pfnDrawModel},
 	{"SetTransform@4",      &hwdriver.pfnSetTransform},
@@ -145,7 +144,6 @@ static loadfunc_t hwdFuncTable[] = {
 	{"ReadRect",            &hwdriver.pfnReadRect},
 	{"GClipRect",           &hwdriver.pfnGClipRect},
 	{"ClearMipMapCache",    &hwdriver.pfnClearMipMapCache},
-	{"ClearCacheList",      &hwdriver.pfnClearCacheList},
 	{"SetSpecialState",     &hwdriver.pfnSetSpecialState},
 	{"DrawModel",           &hwdriver.pfnDrawModel},
 	{"SetTransform",        &hwdriver.pfnSetTransform},
diff --git a/src/z_zone.h b/src/z_zone.h
index e80a45e7fb4f2ed6223868fc78d18649e75ab4ad..7b58be8f3fce52c01642e20bee0de00c1795bece 100644
--- a/src/z_zone.h
+++ b/src/z_zone.h
@@ -68,8 +68,7 @@ enum
 	PU_HWRCACHE_UNLOCKED     = 102, // 'unlocked' PU_HWRCACHE memory:
 									// 'second-level' cache for graphics
                                     // stored in hardware format and downloaded as needed
-	PU_HWRPATCHINFO_UNLOCKED    = 103, // 'unlocked' PU_HWRPATCHINFO memory
-	PU_HWRMODELTEXTURE_UNLOCKED = 104, // 'unlocked' PU_HWRMODELTEXTURE memory
+	PU_HWRMODELTEXTURE_UNLOCKED = 103, // 'unlocked' PU_HWRMODELTEXTURE memory
 };
 
 //