From 928c6acf4b7fa009599c508fa2337578c2b8f3ca Mon Sep 17 00:00:00 2001
From: yoshibot <qwertyitis@gmail.com>
Date: Tue, 17 May 2016 22:56:49 -0500
Subject: [PATCH 01/12] Simplify OS X bundle resource discovery, fix a sigsegv

---
 src/sdl/macosx/mac_resources.c | 28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/src/sdl/macosx/mac_resources.c b/src/sdl/macosx/mac_resources.c
index dacc8014..706c5e7f 100644
--- a/src/sdl/macosx/mac_resources.c
+++ b/src/sdl/macosx/mac_resources.c
@@ -9,23 +9,21 @@ void OSX_GetResourcesPath(char * buffer)
     mainBundle = CFBundleGetMainBundle();
     if (mainBundle)
     {
+        const int BUF_SIZE = 256; // because we somehow always know that
+
         CFURLRef appUrlRef = CFBundleCopyBundleURL(mainBundle);
         CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
-        CFStringRef resources = CFStringCreateWithCString(kCFAllocatorMalloc, "/Contents/Resources", kCFStringEncodingASCII);
-        const void* rawarray[2] = {macPath, resources};
-        CFArrayRef array = CFArrayCreate(kCFAllocatorMalloc, rawarray, 2, NULL);
-        CFStringRef separator = CFStringCreateWithCString(kCFAllocatorMalloc, "", kCFStringEncodingASCII);
-        CFStringRef fullPath = CFStringCreateByCombiningStrings(kCFAllocatorMalloc, array, separator);
-        const char * path = CFStringGetCStringPtr(fullPath, kCFStringEncodingASCII);
-        strcpy(buffer, path);
-        CFRelease(fullPath);
-        path = NULL;
-        CFRelease(array);
-        CFRelease(resources);
+
+        const char* rawPath = CFStringGetCStringPtr(macPath, kCFStringEncodingASCII);
+ 
+        if (CFStringGetLength(macPath) + strlen("/Contents/Resources") < BUF_SIZE)
+        {
+            strcpy(buffer, rawPath);
+            strcat(buffer, "/Contents/Resources");
+        }
+
         CFRelease(macPath);
         CFRelease(appUrlRef);
-        //CFRelease(mainBundle);
-        CFRelease(separator);
     }
-
-}
\ No newline at end of file
+    CFRelease(mainBundle);
+}

From df89563882d8eb7e2bc848944a0b76853d086970 Mon Sep 17 00:00:00 2001
From: yoshibot <qwertyitis@gmail.com>
Date: Wed, 18 May 2016 19:14:53 -0500
Subject: [PATCH 02/12] Add a way to build OS X binaries (not .app) through
 Makefiles

---
 src/Makefile        | 14 ++++++++++++++
 src/Makefile.cfg    | 11 +++++++++++
 src/doomtype.h      |  2 +-
 src/sdl/MakeNIX.cfg |  9 +++++++++
 4 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/src/Makefile b/src/Makefile
index 701cdcfb..deee3854 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -189,6 +189,10 @@ ifdef FREEBSD
 UNIXCOMMON=1
 endif
 
+ifdef MACOSX
+UNIXCOMMON=1
+endif
+
 ifdef NDS
 NOPNG=1
 NONET=1
@@ -588,11 +592,16 @@ ifndef WINDOWSHELL
 	-$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt
 endif
 endif
+
+# i dont know why, but the os x executable absolutely hates
+# being touched by objcopy. so let's not do it
+ifndef MACOSX
 ifndef PSP
 	$(OBJCOPY) $(BIN)/$(EXENAME) $(BIN)/$(DBGNAME)
 	$(OBJCOPY) --strip-debug $(BIN)/$(EXENAME)
 	-$(OBJCOPY) --add-gnu-debuglink=$(BIN)/$(DBGNAME) $(BIN)/$(EXENAME)
 endif
+endif
 ifndef NOUPX
 	-$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME)
 endif
@@ -737,6 +746,11 @@ $(OBJDIR)/%.o: %.c
 $(OBJDIR)/%.o: $(INTERFACE)/%.c
 	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
 
+ifdef MACOSX
+$(OBJDIR)/%.o: sdl/macosx/%.c
+	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
+endif
+
 $(OBJDIR)/%.o: hardware/%.c
 	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
 
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index fa8896a7..7acb4559 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -403,6 +403,17 @@ else
 	WINDRES=windres
 endif
 
+# because Apple screws with us on this
+# need to get bintools from homebrew
+# need to get gzip from homebrew (it's in dupes)
+ifdef MACOSX
+	CC=clang
+	CXX=clang
+	OBJCOPY=gobjcopy
+	OBJDUMP=gobjdump
+	GZIP=/usr/local/bin/gzip
+endif
+
 OBJDUMP_OPTS?=--wide --source --line-numbers
 LD=$(CC)
 
diff --git a/src/doomtype.h b/src/doomtype.h
index d833176f..6bc2c573 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -92,7 +92,7 @@ typedef long ssize_t;
 #endif
 
 #ifdef __APPLE_CC__
-#define DIRECTFULLSCREEN
+#define DIRECTFULLSCREEN 1
 #define DEBUG_LOG
 #define NOIPX
 #endif
diff --git a/src/sdl/MakeNIX.cfg b/src/sdl/MakeNIX.cfg
index f5c9b207..1a0b5421 100644
--- a/src/sdl/MakeNIX.cfg
+++ b/src/sdl/MakeNIX.cfg
@@ -56,6 +56,15 @@ ifdef FREEBSD
 	LIBS+=-lipx -lkvm
 endif
 
+#
+#here is Mac OS X
+#
+ifdef MACOSX
+	OBJS+=$(OBJDIR)/mac_resources.o
+	OBJS+=$(OBJDIR)/mac_alert.o
+	LIBS+=-framework CoreFoundation
+endif
+
 #
 #here is GP2x (arm-gp2x-linux)
 #

From bb90c8366a4cd16ead76b96819065acf332ca3d3 Mon Sep 17 00:00:00 2001
From: yoshibot <qwertyitis@gmail.com>
Date: Wed, 18 May 2016 22:13:53 -0500
Subject: [PATCH 03/12] Fixed bugs in OS X alert code and simplified; added
 more NULL checks in OS X resource code

---
 src/sdl/macosx/mac_alert.c     | 37 +++++++++++++++++++++++++---------
 src/sdl/macosx/mac_resources.c | 18 ++++++++++++-----
 2 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/src/sdl/macosx/mac_alert.c b/src/sdl/macosx/mac_alert.c
index 455e3650..2a139041 100644
--- a/src/sdl/macosx/mac_alert.c
+++ b/src/sdl/macosx/mac_alert.c
@@ -25,19 +25,38 @@
 #include "mac_alert.h"
 #include <CoreFoundation/CoreFoundation.h>
 
+#define CFSTRINGIFY(x) CFStringCreateWithCString(NULL, x, kCFStringEncodingASCII)
+
 int MacShowAlert(const char *title, const char *message, const char *button1, const char *button2, const char *button3)
 {
 	CFOptionFlags results;
 
-	CFUserNotificationDisplayAlert(0,
-	 kCFUserNotificationStopAlertLevel | kCFUserNotificationNoDefaultButtonFlag,
-	 NULL, NULL, NULL,
-	 CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII),
-	 CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII),
-	 button1 != NULL ? CFStringCreateWithCString(NULL, button1, kCFStringEncodingASCII) : NULL,
-	 button2 != NULL ? CFStringCreateWithCString(NULL, button2, kCFStringEncodingASCII) : NULL,
-	 button3 != NULL ? CFStringCreateWithCString(NULL, button3, kCFStringEncodingASCII) : NULL,
-	 &results);
+        CFStringRef cf_title   = CFSTRINGIFY(title);
+        CFStringRef cf_message = CFSTRINGIFY(message);
+        CFStringRef cf_button1 = NULL;
+        CFStringRef cf_button2 = NULL;
+        CFStringRef cf_button3 = NULL;
+
+        if (button1 != NULL)
+            cf_button1 = CFSTRINGIFY(button1);
+        if (button2 != NULL)
+            cf_button2 = CFSTRINGIFY(button2);
+        if (button3 != NULL)
+            cf_button3 = CFSTRINGIFY(button3);
+
+        CFOptionFlags alert_flags = kCFUserNotificationStopAlertLevel | kCFUserNotificationNoDefaultButtonFlag;
+
+	CFUserNotificationDisplayAlert(0, alert_flags, NULL, NULL, NULL, cf_title, cf_message,
+                                       cf_button1, cf_button2, cf_button3, &results);
+
+        if (cf_button1 != NULL)
+           CFRelease(cf_button1);
+        if (cf_button2 != NULL)
+           CFRelease(cf_button2);
+        if (cf_button3 != NULL)
+           CFRelease(cf_button3);
+        CFRelease(cf_message);
+        CFRelease(cf_title);
 
 	return (int)results;
 }
diff --git a/src/sdl/macosx/mac_resources.c b/src/sdl/macosx/mac_resources.c
index 706c5e7f..d67b9258 100644
--- a/src/sdl/macosx/mac_resources.c
+++ b/src/sdl/macosx/mac_resources.c
@@ -12,11 +12,20 @@ void OSX_GetResourcesPath(char * buffer)
         const int BUF_SIZE = 256; // because we somehow always know that
 
         CFURLRef appUrlRef = CFBundleCopyBundleURL(mainBundle);
-        CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
+        CFStringRef macPath;
+        if (appUrlRef != NULL)
+            macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
+        else
+            macPath = NULL;
 
-        const char* rawPath = CFStringGetCStringPtr(macPath, kCFStringEncodingASCII);
- 
-        if (CFStringGetLength(macPath) + strlen("/Contents/Resources") < BUF_SIZE)
+        const char* rawPath;
+
+        if (macPath != NULL)
+            rawPath = CFStringGetCStringPtr(macPath, kCFStringEncodingASCII);
+        else
+            rawPath = NULL;
+
+        if (rawPath != NULL && (CFStringGetLength(macPath) + strlen("/Contents/Resources") < BUF_SIZE))
         {
             strcpy(buffer, rawPath);
             strcat(buffer, "/Contents/Resources");
@@ -25,5 +34,4 @@ void OSX_GetResourcesPath(char * buffer)
         CFRelease(macPath);
         CFRelease(appUrlRef);
     }
-    CFRelease(mainBundle);
 }

From 8fbc0d7f69cd683bd23253522fcf696fd10674e8 Mon Sep 17 00:00:00 2001
From: yoshibot <qwertyitis@gmail.com>
Date: Wed, 18 May 2016 23:52:06 -0500
Subject: [PATCH 04/12] remove bogus homebrew gzip; objdump allowed to fail in
 that way

---
 src/Makefile     | 3 +--
 src/Makefile.cfg | 2 --
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index deee3854..cbd362ae 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -593,8 +593,7 @@ ifndef WINDOWSHELL
 endif
 endif
 
-# i dont know why, but the os x executable absolutely hates
-# being touched by objcopy. so let's not do it
+# mac os x lsdlsrb2 does not like objcopy
 ifndef MACOSX
 ifndef PSP
 	$(OBJCOPY) $(BIN)/$(EXENAME) $(BIN)/$(DBGNAME)
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index 7acb4559..2e67474c 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -405,13 +405,11 @@ endif
 
 # because Apple screws with us on this
 # need to get bintools from homebrew
-# need to get gzip from homebrew (it's in dupes)
 ifdef MACOSX
 	CC=clang
 	CXX=clang
 	OBJCOPY=gobjcopy
 	OBJDUMP=gobjdump
-	GZIP=/usr/local/bin/gzip
 endif
 
 OBJDUMP_OPTS?=--wide --source --line-numbers

From f94d3a1fb0a407f31c35854f370883a6bceaf361 Mon Sep 17 00:00:00 2001
From: Hank Brannock <furiousfox@gmail.com>
Date: Sun, 22 May 2016 22:38:16 -0400
Subject: [PATCH 05/12] The code in i_net.c doesn't actually seem to be used in
 SRB2. I was able to compile a build without it, and hosting and joining
 netgames worked just fine (well, as fine as they can with the current state
 of the netcode...).

Do we really need to keep it around? If not, I say get rid of it. It seems like useless clutter that is just going to confuse people who are trying to understand the source code.
---
 src/Makefile.cfg                     |   1 -
 src/d_net.c                          |   2 +-
 src/i_net.h                          |   3 -
 src/sdl/Srb2SDL-vc10.vcxproj         |   1 -
 src/sdl/Srb2SDL-vc10.vcxproj.filters |   3 -
 src/sdl/i_net.c                      | 442 ---------------------------
 src/sdl12/i_net.c                    | 442 ---------------------------
 7 files changed, 1 insertion(+), 893 deletions(-)
 delete mode 100644 src/sdl/i_net.c
 delete mode 100644 src/sdl12/i_net.c

diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index fa8896a7..5fdea847 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -207,7 +207,6 @@ endif
 
 #determine the interface directory (where you put all i_*.c)
 i_cdmus_o=$(OBJDIR)/i_cdmus.o
-i_net_o=$(OBJDIR)/i_net.o
 i_system_o=$(OBJDIR)/i_system.o
 i_sound_o=$(OBJDIR)/i_sound.o
 i_main_o=$(OBJDIR)/i_main.o
diff --git a/src/d_net.c b/src/d_net.c
index 03e126b5..4b6678c2 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -1080,7 +1080,7 @@ boolean D_CheckNetGame(void)
 	multiplayer = false;
 
 	// only dos version with external driver will return true
-	netgame = I_InitNetwork();
+	netgame = false; // I_InitNetwork() is no longer used
 	if (!netgame && !I_NetOpenSocket)
 	{
 		D_SetDoomcom();
diff --git a/src/i_net.h b/src/i_net.h
index e378f572..ae469701 100644
--- a/src/i_net.h
+++ b/src/i_net.h
@@ -148,7 +148,4 @@ extern const char *(*I_GetBanMask) (size_t ban);
 extern boolean (*I_SetBanAddress) (const char *address,const char *mask);
 extern boolean *bannednode;
 
-/// \brief Called by D_SRB2Main to be defined by extern network driver
-boolean I_InitNetwork(void);
-
 #endif
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 452b47ed..5dc01cfd 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -398,7 +398,6 @@
     </ClCompile>
     <ClCompile Include="i_cdmus.c" />
     <ClCompile Include="i_main.c" />
-    <ClCompile Include="i_net.c" />
     <ClCompile Include="i_system.c" />
     <ClCompile Include="i_ttf.c" />
     <ClCompile Include="i_video.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 9396b482..b037140e 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -837,9 +837,6 @@
     <ClCompile Include="i_main.c">
       <Filter>SDLApp</Filter>
     </ClCompile>
-    <ClCompile Include="i_net.c">
-      <Filter>SDLApp</Filter>
-    </ClCompile>
     <ClCompile Include="i_system.c">
       <Filter>SDLApp</Filter>
     </ClCompile>
diff --git a/src/sdl/i_net.c b/src/sdl/i_net.c
deleted file mode 100644
index ee4a34c1..00000000
--- a/src/sdl/i_net.c
+++ /dev/null
@@ -1,442 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief SDL network interface
-
-#include "../doomdef.h"
-
-#include "../i_system.h"
-#include "../d_event.h"
-#include "../d_net.h"
-#include "../m_argv.h"
-
-#include "../doomstat.h"
-
-#include "../i_net.h"
-
-#include "../z_zone.h"
-
-#include "../i_tcp.h"
-
-#ifdef HAVE_SDL
-
-#ifdef HAVE_SDLNET
-
-#include "SDL_net.h"
-
-#define MAXBANS 20
-
-static IPaddress clientaddress[MAXNETNODES+1];
-static IPaddress banned[MAXBANS];
-
-static UDPpacket mypacket;
-static UDPsocket mysocket = NULL;
-static SDLNet_SocketSet myset = NULL;
-
-static size_t numbans = 0;
-static boolean NET_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
-static boolean init_SDLNet_driver = false;
-
-static const char *NET_AddrToStr(IPaddress* sk)
-{
-	static char s[22]; // 255.255.255.255:65535
-	strcpy(s, SDLNet_ResolveIP(sk));
-	if (sk->port != 0) strcat(s, va(":%d", sk->port));
-	return s;
-}
-
-static const char *NET_GetNodeAddress(INT32 node)
-{
-	if (!nodeconnected[node])
-		return NULL;
-	return NET_AddrToStr(&clientaddress[node]);
-}
-
-static const char *NET_GetBanAddress(size_t ban)
-{
-	if (ban > numbans)
-		return NULL;
-	return NET_AddrToStr(&banned[ban]);
-}
-
-static boolean NET_cmpaddr(IPaddress* a, IPaddress* b)
-{
-	return (a->host == b->host && (b->port == 0 || a->port == b->port));
-}
-
-static boolean NET_CanGet(void)
-{
-	return myset?(SDLNet_CheckSockets(myset,0)  == 1):false;
-}
-
-static void NET_Get(void)
-{
-	INT32 mystatus;
-	INT32 newnode;
-	mypacket.len = MAXPACKETLENGTH;
-	if (!NET_CanGet())
-	{
-		doomcom->remotenode = -1; // no packet
-		return;
-	}
-	mystatus = SDLNet_UDP_Recv(mysocket,&mypacket);
-	if (mystatus != -1)
-	{
-		if (mypacket.channel != -1)
-		{
-			doomcom->remotenode = mypacket.channel+1; // good packet from a game player
-			doomcom->datalength = mypacket.len;
-			return;
-		}
-		newnode = SDLNet_UDP_Bind(mysocket,-1,&mypacket.address);
-		if (newnode != -1)
-		{
-			size_t i;
-			newnode++;
-			M_Memcpy(&clientaddress[newnode], &mypacket.address, sizeof (IPaddress));
-			DEBFILE(va("New node detected: node:%d address:%s\n", newnode,
-					NET_GetNodeAddress(newnode)));
-			doomcom->remotenode = newnode; // good packet from a game player
-			doomcom->datalength = mypacket.len;
-			for (i = 0; i < numbans; i++)
-			{
-				if (NET_cmpaddr(&mypacket.address, &banned[i]))
-				{
-					DEBFILE("This dude has been banned\n");
-					NET_bannednode[newnode] = true;
-					break;
-				}
-			}
-			if (i == numbans)
-				NET_bannednode[newnode] = false;
-			return;
-		}
-		else
-			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-	}
-	else if (mystatus == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-	}
-
-	DEBFILE("New node detected: No more free slots\n");
-	doomcom->remotenode = -1; // no packet
-}
-
-#if 0
-static boolean NET_CanSend(void)
-{
-	return true;
-}
-#endif
-
-static void NET_Send(void)
-{
-	if (!doomcom->remotenode)
-		return;
-	mypacket.len = doomcom->datalength;
-	if (SDLNet_UDP_Send(mysocket,doomcom->remotenode-1,&mypacket) == 0)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-	}
-}
-
-static void NET_FreeNodenum(INT32 numnode)
-{
-	// can't disconnect from self :)
-	if (!numnode)
-		return;
-
-	DEBFILE(va("Free node %d (%s)\n", numnode, NET_GetNodeAddress(numnode)));
-
-	SDLNet_UDP_Unbind(mysocket,numnode-1);
-
-	memset(&clientaddress[numnode], 0, sizeof (IPaddress));
-}
-
-static UDPsocket NET_Socket(void)
-{
-	UDPsocket temp = NULL;
-	Uint16 portnum = 0;
-	IPaddress tempip = {INADDR_BROADCAST,0};
-	//Hurdler: I'd like to put a server and a client on the same computer
-	//Logan: Me too
-	//BP: in fact for client we can use any free port we want i have read
-	//    in some doc that connect in udp can do it for us...
-	//Alam: where?
-	if (M_CheckParm("-clientport"))
-	{
-		if (!M_IsNextParm())
-			I_Error("syntax: -clientport <portnum>");
-		portnum = atoi(M_GetNextParm());
-	}
-	else
-		portnum = sock_port;
-	temp = SDLNet_UDP_Open(portnum);
-	if (!temp)
-	{
-			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return NULL;
-	}
-	if (SDLNet_UDP_Bind(temp,BROADCASTADDR-1,&tempip) == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		SDLNet_UDP_Close(temp);
-		return NULL;
-	}
-	clientaddress[BROADCASTADDR].port = sock_port;
-	clientaddress[BROADCASTADDR].host = INADDR_BROADCAST;
-
-	doomcom->extratics = 1; // internet is very high ping
-
-	return temp;
-}
-
-static void I_ShutdownSDLNetDriver(void)
-{
-	if (myset) SDLNet_FreeSocketSet(myset);
-	myset = NULL;
-	SDLNet_Quit();
-	init_SDLNet_driver = false;
-}
-
-static void I_InitSDLNetDriver(void)
-{
-	if (init_SDLNet_driver)
-		I_ShutdownSDLNetDriver();
-	if (SDLNet_Init() == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return; // No good!
-	}
-	D_SetDoomcom();
-	mypacket.data = doomcom->data;
-	init_SDLNet_driver = true;
-}
-
-static void NET_CloseSocket(void)
-{
-	if (mysocket)
-		SDLNet_UDP_Close(mysocket);
-	mysocket = NULL;
-}
-
-static SINT8 NET_NetMakeNodewPort(const char *hostname, const char *port)
-{
-	INT32 newnode;
-	UINT16 portnum = sock_port;
-	IPaddress hostnameIP;
-
-	// retrieve portnum from address!
-	if (port && !port[0])
-		portnum = atoi(port);
-
-	if (SDLNet_ResolveHost(&hostnameIP,hostname,portnum) == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return -1;
-	}
-	newnode = SDLNet_UDP_Bind(mysocket,-1,&hostnameIP);
-	if (newnode == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return newnode;
-	}
-	newnode++;
-	M_Memcpy(&clientaddress[newnode],&hostnameIP,sizeof (IPaddress));
-	return (SINT8)newnode;
-}
-
-
-static boolean NET_OpenSocket(void)
-{
-	memset(clientaddress, 0, sizeof (clientaddress));
-
-	//I_OutputMsg("SDL_Net Code starting up\n");
-
-	I_NetSend = NET_Send;
-	I_NetGet = NET_Get;
-	I_NetCloseSocket = NET_CloseSocket;
-	I_NetFreeNodenum = NET_FreeNodenum;
-	I_NetMakeNodewPort = NET_NetMakeNodewPort;
-
-	//I_NetCanSend = NET_CanSend;
-
-	// build the socket but close it first
-	NET_CloseSocket();
-	mysocket = NET_Socket();
-
-	if (!mysocket)
-		return false;
-
-	// for select
-	myset = SDLNet_AllocSocketSet(1);
-	if (!myset)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return false;
-	}
-	if (SDLNet_UDP_AddSocket(myset,mysocket) == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return false;
-	}
-	return true;
-}
-
-static boolean NET_Ban(INT32 node)
-{
-	if (numbans == MAXBANS)
-		return false;
-
-	M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (IPaddress));
-	banned[numbans].port = 0;
-	numbans++;
-	return true;
-}
-
-static boolean NET_SetBanAddress(const char *address, const char *mask)
-{
-	(void)mask;
-	if (bans == MAXBANS)
-		return false;
-
-	if (SDLNet_ResolveHost(&banned[numbans], address, 0) == -1)
-		return false;
-	numbans++;
-	return true;
-}
-
-static void NET_ClearBans(void)
-{
-	numbans = 0;
-}
-#endif
-
-//
-// I_InitNetwork
-// Only required for DOS, so this is more a dummy
-//
-boolean I_InitNetwork(void)
-{
-#ifdef HAVE_SDLNET
-	char serverhostname[255];
-	boolean ret = false;
-	SDL_version SDLcompiled;
-	const SDL_version *SDLlinked = SDLNet_Linked_Version();
-	SDL_NET_VERSION(&SDLcompiled)
-	I_OutputMsg("Compiled for SDL_Net version: %d.%d.%d\n",
-                        SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch);
-	I_OutputMsg("Linked with SDL_Net version: %d.%d.%d\n",
-                        SDLlinked->major, SDLlinked->minor, SDLlinked->patch);
-	//if (!M_CheckParm ("-sdlnet"))
-	//	return false;
-	// initilize the driver
-	I_InitSDLNetDriver();
-	I_AddExitFunc(I_ShutdownSDLNetDriver);
-	if (!init_SDLNet_driver)
-		return false;
-
-	if (M_CheckParm("-udpport"))
-	{
-		if (M_IsNextParm())
-			sock_port = (UINT16)atoi(M_GetNextParm());
-		else
-			sock_port = 0;
-	}
-
-	// parse network game options,
-	if (M_CheckParm("-server") || dedicated)
-	{
-		server = true;
-
-		// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
-		// to connect before starting.
-		// If no number is specified here, the server starts with 1 client, and others can join
-		// in-game.
-		// Since Boris has implemented join in-game, there is no actual need for specifying a
-		// particular number here.
-		// FIXME: for dedicated server, numnodes needs to be set to 0 upon start
-/*		if (M_IsNextParm())
-			doomcom->numnodes = (INT16)atoi(M_GetNextParm());
-		else */if (dedicated)
-			doomcom->numnodes = 0;
-		else
-			doomcom->numnodes = 1;
-
-		if (doomcom->numnodes < 0)
-			doomcom->numnodes = 0;
-		if (doomcom->numnodes > MAXNETNODES)
-			doomcom->numnodes = MAXNETNODES;
-
-		// server
-		servernode = 0;
-		// FIXME:
-		// ??? and now ?
-		// server on a big modem ??? 4*isdn
-		net_bandwidth = 16000;
-		hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
-
-		ret = true;
-	}
-	else if (M_CheckParm("-connect"))
-	{
-		if (M_IsNextParm())
-			strcpy(serverhostname, M_GetNextParm());
-		else
-			serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
-
-		// server address only in ip
-		if (serverhostname[0])
-		{
-			COM_BufAddText("connect \"");
-			COM_BufAddText(serverhostname);
-			COM_BufAddText("\"\n");
-
-			// probably modem
-			hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
-		}
-		else
-		{
-			// so we're on a LAN
-			COM_BufAddText("connect any\n");
-
-			net_bandwidth = 800000;
-			hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
-		}
-	}
-
-	mypacket.maxlen = hardware_MAXPACKETLENGTH;
-	I_NetOpenSocket = NET_OpenSocket;
-	I_Ban = NET_Ban;
-	I_ClearBans = NET_ClearBans;
-	I_GetNodeAddress = NET_GetNodeAddress;
-	I_GetBenAddress = NET_GetBenAddress;
-	I_SetBanAddress = NET_SetBanAddress;
-	bannednode = NET_bannednode;
-
-	return ret;
-#else
-	if ( M_CheckParm ("-net") )
-	{
-		I_Error("-net not supported, use -server and -connect\n"
-			"see docs for more\n");
-	}
-	return false;
-#endif
-}
-#endif
diff --git a/src/sdl12/i_net.c b/src/sdl12/i_net.c
deleted file mode 100644
index ee4a34c1..00000000
--- a/src/sdl12/i_net.c
+++ /dev/null
@@ -1,442 +0,0 @@
-// Emacs style mode select   -*- C++ -*-
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//-----------------------------------------------------------------------------
-/// \file
-/// \brief SDL network interface
-
-#include "../doomdef.h"
-
-#include "../i_system.h"
-#include "../d_event.h"
-#include "../d_net.h"
-#include "../m_argv.h"
-
-#include "../doomstat.h"
-
-#include "../i_net.h"
-
-#include "../z_zone.h"
-
-#include "../i_tcp.h"
-
-#ifdef HAVE_SDL
-
-#ifdef HAVE_SDLNET
-
-#include "SDL_net.h"
-
-#define MAXBANS 20
-
-static IPaddress clientaddress[MAXNETNODES+1];
-static IPaddress banned[MAXBANS];
-
-static UDPpacket mypacket;
-static UDPsocket mysocket = NULL;
-static SDLNet_SocketSet myset = NULL;
-
-static size_t numbans = 0;
-static boolean NET_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
-static boolean init_SDLNet_driver = false;
-
-static const char *NET_AddrToStr(IPaddress* sk)
-{
-	static char s[22]; // 255.255.255.255:65535
-	strcpy(s, SDLNet_ResolveIP(sk));
-	if (sk->port != 0) strcat(s, va(":%d", sk->port));
-	return s;
-}
-
-static const char *NET_GetNodeAddress(INT32 node)
-{
-	if (!nodeconnected[node])
-		return NULL;
-	return NET_AddrToStr(&clientaddress[node]);
-}
-
-static const char *NET_GetBanAddress(size_t ban)
-{
-	if (ban > numbans)
-		return NULL;
-	return NET_AddrToStr(&banned[ban]);
-}
-
-static boolean NET_cmpaddr(IPaddress* a, IPaddress* b)
-{
-	return (a->host == b->host && (b->port == 0 || a->port == b->port));
-}
-
-static boolean NET_CanGet(void)
-{
-	return myset?(SDLNet_CheckSockets(myset,0)  == 1):false;
-}
-
-static void NET_Get(void)
-{
-	INT32 mystatus;
-	INT32 newnode;
-	mypacket.len = MAXPACKETLENGTH;
-	if (!NET_CanGet())
-	{
-		doomcom->remotenode = -1; // no packet
-		return;
-	}
-	mystatus = SDLNet_UDP_Recv(mysocket,&mypacket);
-	if (mystatus != -1)
-	{
-		if (mypacket.channel != -1)
-		{
-			doomcom->remotenode = mypacket.channel+1; // good packet from a game player
-			doomcom->datalength = mypacket.len;
-			return;
-		}
-		newnode = SDLNet_UDP_Bind(mysocket,-1,&mypacket.address);
-		if (newnode != -1)
-		{
-			size_t i;
-			newnode++;
-			M_Memcpy(&clientaddress[newnode], &mypacket.address, sizeof (IPaddress));
-			DEBFILE(va("New node detected: node:%d address:%s\n", newnode,
-					NET_GetNodeAddress(newnode)));
-			doomcom->remotenode = newnode; // good packet from a game player
-			doomcom->datalength = mypacket.len;
-			for (i = 0; i < numbans; i++)
-			{
-				if (NET_cmpaddr(&mypacket.address, &banned[i]))
-				{
-					DEBFILE("This dude has been banned\n");
-					NET_bannednode[newnode] = true;
-					break;
-				}
-			}
-			if (i == numbans)
-				NET_bannednode[newnode] = false;
-			return;
-		}
-		else
-			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-	}
-	else if (mystatus == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-	}
-
-	DEBFILE("New node detected: No more free slots\n");
-	doomcom->remotenode = -1; // no packet
-}
-
-#if 0
-static boolean NET_CanSend(void)
-{
-	return true;
-}
-#endif
-
-static void NET_Send(void)
-{
-	if (!doomcom->remotenode)
-		return;
-	mypacket.len = doomcom->datalength;
-	if (SDLNet_UDP_Send(mysocket,doomcom->remotenode-1,&mypacket) == 0)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-	}
-}
-
-static void NET_FreeNodenum(INT32 numnode)
-{
-	// can't disconnect from self :)
-	if (!numnode)
-		return;
-
-	DEBFILE(va("Free node %d (%s)\n", numnode, NET_GetNodeAddress(numnode)));
-
-	SDLNet_UDP_Unbind(mysocket,numnode-1);
-
-	memset(&clientaddress[numnode], 0, sizeof (IPaddress));
-}
-
-static UDPsocket NET_Socket(void)
-{
-	UDPsocket temp = NULL;
-	Uint16 portnum = 0;
-	IPaddress tempip = {INADDR_BROADCAST,0};
-	//Hurdler: I'd like to put a server and a client on the same computer
-	//Logan: Me too
-	//BP: in fact for client we can use any free port we want i have read
-	//    in some doc that connect in udp can do it for us...
-	//Alam: where?
-	if (M_CheckParm("-clientport"))
-	{
-		if (!M_IsNextParm())
-			I_Error("syntax: -clientport <portnum>");
-		portnum = atoi(M_GetNextParm());
-	}
-	else
-		portnum = sock_port;
-	temp = SDLNet_UDP_Open(portnum);
-	if (!temp)
-	{
-			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return NULL;
-	}
-	if (SDLNet_UDP_Bind(temp,BROADCASTADDR-1,&tempip) == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		SDLNet_UDP_Close(temp);
-		return NULL;
-	}
-	clientaddress[BROADCASTADDR].port = sock_port;
-	clientaddress[BROADCASTADDR].host = INADDR_BROADCAST;
-
-	doomcom->extratics = 1; // internet is very high ping
-
-	return temp;
-}
-
-static void I_ShutdownSDLNetDriver(void)
-{
-	if (myset) SDLNet_FreeSocketSet(myset);
-	myset = NULL;
-	SDLNet_Quit();
-	init_SDLNet_driver = false;
-}
-
-static void I_InitSDLNetDriver(void)
-{
-	if (init_SDLNet_driver)
-		I_ShutdownSDLNetDriver();
-	if (SDLNet_Init() == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return; // No good!
-	}
-	D_SetDoomcom();
-	mypacket.data = doomcom->data;
-	init_SDLNet_driver = true;
-}
-
-static void NET_CloseSocket(void)
-{
-	if (mysocket)
-		SDLNet_UDP_Close(mysocket);
-	mysocket = NULL;
-}
-
-static SINT8 NET_NetMakeNodewPort(const char *hostname, const char *port)
-{
-	INT32 newnode;
-	UINT16 portnum = sock_port;
-	IPaddress hostnameIP;
-
-	// retrieve portnum from address!
-	if (port && !port[0])
-		portnum = atoi(port);
-
-	if (SDLNet_ResolveHost(&hostnameIP,hostname,portnum) == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return -1;
-	}
-	newnode = SDLNet_UDP_Bind(mysocket,-1,&hostnameIP);
-	if (newnode == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return newnode;
-	}
-	newnode++;
-	M_Memcpy(&clientaddress[newnode],&hostnameIP,sizeof (IPaddress));
-	return (SINT8)newnode;
-}
-
-
-static boolean NET_OpenSocket(void)
-{
-	memset(clientaddress, 0, sizeof (clientaddress));
-
-	//I_OutputMsg("SDL_Net Code starting up\n");
-
-	I_NetSend = NET_Send;
-	I_NetGet = NET_Get;
-	I_NetCloseSocket = NET_CloseSocket;
-	I_NetFreeNodenum = NET_FreeNodenum;
-	I_NetMakeNodewPort = NET_NetMakeNodewPort;
-
-	//I_NetCanSend = NET_CanSend;
-
-	// build the socket but close it first
-	NET_CloseSocket();
-	mysocket = NET_Socket();
-
-	if (!mysocket)
-		return false;
-
-	// for select
-	myset = SDLNet_AllocSocketSet(1);
-	if (!myset)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return false;
-	}
-	if (SDLNet_UDP_AddSocket(myset,mysocket) == -1)
-	{
-		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
-		return false;
-	}
-	return true;
-}
-
-static boolean NET_Ban(INT32 node)
-{
-	if (numbans == MAXBANS)
-		return false;
-
-	M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (IPaddress));
-	banned[numbans].port = 0;
-	numbans++;
-	return true;
-}
-
-static boolean NET_SetBanAddress(const char *address, const char *mask)
-{
-	(void)mask;
-	if (bans == MAXBANS)
-		return false;
-
-	if (SDLNet_ResolveHost(&banned[numbans], address, 0) == -1)
-		return false;
-	numbans++;
-	return true;
-}
-
-static void NET_ClearBans(void)
-{
-	numbans = 0;
-}
-#endif
-
-//
-// I_InitNetwork
-// Only required for DOS, so this is more a dummy
-//
-boolean I_InitNetwork(void)
-{
-#ifdef HAVE_SDLNET
-	char serverhostname[255];
-	boolean ret = false;
-	SDL_version SDLcompiled;
-	const SDL_version *SDLlinked = SDLNet_Linked_Version();
-	SDL_NET_VERSION(&SDLcompiled)
-	I_OutputMsg("Compiled for SDL_Net version: %d.%d.%d\n",
-                        SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch);
-	I_OutputMsg("Linked with SDL_Net version: %d.%d.%d\n",
-                        SDLlinked->major, SDLlinked->minor, SDLlinked->patch);
-	//if (!M_CheckParm ("-sdlnet"))
-	//	return false;
-	// initilize the driver
-	I_InitSDLNetDriver();
-	I_AddExitFunc(I_ShutdownSDLNetDriver);
-	if (!init_SDLNet_driver)
-		return false;
-
-	if (M_CheckParm("-udpport"))
-	{
-		if (M_IsNextParm())
-			sock_port = (UINT16)atoi(M_GetNextParm());
-		else
-			sock_port = 0;
-	}
-
-	// parse network game options,
-	if (M_CheckParm("-server") || dedicated)
-	{
-		server = true;
-
-		// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
-		// to connect before starting.
-		// If no number is specified here, the server starts with 1 client, and others can join
-		// in-game.
-		// Since Boris has implemented join in-game, there is no actual need for specifying a
-		// particular number here.
-		// FIXME: for dedicated server, numnodes needs to be set to 0 upon start
-/*		if (M_IsNextParm())
-			doomcom->numnodes = (INT16)atoi(M_GetNextParm());
-		else */if (dedicated)
-			doomcom->numnodes = 0;
-		else
-			doomcom->numnodes = 1;
-
-		if (doomcom->numnodes < 0)
-			doomcom->numnodes = 0;
-		if (doomcom->numnodes > MAXNETNODES)
-			doomcom->numnodes = MAXNETNODES;
-
-		// server
-		servernode = 0;
-		// FIXME:
-		// ??? and now ?
-		// server on a big modem ??? 4*isdn
-		net_bandwidth = 16000;
-		hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
-
-		ret = true;
-	}
-	else if (M_CheckParm("-connect"))
-	{
-		if (M_IsNextParm())
-			strcpy(serverhostname, M_GetNextParm());
-		else
-			serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
-
-		// server address only in ip
-		if (serverhostname[0])
-		{
-			COM_BufAddText("connect \"");
-			COM_BufAddText(serverhostname);
-			COM_BufAddText("\"\n");
-
-			// probably modem
-			hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
-		}
-		else
-		{
-			// so we're on a LAN
-			COM_BufAddText("connect any\n");
-
-			net_bandwidth = 800000;
-			hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
-		}
-	}
-
-	mypacket.maxlen = hardware_MAXPACKETLENGTH;
-	I_NetOpenSocket = NET_OpenSocket;
-	I_Ban = NET_Ban;
-	I_ClearBans = NET_ClearBans;
-	I_GetNodeAddress = NET_GetNodeAddress;
-	I_GetBenAddress = NET_GetBenAddress;
-	I_SetBanAddress = NET_SetBanAddress;
-	bannednode = NET_bannednode;
-
-	return ret;
-#else
-	if ( M_CheckParm ("-net") )
-	{
-		I_Error("-net not supported, use -server and -connect\n"
-			"see docs for more\n");
-	}
-	return false;
-#endif
-}
-#endif

From 69f556d40a281caa75697bf2241703418c763648 Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Sun, 5 Jun 2016 21:29:40 +0100
Subject: [PATCH 06/12] Split AA trees code from m_misc.c/.h into m_aatree.c/.h

Also updated any relevant project files that I can think of to include the new files, as well as the makefile of course. Some of the other project files haven't been touched in years so I'll leave those alone ...unless someone objects
---
 SRB2.cbp                               |  33 +++++
 src/CMakeLists.txt                     |   2 +
 src/Makefile                           |   1 +
 src/m_aatree.c                         | 167 +++++++++++++++++++++++++
 src/m_aatree.h                         |  31 +++++
 src/m_misc.c                           | 155 -----------------------
 src/m_misc.h                           |  13 --
 src/sdl/Srb2SDL-vc10.vcxproj           |   2 +
 src/sdl/Srb2SDL-vc10.vcxproj.filters   |   6 +
 src/w_wad.h                            |   4 +-
 src/win32/Srb2win-vc10.vcxproj         |   2 +
 src/win32/Srb2win-vc10.vcxproj.filters |   6 +
 12 files changed, 251 insertions(+), 171 deletions(-)
 create mode 100644 src/m_aatree.c
 create mode 100644 src/m_aatree.h

diff --git a/SRB2.cbp b/SRB2.cbp
index 43696ee2..99a71226 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -2815,6 +2815,39 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/m_aatree.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Native/SDL" />
+			<Option target="Release Native/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
+			<Option target="Debug Mingw/DirectX" />
+			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+			<Option target="Debug Linux/SDL" />
+			<Option target="Release Linux/SDL" />
+			<Option target="Debug Mingw64/SDL" />
+			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw64/DirectX" />
+			<Option target="Release Mingw64/DirectX" />
+		</Unit>
+		<Unit filename="src/m_aatree.h">
+			<Option target="Debug Native/SDL" />
+			<Option target="Release Native/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
+			<Option target="Debug Mingw/DirectX" />
+			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+			<Option target="Debug Linux/SDL" />
+			<Option target="Release Linux/SDL" />
+			<Option target="Debug Mingw64/SDL" />
+			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw64/DirectX" />
+			<Option target="Release Mingw64/DirectX" />
+		</Unit>
 		<Unit filename="src/m_anigif.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 035b4655..ba354c28 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SRB2_CORE_SOURCES
 	i_tcp.c
 	info.c
 	lzf.c
+	m_aatree.c
 	m_anigif.c
 	m_argv.c
 	m_bbox.c
@@ -83,6 +84,7 @@ set(SRB2_CORE_HEADERS
 	info.h
 	keys.h
 	lzf.h
+	m_aatree.h
 	m_anigif.h
 	m_argv.h
 	m_bbox.h
diff --git a/src/Makefile b/src/Makefile
index f7a8c1b8..02b136f3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -429,6 +429,7 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/hu_stuff.o \
 		$(OBJDIR)/y_inter.o  \
 		$(OBJDIR)/st_stuff.o \
+		$(OBJDIR)/m_aatree.o \
 		$(OBJDIR)/m_anigif.o \
 		$(OBJDIR)/m_argv.o   \
 		$(OBJDIR)/m_bbox.o   \
diff --git a/src/m_aatree.c b/src/m_aatree.c
new file mode 100644
index 00000000..6cb3a32c
--- /dev/null
+++ b/src/m_aatree.c
@@ -0,0 +1,167 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  m_aatree.h
+/// \brief AA trees code
+
+#include "m_aatree.h"
+#include "z_zone.h"
+
+// A partial implementation of AA trees,
+// according to the algorithms given on Wikipedia.
+// http://en.wikipedia.org/wiki/AA_tree
+
+typedef struct aatree_node_s
+{
+	INT32	level;
+	INT32	key;
+	void*	value;
+
+	struct aatree_node_s *left, *right;
+} aatree_node_t;
+
+struct aatree_s
+{
+	aatree_node_t	*root;
+	UINT32		flags;
+};
+
+aatree_t *M_AATreeAlloc(UINT32 flags)
+{
+	aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
+	aatree->root = NULL;
+	aatree->flags = flags;
+	return aatree;
+}
+
+static void M_AATreeFree_Node(aatree_node_t *node)
+{
+	if (node->left) M_AATreeFree_Node(node->left);
+	if (node->right) M_AATreeFree_Node(node->right);
+	Z_Free(node);
+}
+
+void M_AATreeFree(aatree_t *aatree)
+{
+	if (aatree->root)
+		M_AATreeFree_Node(aatree->root);
+
+	Z_Free(aatree);
+}
+
+static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
+{
+	if (node && node->left && node->left->level == node->level)
+	{
+		// Not allowed: horizontal left-link. Reverse the
+		// horizontal link and hook the orphan back in.
+		aatree_node_t *oldleft = node->left;
+		node->left = oldleft->right;
+		oldleft->right = node;
+
+		return oldleft;
+	}
+
+	// No change needed.
+	return node;
+}
+
+static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
+{
+	if (node && node->right && node->right->right && node->level == node->right->right->level)
+	{
+		// Not allowed: two consecutive horizontal right-links.
+		// The middle one becomes the new root at this point,
+		// with suitable adjustments below.
+
+		aatree_node_t *oldright = node->right;
+		node->right = oldright->left;
+		oldright->left = node;
+		oldright->level++;
+
+		return oldright;
+	}
+
+	// No change needed.
+	return node;
+}
+
+static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
+{
+	if (!node)
+	{
+		// Nothing here, so just add where we are
+
+		node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
+		node->level = 1;
+		node->key = key;
+		if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+		else node->value = value;
+		node->left = node->right = NULL;
+	}
+	else
+	{
+		if (key < node->key)
+			node->left = M_AATreeSet_Node(node->left, flags, key, value);
+		else if (key > node->key)
+			node->right = M_AATreeSet_Node(node->right, flags, key, value);
+		else
+		{
+			if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+			else node->value = value;
+		}
+
+		node = M_AATreeSkew(node);
+		node = M_AATreeSplit(node);
+	}
+
+	return node;
+}
+
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
+{
+	aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
+}
+
+// Caveat: we don't distinguish between nodes that don't exists
+// and nodes with value == NULL.
+static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
+{
+	if (node)
+	{
+		if (node->key == key)
+			return node->value;
+		else if(node->key < key)
+			return M_AATreeGet_Node(node->right, key);
+		else
+			return M_AATreeGet_Node(node->left, key);
+	}
+
+	return NULL;
+}
+
+void *M_AATreeGet(aatree_t *aatree, INT32 key)
+{
+	return M_AATreeGet_Node(aatree->root, key);
+}
+
+
+static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
+{
+	if (node->left) M_AATreeIterate_Node(node->left, callback);
+	callback(node->key, node->value);
+	if (node->right) M_AATreeIterate_Node(node->right, callback);
+}
+
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
+{
+	if (aatree->root)
+		M_AATreeIterate_Node(aatree->root, callback);
+}
diff --git a/src/m_aatree.h b/src/m_aatree.h
new file mode 100644
index 00000000..c9077b97
--- /dev/null
+++ b/src/m_aatree.h
@@ -0,0 +1,31 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  m_aatree.h
+/// \brief AA trees code
+
+#ifndef __M_AATREE__
+#define __M_AATREE__
+
+#include "doomtype.h"
+
+// Flags for AA trees.
+#define AATREE_ZUSER	1		// Treat values as z_zone-allocated blocks and set their user fields
+
+typedef struct aatree_s aatree_t;
+typedef void (*aatree_iter_t)(INT32 key, void *value);
+
+aatree_t *M_AATreeAlloc(UINT32 flags);
+void M_AATreeFree(aatree_t *aatree);
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
+void *M_AATreeGet(aatree_t *aatree, INT32 key);
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
+
+#endif
\ No newline at end of file
diff --git a/src/m_misc.c b/src/m_misc.c
index 64054d4f..457214e3 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2323,158 +2323,3 @@ void M_SetupMemcpy(void)
 	M_Memcpy = cpu_cpy;
 #endif
 }
-
-
-// A partial implementation of AA trees,
-// according to the algorithms given on Wikipedia.
-// http://en.wikipedia.org/wiki/AA_tree
-
-
-
-typedef struct aatree_node_s
-{
-	INT32	level;
-	INT32	key;
-	void*	value;
-
-	struct aatree_node_s *left, *right;
-} aatree_node_t;
-
-struct aatree_s
-{
-	aatree_node_t	*root;
-	UINT32		flags;
-};
-
-aatree_t *M_AATreeAlloc(UINT32 flags)
-{
-	aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
-	aatree->root = NULL;
-	aatree->flags = flags;
-	return aatree;
-}
-
-static void M_AATreeFree_Node(aatree_node_t *node)
-{
-	if (node->left) M_AATreeFree_Node(node->left);
-	if (node->right) M_AATreeFree_Node(node->right);
-	Z_Free(node);
-}
-
-void M_AATreeFree(aatree_t *aatree)
-{
-	if (aatree->root)
-		M_AATreeFree_Node(aatree->root);
-
-	Z_Free(aatree);
-}
-
-static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
-{
-	if (node && node->left && node->left->level == node->level)
-	{
-		// Not allowed: horizontal left-link. Reverse the
-		// horizontal link and hook the orphan back in.
-		aatree_node_t *oldleft = node->left;
-		node->left = oldleft->right;
-		oldleft->right = node;
-
-		return oldleft;
-	}
-
-	// No change needed.
-	return node;
-}
-
-static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
-{
-	if (node && node->right && node->right->right && node->level == node->right->right->level)
-	{
-		// Not allowed: two consecutive horizontal right-links.
-		// The middle one becomes the new root at this point,
-		// with suitable adjustments below.
-
-		aatree_node_t *oldright = node->right;
-		node->right = oldright->left;
-		oldright->left = node;
-		oldright->level++;
-
-		return oldright;
-	}
-
-	// No change needed.
-	return node;
-}
-
-static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
-{
-	if (!node)
-	{
-		// Nothing here, so just add where we are
-
-		node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
-		node->level = 1;
-		node->key = key;
-		if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
-		else node->value = value;
-		node->left = node->right = NULL;
-	}
-	else
-	{
-		if (key < node->key)
-			node->left = M_AATreeSet_Node(node->left, flags, key, value);
-		else if (key > node->key)
-			node->right = M_AATreeSet_Node(node->right, flags, key, value);
-		else
-		{
-			if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
-			else node->value = value;
-		}
-
-		node = M_AATreeSkew(node);
-		node = M_AATreeSplit(node);
-	}
-
-	return node;
-}
-
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
-{
-	aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
-}
-
-// Caveat: we don't distinguish between nodes that don't exists
-// and nodes with value == NULL.
-static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
-{
-	if (node)
-	{
-		if (node->key == key)
-			return node->value;
-		else if(node->key < key)
-			return M_AATreeGet_Node(node->right, key);
-		else
-			return M_AATreeGet_Node(node->left, key);
-	}
-
-	return NULL;
-}
-
-void *M_AATreeGet(aatree_t *aatree, INT32 key)
-{
-	return M_AATreeGet_Node(aatree->root, key);
-}
-
-
-static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
-{
-	if (node->left) M_AATreeIterate_Node(node->left, callback);
-	callback(node->key, node->value);
-	if (node->right) M_AATreeIterate_Node(node->right, callback);
-}
-
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
-{
-	if (aatree->root)
-		M_AATreeIterate_Node(aatree->root, callback);
-}
diff --git a/src/m_misc.h b/src/m_misc.h
index fa1f3b33..dc540dc1 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -96,19 +96,6 @@ void M_SetupMemcpy(void);
 // counting bits, for weapon ammo code, usually
 FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
 
-// Flags for AA trees.
-#define AATREE_ZUSER	1		// Treat values as z_zone-allocated blocks and set their user fields
-
-typedef struct aatree_s aatree_t;
-typedef void (*aatree_iter_t)(INT32 key, void *value);
-
-aatree_t *M_AATreeAlloc(UINT32 flags);
-void M_AATreeFree(aatree_t *aatree);
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
-void *M_AATreeGet(aatree_t *aatree, INT32 key);
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
-
-// Nasty cyclic dependency workaround. This must come after aatree stuff.
 #include "w_wad.h"
 extern char configfile[MAX_WADPATH];
 
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index d12a7efb..82019264 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -167,6 +167,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
     <ClInclude Include="..\m_bbox.h" />
@@ -308,6 +309,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
     <ClCompile Include="..\m_bbox.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 9396b482..d04007dd 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -294,6 +294,9 @@
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
+    <ClInclude Include="..\m_aatree.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\m_anigif.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
@@ -666,6 +669,9 @@
     <ClCompile Include="..\md5.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
+    <ClCompile Include="..\m_aatree.c">
+      <Filter>M_Misc</Filter>
+    </ClCompile>
     <ClCompile Include="..\m_anigif.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
diff --git a/src/w_wad.h b/src/w_wad.h
index c13f6933..b03e376b 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -54,10 +54,8 @@ typedef struct
 
 #define lumpcache_t void *
 
-// Annoying cyclic dependency workaround: this inlcusion must come after
-// the definition of MAX_WADPATH.
 #ifdef HWRENDER
-#include "m_misc.h"
+#include "m_aatree.h"
 #endif
 
 typedef struct wadfile_s
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 1e9d8241..064f75d7 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -145,6 +145,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
     <ClCompile Include="..\m_bbox.c" />
@@ -300,6 +301,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
     <ClInclude Include="..\m_bbox.h" />
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index 3f5b84bf..b2647ea1 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -255,6 +255,9 @@
     <ClCompile Include="..\lua_skinlib.c">
       <Filter>LUA</Filter>
     </ClCompile>
+    <ClCompile Include="..\m_aatree.c">
+      <Filter>M_Misc</Filter>
+    </ClCompile>
     <ClCompile Include="..\m_anigif.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
@@ -662,6 +665,9 @@
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
+    <ClInclude Include="..\m_aatree.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\m_anigif.h">
       <Filter>M_Misc</Filter>
     </ClInclude>

From 8426ce8d9cf48e0e87adc77698b439f5add38549 Mon Sep 17 00:00:00 2001
From: toasterbabe <rollerorbital@gmail.com>
Date: Thu, 30 Jun 2016 23:23:50 +0100
Subject: [PATCH 07/12] Minor change to fans and gas jets that makes them work
 on slopes.

- Now checks whether the player's top is below the bottom of the fan/gas jet, instead of its bottom. zdist calculation not affected.
- mo->standingslope is NULL'd so the player isn't launched off at a wacky angle. (I also did this for springs, since Prime mentioned it was a problem for them too.)
---
 src/p_map.c  | 14 +++++++++++---
 src/p_mobj.c |  6 +++---
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/src/p_map.c b/src/p_map.c
index 8621ba20..1f2d903e 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -129,6 +129,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		return false;
 	}
 
+#ifdef ESLOPE
+	object->standingslope = NULL; // Okay, now we can't return - no launching off at silly angles for you.
+#endif
+
 	object->eflags |= MFE_SPRUNG; // apply this flag asap!
 	spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
 
@@ -232,20 +236,24 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 	if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
 		return;
 
-	// is object below thruster's position? if not, calculate distance between their bottoms
+	// is object's top below thruster's position? if not, calculate distance between their bottoms
 	if (spring->eflags & MFE_VERTICALFLIP)
 	{
-		if (object->z + object->height > spring->z + spring->height)
+		if (object->z > spring->z + spring->height)
 			return;
 		zdist = (spring->z + spring->height) - (object->z + object->height);
 	}
 	else
 	{
-		if (object->z < spring->z)
+		if (object->z + object->height < spring->z)
 			return;
 		zdist = object->z - spring->z;
 	}
 
+#ifdef ESLOPE
+	object->standingslope = NULL; // No launching off at silly angles for you.
+#endif
+
 	switch (spring->type)
 	{
 		case MT_FAN: // fan
diff --git a/src/p_mobj.c b/src/p_mobj.c
index c6fed993..62dee0a6 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -2376,9 +2376,9 @@ static boolean P_ZMovement(mobj_t *mo)
 
 #ifdef ESLOPE
 		P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
-		if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) {
+		if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
+		{
 			mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
-
 			P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
 		}
 #endif
@@ -2532,7 +2532,7 @@ static boolean P_ZMovement(mobj_t *mo)
 			mom.z = tmfloorthing->momz;
 
 #ifdef ESLOPE
-		if (mo->standingslope) {
+		if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above.
 			P_QuantizeMomentumToSlope(&mom, mo->standingslope);
 		}
 #endif

From 4d0f0230de8ba6e53d376bc0eeba8d9477ca02bc Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Sun, 17 Jul 2016 17:36:37 +0100
Subject: [PATCH 08/12] Fix chasecam/awayviewmobj viewz offset to be consistent
 with non-skybox frame rendering

---
 src/r_main.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/r_main.c b/src/r_main.c
index 97d6876e..1ad125cd 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -919,9 +919,9 @@ void R_SkyboxFrame(player_t *player)
 				}
 			}
 			if (mh->skybox_scalez > 0)
-				viewz += player->awayviewmobj->z / mh->skybox_scalez;
+				viewz += (player->awayviewmobj->z + 20*FRACUNIT) / mh->skybox_scalez;
 			else if (mh->skybox_scalez < 0)
-				viewz += player->awayviewmobj->z * -mh->skybox_scalez;
+				viewz += (player->awayviewmobj->z + 20*FRACUNIT) * -mh->skybox_scalez;
 		}
 		else if (thiscam->chase)
 		{
@@ -966,9 +966,9 @@ void R_SkyboxFrame(player_t *player)
 				}
 			}
 			if (mh->skybox_scalez > 0)
-				viewz += thiscam->z / mh->skybox_scalez;
+				viewz += (thiscam->z + (thiscam->height>>1)) / mh->skybox_scalez;
 			else if (mh->skybox_scalez < 0)
-				viewz += thiscam->z * -mh->skybox_scalez;
+				viewz += (thiscam->z + (thiscam->height>>1)) * -mh->skybox_scalez;
 		}
 		else
 		{

From 9ad205f5ba8793949d9476d712875c88f650e838 Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Sun, 17 Jul 2016 22:33:37 +0100
Subject: [PATCH 09/12] R_DrawTiltedSplat_8 fix: apply colormapping AFTER
 checking the source pixel is cyan first

---
 src/r_draw8.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/r_draw8.c b/src/r_draw8.c
index c22cd236..ec80774a 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -913,9 +913,9 @@ void R_DrawTiltedSplat_8(void)
 		for (i = SPANSIZE-1; i >= 0; i--)
 		{
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 			if (val != TRANSPARENTPIXEL)
-				*dest = val;
+				*dest = colormap[val];
 			dest++;
 			u += stepu;
 			v += stepv;
@@ -931,9 +931,9 @@ void R_DrawTiltedSplat_8(void)
 			u = (INT64)(startu);
 			v = (INT64)(startv);
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 			if (val != TRANSPARENTPIXEL)
-				*dest = val;
+				*dest = colormap[val];
 		}
 		else
 		{
@@ -954,9 +954,9 @@ void R_DrawTiltedSplat_8(void)
 			for (; width != 0; width--)
 			{
 				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-				val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+				val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 				if (val != TRANSPARENTPIXEL)
-					*dest = val;
+					*dest = colormap[val];
 				dest++;
 				u += stepu;
 				v += stepv;

From 77a40e9016bade8091a9134e77040b8a8c07885d Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Sun, 17 Jul 2016 23:01:07 +0100
Subject: [PATCH 10/12] Slightly unrelated, but if R_DrawTranslucentSplat_8 is
 ever going to be used this is probably more efficient (also fixing early
 colormap application for the last part)

---
 src/r_draw8.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/r_draw8.c b/src/r_draw8.c
index ec80774a..9f5ab62c 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -874,9 +874,9 @@ void R_DrawTiltedSplat_8(void)
 
 		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
 
-		val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+		val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			*dest = val;
+			*dest = colormap[val];
 		dest++;
 		iz += ds_sz.x;
 		uz += ds_su.x;
@@ -1124,49 +1124,49 @@ void R_DrawTranslucentSplat_8 (void)
 		// need!
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[0] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[0])];
+			dest[0] = colormap[*(ds_transmap + (val << 8) + dest[0])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[1])];
+			dest[1] = colormap[*(ds_transmap + (val << 8) + dest[1])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[2])];
+			dest[2] = colormap[*(ds_transmap + (val << 8) + dest[2])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[3])];
+			dest[3] = colormap[*(ds_transmap + (val << 8) + dest[3])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[4])];
+			dest[4] = colormap[*(ds_transmap + (val << 8) + dest[4])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[5])];
+			dest[5] = colormap[*(ds_transmap + (val << 8) + dest[5])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[6])];
+			dest[6] = colormap[*(ds_transmap + (val << 8) + dest[6])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[7])];
+			dest[7] = colormap[*(ds_transmap + (val << 8) + dest[7])];
 		xposition += xstep;
 		yposition += ystep;
 
@@ -1175,9 +1175,9 @@ void R_DrawTranslucentSplat_8 (void)
 	}
 	while (count--)
 	{
-		val =colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]];
+		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			*dest = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dest)];
+			*dest = colormap[*(ds_transmap + (val << 8) + *dest)];
 
 		dest++;
 		xposition += xstep;

From 6ba568ac492347c441162adc51379f632936c751 Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Wed, 20 Jul 2016 15:11:36 +0100
Subject: [PATCH 11/12] Fixed typo of mine that lead to the ceiling part of
 GFZ2's tunnel section being rendered wrongly

---
 src/r_segs.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/r_segs.c b/src/r_segs.c
index 59b4f5db..cb78743b 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -1488,7 +1488,7 @@ static void R_RenderSegLoop (void)
 			{
 				// note: don't use min/max macros, since casting from INT32 to INT16 is involved here
 				if (markceiling)
-					ceilingclip[rw_x] = (yh >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
+					ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
 				if (markfloor)
 					floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
 			}
@@ -1523,10 +1523,10 @@ static void R_RenderSegLoop (void)
 						ceilingclip[rw_x] = -1;
 				}
 				else
-					ceilingclip[rw_x] = (yh >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
+					ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
 			}
 			else if (markceiling) // no top wall
-				ceilingclip[rw_x] = (yh >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
+				ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
 
 			if (bottomtexture)
 			{

From 1a0fcbd8dce3fef9b9aa006d144c1953f91597bd Mon Sep 17 00:00:00 2001
From: Alam Ed Arias <alam@srb2.org>
Date: Thu, 21 Jul 2016 14:42:00 -0400
Subject: [PATCH 12/12] Revert "Merge branch 'RemoveINetC' into 'master'"

This reverts commit 8607f5247c5ce8a2ee5e17df987a7a218f0a9a22, reversing
changes made to 11d76a6562de83366fae1583aeb483ff5acdcd0f.
---
 src/Makefile.cfg                     |   1 +
 src/d_net.c                          |   2 +-
 src/i_net.h                          |   3 +
 src/sdl/Srb2SDL-vc10.vcxproj         |   1 +
 src/sdl/Srb2SDL-vc10.vcxproj.filters |   3 +
 src/sdl/i_net.c                      | 442 +++++++++++++++++++++++++++
 src/sdl12/i_net.c                    | 442 +++++++++++++++++++++++++++
 7 files changed, 893 insertions(+), 1 deletion(-)
 create mode 100644 src/sdl/i_net.c
 create mode 100644 src/sdl12/i_net.c

diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index d6cb5411..347efa5e 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -210,6 +210,7 @@ endif
 
 #determine the interface directory (where you put all i_*.c)
 i_cdmus_o=$(OBJDIR)/i_cdmus.o
+i_net_o=$(OBJDIR)/i_net.o
 i_system_o=$(OBJDIR)/i_system.o
 i_sound_o=$(OBJDIR)/i_sound.o
 i_main_o=$(OBJDIR)/i_main.o
diff --git a/src/d_net.c b/src/d_net.c
index 4b6678c2..03e126b5 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -1080,7 +1080,7 @@ boolean D_CheckNetGame(void)
 	multiplayer = false;
 
 	// only dos version with external driver will return true
-	netgame = false; // I_InitNetwork() is no longer used
+	netgame = I_InitNetwork();
 	if (!netgame && !I_NetOpenSocket)
 	{
 		D_SetDoomcom();
diff --git a/src/i_net.h b/src/i_net.h
index ae469701..e378f572 100644
--- a/src/i_net.h
+++ b/src/i_net.h
@@ -148,4 +148,7 @@ extern const char *(*I_GetBanMask) (size_t ban);
 extern boolean (*I_SetBanAddress) (const char *address,const char *mask);
 extern boolean *bannednode;
 
+/// \brief Called by D_SRB2Main to be defined by extern network driver
+boolean I_InitNetwork(void);
+
 #endif
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 81cb7d54..d12a7efb 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -381,6 +381,7 @@
     </ClCompile>
     <ClCompile Include="i_cdmus.c" />
     <ClCompile Include="i_main.c" />
+    <ClCompile Include="i_net.c" />
     <ClCompile Include="i_system.c" />
     <ClCompile Include="i_ttf.c" />
     <ClCompile Include="i_video.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index b037140e..9396b482 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -837,6 +837,9 @@
     <ClCompile Include="i_main.c">
       <Filter>SDLApp</Filter>
     </ClCompile>
+    <ClCompile Include="i_net.c">
+      <Filter>SDLApp</Filter>
+    </ClCompile>
     <ClCompile Include="i_system.c">
       <Filter>SDLApp</Filter>
     </ClCompile>
diff --git a/src/sdl/i_net.c b/src/sdl/i_net.c
new file mode 100644
index 00000000..ee4a34c1
--- /dev/null
+++ b/src/sdl/i_net.c
@@ -0,0 +1,442 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//-----------------------------------------------------------------------------
+/// \file
+/// \brief SDL network interface
+
+#include "../doomdef.h"
+
+#include "../i_system.h"
+#include "../d_event.h"
+#include "../d_net.h"
+#include "../m_argv.h"
+
+#include "../doomstat.h"
+
+#include "../i_net.h"
+
+#include "../z_zone.h"
+
+#include "../i_tcp.h"
+
+#ifdef HAVE_SDL
+
+#ifdef HAVE_SDLNET
+
+#include "SDL_net.h"
+
+#define MAXBANS 20
+
+static IPaddress clientaddress[MAXNETNODES+1];
+static IPaddress banned[MAXBANS];
+
+static UDPpacket mypacket;
+static UDPsocket mysocket = NULL;
+static SDLNet_SocketSet myset = NULL;
+
+static size_t numbans = 0;
+static boolean NET_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
+static boolean init_SDLNet_driver = false;
+
+static const char *NET_AddrToStr(IPaddress* sk)
+{
+	static char s[22]; // 255.255.255.255:65535
+	strcpy(s, SDLNet_ResolveIP(sk));
+	if (sk->port != 0) strcat(s, va(":%d", sk->port));
+	return s;
+}
+
+static const char *NET_GetNodeAddress(INT32 node)
+{
+	if (!nodeconnected[node])
+		return NULL;
+	return NET_AddrToStr(&clientaddress[node]);
+}
+
+static const char *NET_GetBanAddress(size_t ban)
+{
+	if (ban > numbans)
+		return NULL;
+	return NET_AddrToStr(&banned[ban]);
+}
+
+static boolean NET_cmpaddr(IPaddress* a, IPaddress* b)
+{
+	return (a->host == b->host && (b->port == 0 || a->port == b->port));
+}
+
+static boolean NET_CanGet(void)
+{
+	return myset?(SDLNet_CheckSockets(myset,0)  == 1):false;
+}
+
+static void NET_Get(void)
+{
+	INT32 mystatus;
+	INT32 newnode;
+	mypacket.len = MAXPACKETLENGTH;
+	if (!NET_CanGet())
+	{
+		doomcom->remotenode = -1; // no packet
+		return;
+	}
+	mystatus = SDLNet_UDP_Recv(mysocket,&mypacket);
+	if (mystatus != -1)
+	{
+		if (mypacket.channel != -1)
+		{
+			doomcom->remotenode = mypacket.channel+1; // good packet from a game player
+			doomcom->datalength = mypacket.len;
+			return;
+		}
+		newnode = SDLNet_UDP_Bind(mysocket,-1,&mypacket.address);
+		if (newnode != -1)
+		{
+			size_t i;
+			newnode++;
+			M_Memcpy(&clientaddress[newnode], &mypacket.address, sizeof (IPaddress));
+			DEBFILE(va("New node detected: node:%d address:%s\n", newnode,
+					NET_GetNodeAddress(newnode)));
+			doomcom->remotenode = newnode; // good packet from a game player
+			doomcom->datalength = mypacket.len;
+			for (i = 0; i < numbans; i++)
+			{
+				if (NET_cmpaddr(&mypacket.address, &banned[i]))
+				{
+					DEBFILE("This dude has been banned\n");
+					NET_bannednode[newnode] = true;
+					break;
+				}
+			}
+			if (i == numbans)
+				NET_bannednode[newnode] = false;
+			return;
+		}
+		else
+			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+	}
+	else if (mystatus == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+	}
+
+	DEBFILE("New node detected: No more free slots\n");
+	doomcom->remotenode = -1; // no packet
+}
+
+#if 0
+static boolean NET_CanSend(void)
+{
+	return true;
+}
+#endif
+
+static void NET_Send(void)
+{
+	if (!doomcom->remotenode)
+		return;
+	mypacket.len = doomcom->datalength;
+	if (SDLNet_UDP_Send(mysocket,doomcom->remotenode-1,&mypacket) == 0)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+	}
+}
+
+static void NET_FreeNodenum(INT32 numnode)
+{
+	// can't disconnect from self :)
+	if (!numnode)
+		return;
+
+	DEBFILE(va("Free node %d (%s)\n", numnode, NET_GetNodeAddress(numnode)));
+
+	SDLNet_UDP_Unbind(mysocket,numnode-1);
+
+	memset(&clientaddress[numnode], 0, sizeof (IPaddress));
+}
+
+static UDPsocket NET_Socket(void)
+{
+	UDPsocket temp = NULL;
+	Uint16 portnum = 0;
+	IPaddress tempip = {INADDR_BROADCAST,0};
+	//Hurdler: I'd like to put a server and a client on the same computer
+	//Logan: Me too
+	//BP: in fact for client we can use any free port we want i have read
+	//    in some doc that connect in udp can do it for us...
+	//Alam: where?
+	if (M_CheckParm("-clientport"))
+	{
+		if (!M_IsNextParm())
+			I_Error("syntax: -clientport <portnum>");
+		portnum = atoi(M_GetNextParm());
+	}
+	else
+		portnum = sock_port;
+	temp = SDLNet_UDP_Open(portnum);
+	if (!temp)
+	{
+			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return NULL;
+	}
+	if (SDLNet_UDP_Bind(temp,BROADCASTADDR-1,&tempip) == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		SDLNet_UDP_Close(temp);
+		return NULL;
+	}
+	clientaddress[BROADCASTADDR].port = sock_port;
+	clientaddress[BROADCASTADDR].host = INADDR_BROADCAST;
+
+	doomcom->extratics = 1; // internet is very high ping
+
+	return temp;
+}
+
+static void I_ShutdownSDLNetDriver(void)
+{
+	if (myset) SDLNet_FreeSocketSet(myset);
+	myset = NULL;
+	SDLNet_Quit();
+	init_SDLNet_driver = false;
+}
+
+static void I_InitSDLNetDriver(void)
+{
+	if (init_SDLNet_driver)
+		I_ShutdownSDLNetDriver();
+	if (SDLNet_Init() == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return; // No good!
+	}
+	D_SetDoomcom();
+	mypacket.data = doomcom->data;
+	init_SDLNet_driver = true;
+}
+
+static void NET_CloseSocket(void)
+{
+	if (mysocket)
+		SDLNet_UDP_Close(mysocket);
+	mysocket = NULL;
+}
+
+static SINT8 NET_NetMakeNodewPort(const char *hostname, const char *port)
+{
+	INT32 newnode;
+	UINT16 portnum = sock_port;
+	IPaddress hostnameIP;
+
+	// retrieve portnum from address!
+	if (port && !port[0])
+		portnum = atoi(port);
+
+	if (SDLNet_ResolveHost(&hostnameIP,hostname,portnum) == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return -1;
+	}
+	newnode = SDLNet_UDP_Bind(mysocket,-1,&hostnameIP);
+	if (newnode == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return newnode;
+	}
+	newnode++;
+	M_Memcpy(&clientaddress[newnode],&hostnameIP,sizeof (IPaddress));
+	return (SINT8)newnode;
+}
+
+
+static boolean NET_OpenSocket(void)
+{
+	memset(clientaddress, 0, sizeof (clientaddress));
+
+	//I_OutputMsg("SDL_Net Code starting up\n");
+
+	I_NetSend = NET_Send;
+	I_NetGet = NET_Get;
+	I_NetCloseSocket = NET_CloseSocket;
+	I_NetFreeNodenum = NET_FreeNodenum;
+	I_NetMakeNodewPort = NET_NetMakeNodewPort;
+
+	//I_NetCanSend = NET_CanSend;
+
+	// build the socket but close it first
+	NET_CloseSocket();
+	mysocket = NET_Socket();
+
+	if (!mysocket)
+		return false;
+
+	// for select
+	myset = SDLNet_AllocSocketSet(1);
+	if (!myset)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return false;
+	}
+	if (SDLNet_UDP_AddSocket(myset,mysocket) == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return false;
+	}
+	return true;
+}
+
+static boolean NET_Ban(INT32 node)
+{
+	if (numbans == MAXBANS)
+		return false;
+
+	M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (IPaddress));
+	banned[numbans].port = 0;
+	numbans++;
+	return true;
+}
+
+static boolean NET_SetBanAddress(const char *address, const char *mask)
+{
+	(void)mask;
+	if (bans == MAXBANS)
+		return false;
+
+	if (SDLNet_ResolveHost(&banned[numbans], address, 0) == -1)
+		return false;
+	numbans++;
+	return true;
+}
+
+static void NET_ClearBans(void)
+{
+	numbans = 0;
+}
+#endif
+
+//
+// I_InitNetwork
+// Only required for DOS, so this is more a dummy
+//
+boolean I_InitNetwork(void)
+{
+#ifdef HAVE_SDLNET
+	char serverhostname[255];
+	boolean ret = false;
+	SDL_version SDLcompiled;
+	const SDL_version *SDLlinked = SDLNet_Linked_Version();
+	SDL_NET_VERSION(&SDLcompiled)
+	I_OutputMsg("Compiled for SDL_Net version: %d.%d.%d\n",
+                        SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch);
+	I_OutputMsg("Linked with SDL_Net version: %d.%d.%d\n",
+                        SDLlinked->major, SDLlinked->minor, SDLlinked->patch);
+	//if (!M_CheckParm ("-sdlnet"))
+	//	return false;
+	// initilize the driver
+	I_InitSDLNetDriver();
+	I_AddExitFunc(I_ShutdownSDLNetDriver);
+	if (!init_SDLNet_driver)
+		return false;
+
+	if (M_CheckParm("-udpport"))
+	{
+		if (M_IsNextParm())
+			sock_port = (UINT16)atoi(M_GetNextParm());
+		else
+			sock_port = 0;
+	}
+
+	// parse network game options,
+	if (M_CheckParm("-server") || dedicated)
+	{
+		server = true;
+
+		// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
+		// to connect before starting.
+		// If no number is specified here, the server starts with 1 client, and others can join
+		// in-game.
+		// Since Boris has implemented join in-game, there is no actual need for specifying a
+		// particular number here.
+		// FIXME: for dedicated server, numnodes needs to be set to 0 upon start
+/*		if (M_IsNextParm())
+			doomcom->numnodes = (INT16)atoi(M_GetNextParm());
+		else */if (dedicated)
+			doomcom->numnodes = 0;
+		else
+			doomcom->numnodes = 1;
+
+		if (doomcom->numnodes < 0)
+			doomcom->numnodes = 0;
+		if (doomcom->numnodes > MAXNETNODES)
+			doomcom->numnodes = MAXNETNODES;
+
+		// server
+		servernode = 0;
+		// FIXME:
+		// ??? and now ?
+		// server on a big modem ??? 4*isdn
+		net_bandwidth = 16000;
+		hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
+
+		ret = true;
+	}
+	else if (M_CheckParm("-connect"))
+	{
+		if (M_IsNextParm())
+			strcpy(serverhostname, M_GetNextParm());
+		else
+			serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
+
+		// server address only in ip
+		if (serverhostname[0])
+		{
+			COM_BufAddText("connect \"");
+			COM_BufAddText(serverhostname);
+			COM_BufAddText("\"\n");
+
+			// probably modem
+			hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
+		}
+		else
+		{
+			// so we're on a LAN
+			COM_BufAddText("connect any\n");
+
+			net_bandwidth = 800000;
+			hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
+		}
+	}
+
+	mypacket.maxlen = hardware_MAXPACKETLENGTH;
+	I_NetOpenSocket = NET_OpenSocket;
+	I_Ban = NET_Ban;
+	I_ClearBans = NET_ClearBans;
+	I_GetNodeAddress = NET_GetNodeAddress;
+	I_GetBenAddress = NET_GetBenAddress;
+	I_SetBanAddress = NET_SetBanAddress;
+	bannednode = NET_bannednode;
+
+	return ret;
+#else
+	if ( M_CheckParm ("-net") )
+	{
+		I_Error("-net not supported, use -server and -connect\n"
+			"see docs for more\n");
+	}
+	return false;
+#endif
+}
+#endif
diff --git a/src/sdl12/i_net.c b/src/sdl12/i_net.c
new file mode 100644
index 00000000..ee4a34c1
--- /dev/null
+++ b/src/sdl12/i_net.c
@@ -0,0 +1,442 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Portions Copyright (C) 1998-2000 by DooM Legacy Team.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//-----------------------------------------------------------------------------
+/// \file
+/// \brief SDL network interface
+
+#include "../doomdef.h"
+
+#include "../i_system.h"
+#include "../d_event.h"
+#include "../d_net.h"
+#include "../m_argv.h"
+
+#include "../doomstat.h"
+
+#include "../i_net.h"
+
+#include "../z_zone.h"
+
+#include "../i_tcp.h"
+
+#ifdef HAVE_SDL
+
+#ifdef HAVE_SDLNET
+
+#include "SDL_net.h"
+
+#define MAXBANS 20
+
+static IPaddress clientaddress[MAXNETNODES+1];
+static IPaddress banned[MAXBANS];
+
+static UDPpacket mypacket;
+static UDPsocket mysocket = NULL;
+static SDLNet_SocketSet myset = NULL;
+
+static size_t numbans = 0;
+static boolean NET_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
+static boolean init_SDLNet_driver = false;
+
+static const char *NET_AddrToStr(IPaddress* sk)
+{
+	static char s[22]; // 255.255.255.255:65535
+	strcpy(s, SDLNet_ResolveIP(sk));
+	if (sk->port != 0) strcat(s, va(":%d", sk->port));
+	return s;
+}
+
+static const char *NET_GetNodeAddress(INT32 node)
+{
+	if (!nodeconnected[node])
+		return NULL;
+	return NET_AddrToStr(&clientaddress[node]);
+}
+
+static const char *NET_GetBanAddress(size_t ban)
+{
+	if (ban > numbans)
+		return NULL;
+	return NET_AddrToStr(&banned[ban]);
+}
+
+static boolean NET_cmpaddr(IPaddress* a, IPaddress* b)
+{
+	return (a->host == b->host && (b->port == 0 || a->port == b->port));
+}
+
+static boolean NET_CanGet(void)
+{
+	return myset?(SDLNet_CheckSockets(myset,0)  == 1):false;
+}
+
+static void NET_Get(void)
+{
+	INT32 mystatus;
+	INT32 newnode;
+	mypacket.len = MAXPACKETLENGTH;
+	if (!NET_CanGet())
+	{
+		doomcom->remotenode = -1; // no packet
+		return;
+	}
+	mystatus = SDLNet_UDP_Recv(mysocket,&mypacket);
+	if (mystatus != -1)
+	{
+		if (mypacket.channel != -1)
+		{
+			doomcom->remotenode = mypacket.channel+1; // good packet from a game player
+			doomcom->datalength = mypacket.len;
+			return;
+		}
+		newnode = SDLNet_UDP_Bind(mysocket,-1,&mypacket.address);
+		if (newnode != -1)
+		{
+			size_t i;
+			newnode++;
+			M_Memcpy(&clientaddress[newnode], &mypacket.address, sizeof (IPaddress));
+			DEBFILE(va("New node detected: node:%d address:%s\n", newnode,
+					NET_GetNodeAddress(newnode)));
+			doomcom->remotenode = newnode; // good packet from a game player
+			doomcom->datalength = mypacket.len;
+			for (i = 0; i < numbans; i++)
+			{
+				if (NET_cmpaddr(&mypacket.address, &banned[i]))
+				{
+					DEBFILE("This dude has been banned\n");
+					NET_bannednode[newnode] = true;
+					break;
+				}
+			}
+			if (i == numbans)
+				NET_bannednode[newnode] = false;
+			return;
+		}
+		else
+			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+	}
+	else if (mystatus == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+	}
+
+	DEBFILE("New node detected: No more free slots\n");
+	doomcom->remotenode = -1; // no packet
+}
+
+#if 0
+static boolean NET_CanSend(void)
+{
+	return true;
+}
+#endif
+
+static void NET_Send(void)
+{
+	if (!doomcom->remotenode)
+		return;
+	mypacket.len = doomcom->datalength;
+	if (SDLNet_UDP_Send(mysocket,doomcom->remotenode-1,&mypacket) == 0)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+	}
+}
+
+static void NET_FreeNodenum(INT32 numnode)
+{
+	// can't disconnect from self :)
+	if (!numnode)
+		return;
+
+	DEBFILE(va("Free node %d (%s)\n", numnode, NET_GetNodeAddress(numnode)));
+
+	SDLNet_UDP_Unbind(mysocket,numnode-1);
+
+	memset(&clientaddress[numnode], 0, sizeof (IPaddress));
+}
+
+static UDPsocket NET_Socket(void)
+{
+	UDPsocket temp = NULL;
+	Uint16 portnum = 0;
+	IPaddress tempip = {INADDR_BROADCAST,0};
+	//Hurdler: I'd like to put a server and a client on the same computer
+	//Logan: Me too
+	//BP: in fact for client we can use any free port we want i have read
+	//    in some doc that connect in udp can do it for us...
+	//Alam: where?
+	if (M_CheckParm("-clientport"))
+	{
+		if (!M_IsNextParm())
+			I_Error("syntax: -clientport <portnum>");
+		portnum = atoi(M_GetNextParm());
+	}
+	else
+		portnum = sock_port;
+	temp = SDLNet_UDP_Open(portnum);
+	if (!temp)
+	{
+			I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return NULL;
+	}
+	if (SDLNet_UDP_Bind(temp,BROADCASTADDR-1,&tempip) == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		SDLNet_UDP_Close(temp);
+		return NULL;
+	}
+	clientaddress[BROADCASTADDR].port = sock_port;
+	clientaddress[BROADCASTADDR].host = INADDR_BROADCAST;
+
+	doomcom->extratics = 1; // internet is very high ping
+
+	return temp;
+}
+
+static void I_ShutdownSDLNetDriver(void)
+{
+	if (myset) SDLNet_FreeSocketSet(myset);
+	myset = NULL;
+	SDLNet_Quit();
+	init_SDLNet_driver = false;
+}
+
+static void I_InitSDLNetDriver(void)
+{
+	if (init_SDLNet_driver)
+		I_ShutdownSDLNetDriver();
+	if (SDLNet_Init() == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return; // No good!
+	}
+	D_SetDoomcom();
+	mypacket.data = doomcom->data;
+	init_SDLNet_driver = true;
+}
+
+static void NET_CloseSocket(void)
+{
+	if (mysocket)
+		SDLNet_UDP_Close(mysocket);
+	mysocket = NULL;
+}
+
+static SINT8 NET_NetMakeNodewPort(const char *hostname, const char *port)
+{
+	INT32 newnode;
+	UINT16 portnum = sock_port;
+	IPaddress hostnameIP;
+
+	// retrieve portnum from address!
+	if (port && !port[0])
+		portnum = atoi(port);
+
+	if (SDLNet_ResolveHost(&hostnameIP,hostname,portnum) == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return -1;
+	}
+	newnode = SDLNet_UDP_Bind(mysocket,-1,&hostnameIP);
+	if (newnode == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return newnode;
+	}
+	newnode++;
+	M_Memcpy(&clientaddress[newnode],&hostnameIP,sizeof (IPaddress));
+	return (SINT8)newnode;
+}
+
+
+static boolean NET_OpenSocket(void)
+{
+	memset(clientaddress, 0, sizeof (clientaddress));
+
+	//I_OutputMsg("SDL_Net Code starting up\n");
+
+	I_NetSend = NET_Send;
+	I_NetGet = NET_Get;
+	I_NetCloseSocket = NET_CloseSocket;
+	I_NetFreeNodenum = NET_FreeNodenum;
+	I_NetMakeNodewPort = NET_NetMakeNodewPort;
+
+	//I_NetCanSend = NET_CanSend;
+
+	// build the socket but close it first
+	NET_CloseSocket();
+	mysocket = NET_Socket();
+
+	if (!mysocket)
+		return false;
+
+	// for select
+	myset = SDLNet_AllocSocketSet(1);
+	if (!myset)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return false;
+	}
+	if (SDLNet_UDP_AddSocket(myset,mysocket) == -1)
+	{
+		I_OutputMsg("SDL_Net: %s",SDLNet_GetError());
+		return false;
+	}
+	return true;
+}
+
+static boolean NET_Ban(INT32 node)
+{
+	if (numbans == MAXBANS)
+		return false;
+
+	M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (IPaddress));
+	banned[numbans].port = 0;
+	numbans++;
+	return true;
+}
+
+static boolean NET_SetBanAddress(const char *address, const char *mask)
+{
+	(void)mask;
+	if (bans == MAXBANS)
+		return false;
+
+	if (SDLNet_ResolveHost(&banned[numbans], address, 0) == -1)
+		return false;
+	numbans++;
+	return true;
+}
+
+static void NET_ClearBans(void)
+{
+	numbans = 0;
+}
+#endif
+
+//
+// I_InitNetwork
+// Only required for DOS, so this is more a dummy
+//
+boolean I_InitNetwork(void)
+{
+#ifdef HAVE_SDLNET
+	char serverhostname[255];
+	boolean ret = false;
+	SDL_version SDLcompiled;
+	const SDL_version *SDLlinked = SDLNet_Linked_Version();
+	SDL_NET_VERSION(&SDLcompiled)
+	I_OutputMsg("Compiled for SDL_Net version: %d.%d.%d\n",
+                        SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch);
+	I_OutputMsg("Linked with SDL_Net version: %d.%d.%d\n",
+                        SDLlinked->major, SDLlinked->minor, SDLlinked->patch);
+	//if (!M_CheckParm ("-sdlnet"))
+	//	return false;
+	// initilize the driver
+	I_InitSDLNetDriver();
+	I_AddExitFunc(I_ShutdownSDLNetDriver);
+	if (!init_SDLNet_driver)
+		return false;
+
+	if (M_CheckParm("-udpport"))
+	{
+		if (M_IsNextParm())
+			sock_port = (UINT16)atoi(M_GetNextParm());
+		else
+			sock_port = 0;
+	}
+
+	// parse network game options,
+	if (M_CheckParm("-server") || dedicated)
+	{
+		server = true;
+
+		// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
+		// to connect before starting.
+		// If no number is specified here, the server starts with 1 client, and others can join
+		// in-game.
+		// Since Boris has implemented join in-game, there is no actual need for specifying a
+		// particular number here.
+		// FIXME: for dedicated server, numnodes needs to be set to 0 upon start
+/*		if (M_IsNextParm())
+			doomcom->numnodes = (INT16)atoi(M_GetNextParm());
+		else */if (dedicated)
+			doomcom->numnodes = 0;
+		else
+			doomcom->numnodes = 1;
+
+		if (doomcom->numnodes < 0)
+			doomcom->numnodes = 0;
+		if (doomcom->numnodes > MAXNETNODES)
+			doomcom->numnodes = MAXNETNODES;
+
+		// server
+		servernode = 0;
+		// FIXME:
+		// ??? and now ?
+		// server on a big modem ??? 4*isdn
+		net_bandwidth = 16000;
+		hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
+
+		ret = true;
+	}
+	else if (M_CheckParm("-connect"))
+	{
+		if (M_IsNextParm())
+			strcpy(serverhostname, M_GetNextParm());
+		else
+			serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
+
+		// server address only in ip
+		if (serverhostname[0])
+		{
+			COM_BufAddText("connect \"");
+			COM_BufAddText(serverhostname);
+			COM_BufAddText("\"\n");
+
+			// probably modem
+			hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
+		}
+		else
+		{
+			// so we're on a LAN
+			COM_BufAddText("connect any\n");
+
+			net_bandwidth = 800000;
+			hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
+		}
+	}
+
+	mypacket.maxlen = hardware_MAXPACKETLENGTH;
+	I_NetOpenSocket = NET_OpenSocket;
+	I_Ban = NET_Ban;
+	I_ClearBans = NET_ClearBans;
+	I_GetNodeAddress = NET_GetNodeAddress;
+	I_GetBenAddress = NET_GetBenAddress;
+	I_SetBanAddress = NET_SetBanAddress;
+	bannednode = NET_bannednode;
+
+	return ret;
+#else
+	if ( M_CheckParm ("-net") )
+	{
+		I_Error("-net not supported, use -server and -connect\n"
+			"see docs for more\n");
+	}
+	return false;
+#endif
+}
+#endif