diff --git a/src/Makefile b/src/Makefile
index 017bd2442b6563b64210702087418fb16f013938..322e67bfe5bd87abc1bc6bd911cd3ea3a0d9e136 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -79,7 +79,7 @@
 
 # SRB2 data files
 D_DIR?=../bin/Resources
-D_FILES=$(D_DIR)/srb2.srb \
+D_FILES=$(D_DIR)/srb2.pk3 \
 	$(D_DIR)/player.dta \
 	$(D_DIR)/rings.wpn \
 	$(D_DIR)/drill.dta \
diff --git a/src/config.h.in b/src/config.h.in
index 5f06ec45df306429a53eb26dd883939d5173df76..7c9ebe6cb5e3982a22a9a588d9f1cb5460595c60 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -11,7 +11,7 @@
 
 #ifdef CMAKECONFIG
 
-#define ASSET_HASH_SRB2_SRB   "${SRB2_ASSET_srb2.srb_HASH}"
+#define ASSET_HASH_SRB2_PK3   "${SRB2_ASSET_srb2.pk3_HASH}"
 #define ASSET_HASH_PLAYER_DTA "${SRB2_ASSET_player.dta_HASH}"
 #define ASSET_HASH_RINGS_DTA  "${SRB2_ASSET_rings.dta_HASH}"
 #define ASSET_HASH_ZONES_DTA  "${SRB2_ASSET_zones.dta_HASH}"
@@ -31,7 +31,7 @@
 /* Manually defined asset hashes for non-CMake builds
  * Last updated 2015 / 05 / 03
  */
-#define ASSET_HASH_SRB2_SRB   "c1b9577687f8a795104aef4600720ea7"
+#define ASSET_HASH_SRB2_PK3   "c1b9577687f8a795104aef4600720ea7"
 #define ASSET_HASH_ZONES_DTA  "303838c6c534d9540288360fa49cca60"
 #define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799"
 #define ASSET_HASH_RINGS_DTA  "85901ad4bf94637e5753d2ac2c03ea26"
diff --git a/src/console.c b/src/console.c
index a504af06d7f4d28f88c0d1f1c40e806c9f5e2b2a..0b3245a6fa6f93ec8f932e7ae6105fc50069ebe4 100644
--- a/src/console.c
+++ b/src/console.c
@@ -839,8 +839,9 @@ boolean CON_Responder(event_t *ev)
 			return true;
 		}
 
-		// don't eat the key
-		return false;
+		// ...why shouldn't it eat the key? if it doesn't, it just means you
+		// can control Sonic from the console, which is silly
+		return true; //return false;
 	}
 
 	// command completion forward (tab) and backward (shift-tab)
@@ -1039,7 +1040,7 @@ boolean CON_Responder(event_t *ev)
 
 	// enter a char into the command prompt
 	if (key < 32 || key > 127)
-		return false;
+		return true; // even if key can't be printed, eat it anyway
 
 	// add key to cmd line here
 	if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 10a5c13678a55e3fc03fcff4e569cfe089494c42..bb80e88ef2cfeec5c8f9f49d66b8202b3422a845 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -4003,7 +4003,8 @@ static void HandlePacketFromPlayer(SINT8 node)
 						INT32 k = *txtpak++; // playernum
 						const size_t txtsize = txtpak[0]+1;
 
-						M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize);
+						if (i >= gametic) // Don't copy old net commands
+							M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize);
 						txtpak += txtsize;
 					}
 				}
diff --git a/src/d_main.c b/src/d_main.c
index 45f9d67639ea7395ccd5f5c8bd68156a76aefe5a..05aa3e67570bdbb8ad14f368035c42437049c74d 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -784,7 +784,7 @@ static inline void D_CleanFile(void)
 
 static void IdentifyVersion(void)
 {
-	char *srb2wad1, *srb2wad2;
+	char *srb2wad;
 	const char *srb2waddir = NULL;
 
 #if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
@@ -813,31 +813,24 @@ static void IdentifyVersion(void)
 		srb2waddir = I_GetWadDir();
 #endif
 	// Commercial.
-	srb2wad1 = malloc(strlen(srb2waddir)+1+8+1);
-	srb2wad2 = malloc(strlen(srb2waddir)+1+8+1);
-	if (srb2wad1 == NULL && srb2wad2 == NULL)
+	srb2wad = malloc(strlen(srb2waddir)+1+8+1);
+	if (srb2wad == NULL)
 		I_Error("No more free memory to look in %s", srb2waddir);
-	if (srb2wad1 != NULL)
-		sprintf(srb2wad1, pandf, srb2waddir, "srb2.pk3");
-	if (srb2wad2 != NULL)
-		sprintf(srb2wad2, pandf, srb2waddir, "srb2.wad");
+	else
+		sprintf(srb2wad, pandf, srb2waddir, "srb2.pk3");
 
 	// will be overwritten in case of -cdrom or unix/win home
 	snprintf(configfile, sizeof configfile, "%s" PATHSEP CONFIGFILENAME, srb2waddir);
 	configfile[sizeof configfile - 1] = '\0';
 
 	// Load the IWAD
-	if (srb2wad2 != NULL && FIL_ReadFileOK(srb2wad2))
-		D_AddFile(srb2wad2);
-	else if (srb2wad1 != NULL && FIL_ReadFileOK(srb2wad1))
-		D_AddFile(srb2wad1);
+	if (srb2wad != NULL && FIL_ReadFileOK(srb2wad))
+		D_AddFile(srb2wad);
 	else
-		I_Error("SRB2.SRB/SRB2.WAD not found! Expected in %s, ss files: %s and %s\n", srb2waddir, srb2wad1, srb2wad2);
+		I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad);
 
-	if (srb2wad1)
-		free(srb2wad1);
-	if (srb2wad2)
-		free(srb2wad2);
+	if (srb2wad)
+		free(srb2wad);
 
 	// if you change the ordering of this or add/remove a file, be sure to update the md5
 	// checking in D_SRB2Main
@@ -1132,7 +1125,7 @@ void D_SRB2Main(void)
 #ifndef DEVELOP // md5s last updated 12/14/14
 
 	// Check MD5s of autoloaded files
-	//W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad
+	//W_VerifyFileMD5(0, ASSET_HASH_SRB2_PK3); // srb2.pk3
 	//W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta
 	//W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta
 #ifdef USE_PATCH_DTA
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 6f0406a2104ff0299a90435dc7cd1e1c7baa1aff..94eada15217c652984bd3ee7453e096228ee786e 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -586,7 +586,6 @@ void D_RegisterServerCommands(void)
   */
 void D_RegisterClientCommands(void)
 {
-	const char *username;
 	INT32 i;
 
 	for (i = 0; i < MAXSKINCOLORS; i++)
@@ -644,8 +643,6 @@ void D_RegisterClientCommands(void)
 #endif
 
 	// register these so it is saved to config
-	if ((username = I_GetUserName()))
-		cv_playername.defaultvalue = cv_defaultplayername.defaultvalue = username;
 	CV_RegisterVar(&cv_playername);
 	CV_RegisterVar(&cv_playercolor);
 	CV_RegisterVar(&cv_skin); // r_things.c (skin NAME)
@@ -3071,7 +3068,7 @@ static void Command_Addfile(void)
 	// Add file on your client directly if it is trivial, or you aren't in a netgame.
 	if (!(netgame || multiplayer) || musiconly)
 	{
-		P_AddWadFile(fn, NULL);
+		P_AddWadFile(fn);
 		return;
 	}
 
@@ -3240,7 +3237,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
 
 	ncs = findfile(filename,md5sum,true);
 
-	if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
+	if (ncs != FS_FOUND || !P_AddWadFile(filename))
 	{
 		Command_ExitGame_f();
 		if (ncs == FS_FOUND)
diff --git a/src/d_netfil.c b/src/d_netfil.c
index 72ac0dd320bbfa284134d0e240c80b955415ec4e..614d2064e374ddd7aff45703b6309617de8c1f3e 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -333,7 +333,7 @@ INT32 CL_CheckFiles(void)
 //		return 1;
 
 	// the first is the iwad (the main wad file)
-	// we don't care if it's called srb2.srb or srb2.wad.
+	// we don't care if it's called srb2.pk3 or not.
 	// Never download the IWAD, just assume it's there and identical
 	fileneeded[0].status = FS_OPEN;
 
@@ -423,7 +423,7 @@ void CL_LoadServerFiles(void)
 			continue; // Already loaded
 		else if (fileneeded[i].status == FS_FOUND)
 		{
-			P_AddWadFile(fileneeded[i].filename, NULL);
+			P_AddWadFile(fileneeded[i].filename);
 			G_SetGameModified(true);
 			fileneeded[i].status = FS_OPEN;
 		}
@@ -754,6 +754,7 @@ void Got_Filetxpak(void)
 	static INT32 filetime = 0;
 
 	if (!(strcmp(filename, "srb2.pk3")
+		&& strcmp(filename, "srb2.srb")
 		&& strcmp(filename, "srb2.wad")
 		&& strcmp(filename, "zones.dta")
 		&& strcmp(filename, "player.dta")
diff --git a/src/dehacked.c b/src/dehacked.c
index cb76c663e74b947cfed0635bcdcf6f69f4a97ae4..c172549e1bcf2a7d12965d9cdace291136ab01d8 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -1819,7 +1819,6 @@ static void readframe(MYFILE *f, INT32 num)
 	char *word1;
 	char *word2 = NULL;
 	char *tmp;
-	INT32 j;
 
 	do
 	{
@@ -1834,16 +1833,6 @@ static void readframe(MYFILE *f, INT32 num)
 			if (s == tmp)
 				continue; // Skip comment lines, but don't break.
 
-			for (j = 0; s[j] != '\n'; j++)
-			{
-				if (s[j] == '=')
-				{
-					j += 2;
-					j = atoi(&s[j]);
-					break;
-				}
-			}
-
 			word1 = strtok(s, " ");
 			if (word1)
 				strupr(word1);
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 919bbb31cd8a11db78d1613a955330596284aeaa..395fc2e4be22b68e4d57e6fc6efb2cb11ecb5852 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -593,8 +593,8 @@ void HWR_FreeTextureCache(void)
 
 	// free all hardware-converted graphics cached in the heap
 	// our gool is only the textures since user of the texture is the texture cache
-	Z_FreeTags(PU_HWRCACHE, PU_HWRCACHE);
-	Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRCACHE_UNLOCKED);
+	Z_FreeTag(PU_HWRCACHE);
+	Z_FreeTag(PU_HWRCACHE_UNLOCKED);
 
 	// Alam: free the Z_Blocks before freeing it's users
 
@@ -641,8 +641,8 @@ void HWR_SetPalette(RGBA_t *palette)
 	// now flush data texture cache so 32 bit texture are recomputed
 	if (patchformat == GR_RGBA || textureformat == GR_RGBA)
 	{
-		Z_FreeTags(PU_HWRCACHE, PU_HWRCACHE);
-		Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRCACHE_UNLOCKED);
+		Z_FreeTag(PU_HWRCACHE);
+		Z_FreeTag(PU_HWRCACHE_UNLOCKED);
 	}
 }
 
diff --git a/src/lua_script.c b/src/lua_script.c
index fdaa12c781093fb0c2b112a25fd6d827b0cf89f0..0aebafaeeb37e98529561b90255c2117e03698cf 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -176,11 +176,16 @@ static inline void LUA_LoadFile(MYFILE *f, char *name)
 		LUA_ClearState();
 	lua_pushinteger(gL, f->wad);
 	lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
+
+	lua_lumploading = true; // turn on loading flag
+
 	if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, 0, 0)) {
 		CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
 		lua_pop(gL,1);
 	}
 	lua_gc(gL, LUA_GCCOLLECT, 0);
+
+	lua_lumploading = false; // turn off again
 }
 
 // Load a script from a lump
@@ -188,24 +193,28 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump)
 {
 	MYFILE f;
 	char *name;
+
 	f.wad = wad;
 	f.size = W_LumpLengthPwad(wad, lump);
 	f.data = Z_Malloc(f.size, PU_LUA, NULL);
 	W_ReadLumpPwad(wad, lump, f.data);
 	f.curpos = f.data;
 
-	name = malloc(strlen(wadfiles[wad]->filename)+10);
-	strcpy(name, wadfiles[wad]->filename);
-	if (!fasticmp(&name[strlen(name) - 4], ".lua")) {
-		// If it's not a .lua file, copy the lump name in too.
-		name[strlen(wadfiles[wad]->filename)] = '|';
-		M_Memcpy(name+strlen(wadfiles[wad]->filename)+1, wadfiles[wad]->lumpinfo[lump].name, 8);
-		name[strlen(wadfiles[wad]->filename)+9] = '\0';
+	if (wadfiles[wad]->type == RET_LUA)
+	{
+		name = malloc(strlen(wadfiles[wad]->filename)+1);
+		strcpy(name, wadfiles[wad]->filename);
+	}
+	else // If it's not a .lua file, copy the lump name in too.
+	{
+		lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump];
+		size_t length = strlen(wadfiles[wad]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name
+		name = malloc(length + 1);
+		sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2);
+		name[length] = '\0';
 	}
 
-	lua_lumploading = true; // turn on loading flag
 	LUA_LoadFile(&f, name); // actually load file!
-	lua_lumploading = false; // turn off again
 
 	free(name);
 	Z_Free(f.data);
diff --git a/src/m_misc.c b/src/m_misc.c
index 1cf244da02d96fbc86f8ec83a61a20a2a1137f70..bf637f7c3fcb65ea8b1879872d2f1bdd6724d893 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -649,13 +649,12 @@ static void M_PNGhdr(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_
 static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png_byte movie)
 {
 #ifdef PNG_TEXT_SUPPORTED
-#define SRB2PNGTXT 11 //PNG_KEYWORD_MAX_LENGTH(79) is the max
+#define SRB2PNGTXT 10 //PNG_KEYWORD_MAX_LENGTH(79) is the max
 	png_text png_infotext[SRB2PNGTXT];
 	char keytxt[SRB2PNGTXT][12] = {
-	"Title", "Author", "Description", "Playername", "Mapnum", "Mapname",
+	"Title", "Description", "Playername", "Mapnum", "Mapname",
 	"Location", "Interface", "Revision", "Build Date", "Build Time"};
 	char titletxt[] = "Sonic Robo Blast 2 " VERSIONSTRING;
-	png_charp authortxt = I_GetUserName();
 	png_charp playertxt =  cv_playername.zstring;
 	char desctxt[] = "SRB2 Screenshot";
 	char Movietxt[] = "SRB2 Movie";
@@ -705,19 +704,18 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
 		png_infotext[i].key  = keytxt[i];
 
 	png_infotext[0].text = titletxt;
-	png_infotext[1].text = authortxt;
 	if (movie)
-		png_infotext[2].text = Movietxt;
+		png_infotext[1].text = Movietxt;
 	else
-		png_infotext[2].text = desctxt;
-	png_infotext[3].text = playertxt;
-	png_infotext[4].text = maptext;
-	png_infotext[5].text = lvlttltext;
-	png_infotext[6].text = locationtxt;
-	png_infotext[7].text = interfacetxt;
-	png_infotext[8].text = strncpy(ctrevision, comprevision, sizeof(ctrevision)-1);
-	png_infotext[9].text = strncpy(ctdate, compdate, sizeof(ctdate)-1);
-	png_infotext[10].text = strncpy(cttime, comptime, sizeof(cttime)-1);
+		png_infotext[1].text = desctxt;
+	png_infotext[2].text = playertxt;
+	png_infotext[3].text = maptext;
+	png_infotext[4].text = lvlttltext;
+	png_infotext[5].text = locationtxt;
+	png_infotext[6].text = interfacetxt;
+	png_infotext[7].text = strncpy(ctrevision, comprevision, sizeof(ctrevision)-1);
+	png_infotext[8].text = strncpy(ctdate, compdate, sizeof(ctdate)-1);
+	png_infotext[9].text = strncpy(cttime, comptime, sizeof(cttime)-1);
 
 	png_set_text(png_ptr, png_info_ptr, png_infotext, SRB2PNGTXT);
 #undef SRB2PNGTXT
diff --git a/src/p_saveg.c b/src/p_saveg.c
index d53869d2eebcb0b6d98d34cb7352c556e5303332..029df08f4befdbe0f897ee781cb52038f099bcd8 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -497,16 +497,34 @@ static void P_NetArchiveWorld(void)
 	UINT8 *put;
 
 	// reload the map just to see difference
-	const mapsector_t *ms;
-	const mapsidedef_t *msd;
-	const maplinedef_t *mld;
+	mapsector_t *ms;
+	mapsidedef_t *msd;
+	maplinedef_t *mld;
 	const sector_t *ss = sectors;
 	UINT8 diff, diff2;
 
 	WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
 	put = save_p;
 
-	ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE);
+	if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
+	{ // HACK: Open wad file rather quickly so we can get the data from the relevant lumps
+		UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
+		filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
+#define retrieve_mapdata(d, f)\
+		d = Z_Malloc((f)->size, PU_CACHE, NULL); \
+		M_Memcpy(d, wadData + (f)->filepos, (f)->size)
+		retrieve_mapdata(ms, fileinfo + ML_SECTORS);
+		retrieve_mapdata(mld, fileinfo + ML_LINEDEFS);
+		retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS);
+#undef retrieve_mapdata
+		Z_Free(wadData); // we're done with this now
+	}
+	else // phew it's just a WAD
+	{
+			ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE);
+			mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE);
+			msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE);
+	}
 
 	for (i = 0; i < numsectors; i++, ss++, ms++)
 	{
@@ -637,8 +655,6 @@ static void P_NetArchiveWorld(void)
 
 	WRITEUINT16(put, 0xffff);
 
-	mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE);
-	msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE);
 	// do lines
 	for (i = 0; i < numlines; i++, mld++, li++)
 	{
diff --git a/src/p_setup.c b/src/p_setup.c
index fc0b7273b2d6f7f8c57e2ee893987df33c43e5bd..a9fc57652f63d54a5f1b88966c4ac8db49e81649 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1893,6 +1893,30 @@ static void P_CreateBlockMap(void)
 	}
 }
 
+// Split from P_LoadBlockMap for convenience
+// -- Monster Iestyn 08/01/18
+static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count)
+{
+	size_t i;
+	blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, NULL);
+
+	// killough 3/1/98: Expand wad blockmap into larger internal one,
+	// by treating all offsets except -1 as unsigned and zero-extending
+	// them. This potentially doubles the size of blockmaps allowed,
+	// because Doom originally considered the offsets as always signed.
+
+	blockmaplump[0] = SHORT(wadblockmaplump[0]);
+	blockmaplump[1] = SHORT(wadblockmaplump[1]);
+	blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff;
+	blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff;
+
+	for (i = 4; i < count; i++)
+	{
+		INT16 t = SHORT(wadblockmaplump[i]);          // killough 3/1/98
+		blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff;
+	}
+}
+
 //
 // P_LoadBlockMap
 //
@@ -1919,38 +1943,20 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum)
 		return false;
 
 	{
-		size_t i;
 		INT16 *wadblockmaplump = malloc(count); //INT16 *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL);
-
-		if (wadblockmaplump) W_ReadLump(lumpnum, wadblockmaplump);
-		else return false;
+		if (!wadblockmaplump)
+			return false;
+		W_ReadLump(lumpnum, wadblockmaplump);
 		count /= 2;
-		blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, 0);
-
-		// killough 3/1/98: Expand wad blockmap into larger internal one,
-		// by treating all offsets except -1 as unsigned and zero-extending
-		// them. This potentially doubles the size of blockmaps allowed,
-		// because Doom originally considered the offsets as always signed.
-
-		blockmaplump[0] = SHORT(wadblockmaplump[0]);
-		blockmaplump[1] = SHORT(wadblockmaplump[1]);
-		blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff;
-		blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff;
-
-		for (i = 4; i < count; i++)
-		{
-			INT16 t = SHORT(wadblockmaplump[i]);          // killough 3/1/98
-			blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff;
-		}
-
+		P_ReadBlockMapLump(wadblockmaplump, count);
 		free(wadblockmaplump);
-
-		bmaporgx = blockmaplump[0]<<FRACBITS;
-		bmaporgy = blockmaplump[1]<<FRACBITS;
-		bmapwidth = blockmaplump[2];
-		bmapheight = blockmaplump[3];
 	}
 
+	bmaporgx = blockmaplump[0]<<FRACBITS;
+	bmaporgy = blockmaplump[1]<<FRACBITS;
+	bmapwidth = blockmaplump[2];
+	bmapheight = blockmaplump[3];
+
 	// clear out mobj chains
 	count = sizeof (*blocklinks)* bmapwidth*bmapheight;
 	blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
@@ -1984,6 +1990,53 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum)
 #endif
 }
 
+// This needs to be a separate function
+// because making both the WAD and PK3 loading code use
+// the same functions is trickier than it looks for blockmap
+// -- Monster Iestyn 09/01/18
+static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname)
+{
+#if 0
+	(void)data;
+	(void)count;
+	(void)lumpname;
+	return false;
+#else
+	// Check if the lump is named "BLOCKMAP"
+	if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0)
+	{
+		CONS_Printf("No blockmap lump found for pk3!\n");
+		return false;
+	}
+
+	if (!count || count >= 0x20000)
+		return false;
+
+	CONS_Printf("Reading blockmap lump for pk3...\n");
+
+	// no need to malloc anything, assume the data is uncompressed for now
+	count /= 2;
+	P_ReadBlockMapLump((INT16 *)data, count);
+
+	bmaporgx = blockmaplump[0]<<FRACBITS;
+	bmaporgy = blockmaplump[1]<<FRACBITS;
+	bmapwidth = blockmaplump[2];
+	bmapheight = blockmaplump[3];
+
+	// clear out mobj chains
+	count = sizeof (*blocklinks)* bmapwidth*bmapheight;
+	blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
+	blockmap = blockmaplump+4;
+
+#ifdef POLYOBJECTS
+	// haleyjd 2/22/06: setup polyobject blockmap
+	count = sizeof(*polyblocklinks) * bmapwidth * bmapheight;
+	polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL);
+#endif
+	return true;
+#endif
+}
+
 //
 // P_GroupLines
 // Builds sector line lists and subsector sector numbers.
@@ -2109,6 +2162,30 @@ static void P_LoadReject(lumpnum_t lumpnum)
 		rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
 }
 
+// PK3 version
+// -- Monster Iestyn 09/01/18
+static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname)
+{
+	// Check if the lump is named "REJECT"
+	if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
+	{
+		rejectmatrix = NULL;
+		CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n");
+		return;
+	}
+
+	if (!count) // zero length, someone probably used ZDBSP
+	{
+		rejectmatrix = NULL;
+		CONS_Debug(DBG_SETUP, "P_LoadRawReject: REJECT lump has size 0, will not be loaded\n");
+	}
+	else
+	{
+		rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
+		M_Memcpy(rejectmatrix, data, count); // copy the data into it
+	}
+}
+
 #if 0
 static char *levellumps[] =
 {
@@ -2581,7 +2658,6 @@ boolean P_SetupLevel(boolean skipprecip)
 	// use gamemap to get map number.
 	// 99% of the things already did, so.
 	// Map header should always be in place at this point
-	char *lumpfullName;
 	INT32 i, loadprecip = 1, ranspecialwipe = 0;
 	INT32 loademblems = 1;
 	INT32 fromnetsave = 0;
@@ -2764,14 +2840,26 @@ boolean P_SetupLevel(boolean skipprecip)
 	// As it is implemented right now, we're assuming an uncompressed WAD.
 	// (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.)
 	// We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error.
-	lumpfullName = (wadfiles[WADFILENUM(lastloadedmaplumpnum)]->lumpinfo + LUMPNUM(lastloadedmaplumpnum))->name2;
-	if (!strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4))
+	if (W_IsLumpWad(lastloadedmaplumpnum))
 	{
 		// Remember that we're assuming that the WAD will have a specific set of lumps in a specific order.
 		UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
 		//filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs;
 		filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
+		UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps;
+
+		if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded
+		{
+			I_Error("Bad WAD file for map %s!\n", maplumpname);
+		}
 
+		if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least
+		{
+			loadedbm = P_LoadRawBlockMap(
+							wadData + (fileinfo + ML_BLOCKMAP)->filepos,
+							(fileinfo + ML_BLOCKMAP)->size,
+							(fileinfo + ML_BLOCKMAP)->name);
+		}
 		P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size);
 		P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size);
 		P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size);
@@ -2780,6 +2868,13 @@ boolean P_SetupLevel(boolean skipprecip)
 		P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size);
 		P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size);
 		P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size);
+		if (numlumps > ML_REJECT) // enough room for a REJECT lump at least
+		{
+			P_LoadRawReject(
+					wadData + (fileinfo + ML_REJECT)->filepos,
+					(fileinfo + ML_REJECT)->size,
+					(fileinfo + ML_REJECT)->name);
+		}
 
 		// Important: take care of the ordering of the next functions.
 		if (!loadedbm)
@@ -3133,7 +3228,7 @@ boolean P_RunSOC(const char *socfilename)
 	lumpnum_t lump;
 
 	if (strstr(socfilename, ".soc") != NULL)
-		return P_AddWadFile(socfilename, NULL);
+		return P_AddWadFile(socfilename);
 
 	lump = W_CheckNumForName(socfilename);
 	if (lump == LUMPERROR)
@@ -3163,6 +3258,7 @@ void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num)
 				CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", lumpinfo->name);
 
 				I_FreeSfx(&S_sfx[j]);
+				break; // there shouldn't be two sounds with the same name, so stop looking
 			}
 		}
 	}
@@ -3214,13 +3310,13 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
 // Add a wadfile to the active wad files,
 // replace sounds, musics, patches, textures, sprites and maps
 //
-boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
+boolean P_AddWadFile(const char *wadfilename)
 {
 	size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
 	UINT16 numlumps, wadnum;
-	INT16 firstmapreplaced = 0, num;
 	char *name;
 	lumpinfo_t *lumpinfo;
+	boolean mapsadded = false;
 	boolean replacedcurrentmap = false;
 
 	// Vars to help us with the position start and amount of each resource type.
@@ -3290,17 +3386,21 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
 			name = lumpinfo->name;
 			if (name[0] == 'D')
 			{
-				if (name[1] == 'S') for (j = 1; j < NUMSFX; j++)
+				if (name[1] == 'S')
 				{
-					if (S_sfx[j].name && !strnicmp(S_sfx[j].name, name + 2, 6))
+					for (j = 1; j < NUMSFX; j++)
 					{
-						// the sound will be reloaded when needed,
-						// since sfx->data will be NULL
-						CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", name);
+						if (S_sfx[j].name && !strnicmp(S_sfx[j].name, name + 2, 6))
+						{
+							// the sound will be reloaded when needed,
+							// since sfx->data will be NULL
+							CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", name);
 
-						I_FreeSfx(&S_sfx[j]);
+							I_FreeSfx(&S_sfx[j]);
 
-						sreplaces++;
+							sreplaces++;
+							break; // there shouldn't be two sounds with the same name, so stop looking
+						}
 					}
 				}
 				else if (name[1] == '_')
@@ -3354,10 +3454,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
 	for (i = 0; i < numlumps; i++, lumpinfo++)
 	{
 		name = lumpinfo->name;
-		num = firstmapreplaced;
-
 		if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
 		{
+			INT16 num;
 			if (name[5]!='\0')
 				continue;
 			num = (INT16)M_MapNumber(name[3], name[4]);
@@ -3367,16 +3466,10 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
 				replacedcurrentmap = true;
 
 			CONS_Printf("%s\n", name);
-		}
-
-		if (num && (num < firstmapreplaced || !firstmapreplaced))
-		{
-			firstmapreplaced = num;
-			if (firstmapname)
-				*firstmapname = name;
+			mapsadded = true;
 		}
 	}
-	if (!firstmapreplaced)
+	if (!mapsadded)
 		CONS_Printf(M_GetText("No maps added\n"));
 
 	// reload status bar (warning should have valid player!)
diff --git a/src/p_setup.h b/src/p_setup.h
index de763bed0c274e0eeacc98630a8c4f330c81571d..a42ac5b7605322f2d75229c6941450f331848748 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -59,7 +59,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
 #endif
 void P_LoadThingsOnly(void);
 boolean P_SetupLevel(boolean skipprecip);
-boolean P_AddWadFile(const char *wadfilename, char **firstmapname);
+boolean P_AddWadFile(const char *wadfilename);
 boolean P_RunSOC(const char *socfilename);
 void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
 void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);
diff --git a/src/p_spec.c b/src/p_spec.c
index 797aba049cef29e9622e4f55d60dfe79ad6ca1cc..0b005baff88d86ce2e55ee57d5df88fd029039d7 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -6305,9 +6305,21 @@ void P_SpawnSpecials(INT32 fromnetsave)
 			case 259: // Make-Your-Own FOF!
 				if (lines[i].sidenum[1] != 0xffff)
 				{
-					UINT8 *data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC);
+					UINT8 *data;
 					UINT16 b;
 
+					if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
+					{ // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump
+						UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
+						filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
+						fileinfo += ML_SIDEDEFS; // we only need the SIDEDEFS lump
+						data = Z_Malloc(fileinfo->size, PU_STATIC, NULL);
+						M_Memcpy(data, wadData + fileinfo->filepos, fileinfo->size); // copy data
+						Z_Free(wadData); // we're done with this now
+					}
+					else // phew it's just a WAD
+						data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC);
+
 					for (b = 0; b < (INT16)numsides; b++)
 					{
 						register mapsidedef_t *msd = (mapsidedef_t *)data + b;
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 7d0eabe31ccdf809f82e7e241c6af93ee3df957a..c8fcd080ebd42aa5f989c60875e0cd2f4bbe1aec 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -124,7 +124,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 #include "macosx/mac_resources.h"
 #endif
 
-// Locations for searching the srb2.srb
+// Locations for searching the srb2.pk3
 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
 #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2"
 #define DEFAULTWADLOCATION2 "/usr/local/games/SRB2"
@@ -143,7 +143,6 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
 /**	\brief WAD file to look for
 */
 #define WADKEYWORD1 "srb2.pk3"
-#define WADKEYWORD2 "srb2.wad"
 /**	\brief holds wad path
 */
 static char returnWadPath[256];
@@ -2511,14 +2510,6 @@ static boolean isWadPathOk(const char *path)
 		return true;
 	}
 
-	sprintf(wad3path, pandf, path, WADKEYWORD2);
-
-	if (FIL_ReadFileOK(wad3path))
-	{
-		free(wad3path);
-		return true;
-	}
-
 	free(wad3path);
 	return false;
 }
@@ -2536,7 +2527,7 @@ static void pathonly(char *s)
 		}
 }
 
-/**	\brief	search for srb2.srb in the given path
+/**	\brief	search for srb2.pk3 in the given path
 
 	\param	searchDir	starting path
 
@@ -2557,19 +2548,12 @@ static const char *searchWad(const char *searchDir)
 		return tempsw;
 	}
 
-	strcpy(tempsw, WADKEYWORD2);
-	fstemp = filesearch(tempsw, searchDir, NULL, true, 20);
-	if (fstemp == FS_FOUND)
-	{
-		pathonly(tempsw);
-		return tempsw;
-	}
 	return NULL;
 }
 
-/**	\brief go through all possible paths and look for srb2.srb
+/**	\brief go through all possible paths and look for srb2.pk3
 
-  \return path to srb2.srb if any
+  \return path to srb2.pk3 if any
 */
 static const char *locateWad(void)
 {
@@ -2698,7 +2682,7 @@ const char *I_LocateWad(void)
 
 	if (waddir)
 	{
-		// change to the directory where we found srb2.srb
+		// change to the directory where we found srb2.pk3
 #if defined (_WIN32)
 		SetCurrentDirectoryA(waddir);
 #else
@@ -2709,7 +2693,7 @@ const char *I_LocateWad(void)
 	return waddir;
 }
 
-#if defined(LINUX) || defined(LINUX64)
+#ifdef __linux__
 #define MEMINFO_FILE "/proc/meminfo"
 #define MEMTOTAL "MemTotal:"
 #define MEMFREE "MemFree:"
@@ -2729,20 +2713,23 @@ UINT32 I_GetFreeMem(UINT32 *total)
 	};
 	if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
 	{
-		*total = 0L;
+		if (total)
+			*total = 0L;
 		return 0;
 	}
 	if (kvm_nlist(kd, namelist) != 0)
 	{
 		kvm_close (kd);
-		*total = 0L;
+		if (total)
+			*total = 0L;
 		return 0;
 	}
 	if (kvm_read(kd, namelist[X_SUM].n_value, &sum,
 		sizeof (sum)) != sizeof (sum))
 	{
 		kvm_close(kd);
-		*total = 0L;
+		if (total)
+			*total = 0L;
 		return 0;
 	}
 	kvm_close(kd);
@@ -2763,7 +2750,7 @@ UINT32 I_GetFreeMem(UINT32 *total)
 	if (total)
 		*total = (UINT32)info.dwTotalPhys;
 	return (UINT32)info.dwAvailPhys;
-#elif defined (LINUX) || defined (LINUX64)
+#elif defined (__linux__)
 	/* Linux */
 	char buf[1024];
 	char *memTag;
@@ -2779,25 +2766,28 @@ UINT32 I_GetFreeMem(UINT32 *total)
 	if (n < 0)
 	{
 		// Error
-		*total = 0L;
+		if (total)
+			*total = 0L;
 		return 0;
 	}
 
 	buf[n] = '\0';
-	if (NULL == (memTag = strstr(buf, MEMTOTAL)))
+	if ((memTag = strstr(buf, MEMTOTAL)) == NULL)
 	{
 		// Error
-		*total = 0L;
+		if (total)
+			*total = 0L;
 		return 0;
 	}
 
 	memTag += sizeof (MEMTOTAL);
 	totalKBytes = atoi(memTag);
 
-	if (NULL == (memTag = strstr(buf, MEMFREE)))
+	if ((memTag = strstr(buf, MEMFREE)) == NULL)
 	{
 		// Error
-		*total = 0L;
+		if (total)
+			*total = 0L;
 		return 0;
 	}
 
@@ -2812,7 +2802,7 @@ UINT32 I_GetFreeMem(UINT32 *total)
 	if (total)
 		*total = 48<<20;
 	return 48<<20;
-#endif /* LINUX */
+#endif
 }
 
 const CPUInfoFlags *I_CPUInfo(void)
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 437b6758a386381dc06276c1efb43357e3a83a4f..887925666d54d58d6075cb9881c2624547b891b9 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -606,7 +606,7 @@ static void ST_drawDebugInfo(void)
 
 	if (cv_debug & DBG_MEMORY)
 	{
-		V_DrawRightAlignedString(320, height,     V_MONOSPACE, va("Heap: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10)));
+		V_DrawRightAlignedString(320, height,     V_MONOSPACE, va("Heap: %7sKB", sizeu1(Z_TotalUsage()>>10)));
 	}
 }
 
diff --git a/src/w_wad.c b/src/w_wad.c
index f25711e4e741a8c86ab86d0936744f167c20b679..1b0e501a63dd6f3dd1c6b4b9c913a5044825b3cc 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -190,6 +190,7 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum)
 	if (posStart != INT16_MAX)
 	{
 		posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart);
+		posStart++; // first "lump" will be "Lua/" folder itself, so ignore it
 		for (; posStart < posEnd; posStart++)
 			LUA_LoadLump(wadnum, posStart);
 	}
@@ -197,8 +198,19 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum)
 	if (posStart != INT16_MAX)
 	{
 		posEnd = W_CheckNumForFolderEndPK3("SOCs/", wadnum, posStart);
+		posStart++; // first "lump" will be "SOCs/" folder itself, so ignore it
 		for(; posStart < posEnd; posStart++)
+		{
+			lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart];
+			size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name
+			char *name = malloc(length + 1);
+			sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2);
+			name[length] = '\0';
+
+			CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
 			DEH_LoadDehackedLumpPwad(wadnum, posStart);
+			free(name);
+		}
 	}
 }
 
@@ -222,16 +234,14 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum)
 		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
 			if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
 			{	// shameless copy+paste of code from LUA_LoadLump
-				char *name = malloc(strlen(wadfiles[wadnum]->filename)+10);
-				strcpy(name, wadfiles[wadnum]->filename);
-				if (!fasticmp(&name[strlen(name) - 4], ".soc")) {
-					// If it's not a .soc file, copy the lump name in too.
-					name[strlen(wadfiles[wadnum]->filename)] = '|';
-					M_Memcpy(name+strlen(wadfiles[wadnum]->filename)+1, lump_p->name, 8);
-					name[strlen(wadfiles[wadnum]->filename)+9] = '\0';
-				}
+				size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name
+				char *name = malloc(length + 1);
+				sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2);
+				name[length] = '\0';
+
 				CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
 				DEH_LoadDehackedLumpPwad(wadnum, lump);
+				free(name);
 			}
 			else if (memcmp(lump_p->name,"MAINCFG",8)==0) // Check for MAINCFG
 			{
@@ -319,7 +329,7 @@ UINT16 W_InitFile(const char *filename)
 	FILE *handle;
 	lumpinfo_t *lumpinfo;
 	wadfile_t *wadfile;
-	enum restype type;
+	restype_t type;
 	UINT16 numlumps;
 	size_t i;
 	INT32 compressed = 0;
@@ -390,7 +400,7 @@ UINT16 W_InitFile(const char *filename)
 		// This code emulates a wadfile with one lump name "OBJCTCFG"
 		// at position 0 and size of the whole file.
 		// This allows soc files to be like all wads, copied by network and loaded at the console.
-		type = RET_WAD;
+		type = RET_SOC;
 
 		numlumps = 1;
 		lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL);
@@ -411,7 +421,7 @@ UINT16 W_InitFile(const char *filename)
 		// This code emulates a wadfile with one lump name "LUA_INIT"
 		// at position 0 and size of the whole file.
 		// This allows soc files to be like all wads, copied by network and loaded at the console.
-		type = RET_WAD;
+		type = RET_LUA;
 
 		numlumps = 1;
 		lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL);
@@ -733,11 +743,24 @@ UINT16 W_InitFile(const char *filename)
 	numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
 
 	// TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now.
-	if (wadfile->type == RET_WAD)
-		W_LoadDehackedLumps(numwadfiles - 1);
-	else if (wadfile->type == RET_PK3)
-		W_LoadDehackedLumpsPK3(numwadfiles - 1);
-
+	switch (wadfile->type)
+	{
+		case RET_WAD:
+			W_LoadDehackedLumps(numwadfiles - 1);
+			break;
+		case RET_PK3:
+			W_LoadDehackedLumpsPK3(numwadfiles - 1);
+			break;
+		case RET_SOC:
+			CONS_Printf(M_GetText("Loading SOC from %s\n"), wadfile->filename);
+			DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0);
+			break;
+		case RET_LUA:
+			LUA_LoadLump(numwadfiles - 1, 0);
+			break;
+		default:
+			break;
+	}
 
 	W_InvalidateLumpnumCache();
 
@@ -1038,6 +1061,24 @@ size_t W_LumpLength(lumpnum_t lumpnum)
 	return W_LumpLengthPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
 }
 
+//
+// W_IsLumpWad
+// Is the lump a WAD? (presumably in a PK3)
+//
+boolean W_IsLumpWad(lumpnum_t lumpnum)
+{
+	if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3)
+	{
+		const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->name2;
+
+		if (strlen(lumpfullName) < 4)
+			return false; // can't possibly be a WAD can it?
+		return !strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4);
+	}
+
+	return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned
+}
+
 /* report a zlib or i/o error */
 void zerr(int ret)
 {
@@ -1117,30 +1158,30 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
 				I_Error("wad %d, lump %d: cannot read compressed data", wad, lump);
 			retval = lzf_decompress(rawData, l->disksize, decData, l->size);
 #ifndef AVOID_ERRNO
-			if (retval == 0 && errno == E2BIG) // errno is a global var set by the lzf functions when something goes wrong.
+			if (retval == 0) // If this was returned, check if errno was set
 			{
-				I_Error("wad %d, lump %d: compressed data too big (bigger than %s)", wad, lump, sizeu1(l->size));
+				// errno is a global var set by the lzf functions when something goes wrong.
+				if (errno == E2BIG)
+					I_Error("wad %d, lump %d: compressed data too big (bigger than %s)", wad, lump, sizeu1(l->size));
+				else if (errno == EINVAL)
+					I_Error("wad %d, lump %d: invalid compressed data", wad, lump);
 			}
-			else if (retval == 0 && errno == EINVAL)
-				I_Error("wad %d, lump %d: invalid compressed data", wad, lump);
-			else
+			// Otherwise, fall back on below error (if zero was actually the correct size then ???)
 #endif
 			if (retval != l->size)
 			{
 				I_Error("wad %d, lump %d: decompressed to wrong number of bytes (expected %s, got %s)", wad, lump, sizeu1(l->size), sizeu2(retval));
 			}
-#else
-			(void)wad;
-			(void)lump;
-			//I_Error("ZWAD files not supported on this platform.");
-			return NULL;
-#endif
 			if (!decData) // Did we get no data at all?
 				return 0;
 			M_Memcpy(dest, decData + offset, size);
 			Z_Free(rawData);
 			Z_Free(decData);
 			return size;
+#else
+			//I_Error("ZWAD files not supported on this platform.");
+			return 0;
+#endif
 		}
 	case CM_DEFLATE: // Is it compressed via DEFLATE? Very common in ZIPs/PK3s, also what most doom-related editors support.
 		{
diff --git a/src/w_wad.h b/src/w_wad.h
index f067258849de2234076483753f33860116d0db61..ef4213579faf2120bda9b9459e79a9746b29f41c 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -78,12 +78,18 @@ typedef struct
 #endif
 
 // Resource type of the WAD. Yeah, I know this sounds dumb, but I'll leave it like this until I clean up the code further.
-enum restype {RET_WAD, RET_PK3};
+typedef enum restype
+{
+	RET_WAD,
+	RET_SOC,
+	RET_LUA,
+	RET_PK3
+} restype_t;
 
 typedef struct wadfile_s
 {
 	char *filename;
-	enum restype type;
+	restype_t type;
 	lumpinfo_t *lumpinfo;
 	lumpcache_t *lumpcache;
 #ifdef HWRENDER
@@ -133,6 +139,8 @@ UINT8 W_LumpExists(const char *name); // Lua uses this.
 size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump);
 size_t W_LumpLength(lumpnum_t lumpnum);
 
+boolean W_IsLumpWad(lumpnum_t lumpnum); // for loading maps from WADs in PK3s
+
 void zerr(int ret); // zlib error checking
 
 size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset);
diff --git a/src/z_zone.c b/src/z_zone.c
index a28ea87b035d3e0e7e5c7ca3ae7005aea541524e..b5799b583889f731bc5058699ba74d63bb462ce0 100644
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -82,6 +82,59 @@ typedef struct memblock_s
 	struct memblock_s *next, *prev;
 } ATTRPACK memblock_t;
 
+// both the head and tail of the zone memory block list
+static memblock_t head;
+
+//
+// Function prototypes
+//
+static void Command_Memfree_f(void);
+#ifdef ZDEBUG
+static void Command_Memdump_f(void);
+#endif
+
+// --------------------------
+// Zone memory initialisation
+// --------------------------
+
+/** Initialises zone memory.
+  * Used at game startup.
+  *
+  * \sa I_GetFreeMem, Command_Memfree_f, Command_Memdump_f
+  */
+void Z_Init(void)
+{
+	UINT32 total, memfree;
+
+	memset(&head, 0x00, sizeof(head));
+
+	head.next = head.prev = &head;
+
+	memfree = I_GetFreeMem(&total)>>20;
+	CONS_Printf("System memory: %uMB - Free: %uMB\n", total>>20, memfree);
+
+	// Note: This allocates memory. Watch out.
+	COM_AddCommand("memfree", Command_Memfree_f);
+
+#ifdef ZDEBUG
+	COM_AddCommand("memdump", Command_Memdump_f);
+#endif
+}
+
+
+// ----------------------
+// Zone memory allocation
+// ----------------------
+
+/** Returns the corresponding memblock_t for a given memory block.
+  *
+  * \param ptr A pointer to allocated memory,
+  *             assumed to have been allocated with Z_Malloc/Z_Calloc.
+  * \param func A string containing the name of the function that called this,
+  *              to be printed if the function I_Errors
+  * \return A pointer to the memblock_t for the given memory.
+  * \sa Z_Free, Z_ReallocAlign
+  */
 #ifdef ZDEBUG
 #define Ptr2Memblock(s, f) Ptr2Memblock2(s, f, __FILE__, __LINE__)
 static memblock_t *Ptr2Memblock2(void *ptr, const char* func, const char *file, INT32 line)
@@ -131,32 +184,12 @@ static memblock_t *Ptr2Memblock(void *ptr, const char* func)
 
 }
 
-static memblock_t head;
-
-static void Command_Memfree_f(void);
-#ifdef ZDEBUG
-static void Command_Memdump_f(void);
-#endif
-
-void Z_Init(void)
-{
-	UINT32 total, memfree;
-
-	memset(&head, 0x00, sizeof(head));
-
-	head.next = head.prev = &head;
-
-	memfree = I_GetFreeMem(&total)>>20;
-	CONS_Printf("System memory: %uMB - Free: %uMB\n", total>>20, memfree);
-
-	// Note: This allocates memory. Watch out.
-	COM_AddCommand("memfree", Command_Memfree_f);
-
-#ifdef ZDEBUG
-	COM_AddCommand("memdump", Command_Memdump_f);
-#endif
-}
-
+/** Frees allocated memory.
+  *
+  * \param ptr A pointer to allocated memory,
+  *             assumed to have been allocated with Z_Malloc/Z_Calloc.
+  * \sa Z_FreeTags
+  */
 #ifdef ZDEBUG
 void Z_Free2(void *ptr, const char *file, INT32 line)
 #else
@@ -206,7 +239,11 @@ void Z_Free(void *ptr)
 #endif
 }
 
-// malloc() that doesn't accept failure.
+/** malloc() that doesn't accept failure.
+  *
+  * \param size Amount of memory to be allocated, in bytes.
+  * \return A pointer to the allocated memory.
+  */
 static void *xm(size_t size)
 {
 	const size_t padedsize = size+sizeof (size_t);
@@ -227,10 +264,18 @@ static void *xm(size_t size)
 	return p;
 }
 
-// Z_Malloc
-// You can pass Z_Malloc() a NULL user if the tag is less than
-// PU_PURGELEVEL.
-
+/** The Z_MallocAlign function.
+  * Allocates a block of memory, adds it to a linked list so we can keep track of it.
+  *
+  * \param size Amount of memory to be allocated, in bytes.
+  * \param tag Purge tag.
+  * \param user The address of a pointer to the memory to be allocated.
+  *             When the memory is freed by Z_Free later,
+  *             the pointer at this address will then be automatically set to NULL.
+  * \param alignbits The alignment of the memory to be allocated, in bits. Can be 0.
+  * \note You can pass Z_Malloc() a NULL user if the tag is less than PU_PURGELEVEL.
+  * \sa Z_CallocAlign, Z_ReallocAlign
+  */
 #ifdef ZDEBUG
 void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits,
 	const char *file, INT32 line)
@@ -307,6 +352,19 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
 	return given;
 }
 
+/** The Z_CallocAlign function.
+  * Allocates a block of memory, adds it to a linked list so we can keep track of it.
+  * Unlike Z_MallocAlign, this also initialises the bytes to zero.
+  *
+  * \param size Amount of memory to be allocated, in bytes.
+  * \param tag Purge tag.
+  * \param user The address of a pointer to the memory to be allocated.
+  *             When the memory is freed by Z_Free later,
+  *             the pointer at this address will then be automatically set to NULL.
+  * \param alignbits The alignment of the memory to be allocated, in bits. Can be 0.
+  * \note You can pass Z_Calloc() a NULL user if the tag is less than PU_PURGELEVEL.
+  * \sa Z_MallocAlign, Z_ReallocAlign
+  */
 #ifdef ZDEBUG
 void *Z_Calloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line)
 #else
@@ -323,10 +381,26 @@ void *Z_CallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
 #endif
 }
 
+/** The Z_ReallocAlign function.
+  * Reallocates a block of memory with a new size.
+  *
+  * \param ptr A pointer to allocated memory,
+  *             assumed to have been allocated with Z_Malloc/Z_Calloc.
+  *             If NULL, this function instead acts as a wrapper for Z_CallocAlign.
+  * \param size New size of memory block, in bytes.
+  *             If zero, then the memory is freed and NULL is returned.
+  * \param tag New purge tag.
+  * \param user The address of a pointer to the memory to be reallocated.
+  *             This can be a different user to the one originally assigned to the memory block.
+  * \param alignbits The alignment of the memory to be allocated, in bits. Can be 0.
+  * \return A pointer to the reallocated memory. Can be NULL if memory was freed.
+  * \note You can pass Z_Realloc() a NULL user if the tag is less than PU_PURGELEVEL.
+  * \sa Z_MallocAlign, Z_CallocAlign
+  */
 #ifdef ZDEBUG
 void *Z_Realloc2(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line)
 #else
-void *Z_ReallocAlign(void *ptr, size_t size,INT32 tag, void *user,  INT32 alignbits)
+void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits)
 #endif
 {
 	void *rez;
@@ -393,6 +467,11 @@ void *Z_ReallocAlign(void *ptr, size_t size,INT32 tag, void *user,  INT32 alignb
 	return rez;
 }
 
+/** Frees all memory for a given set of tags.
+  *
+  * \param lowtag The lowest tag to consider.
+  * \param hightag The highest tag to consider.
+  */
 void Z_FreeTags(INT32 lowtag, INT32 hightag)
 {
 	memblock_t *block, *next;
@@ -407,22 +486,25 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag)
 	}
 }
 
-//
-// Z_CheckMemCleanup
-//
-// TODO: Currently blocks >= PU_PURGELEVEL are freed every
-// CLEANUPCOUNT. It might be better to keep track of
-// the total size of all purgable memory and free it when the
-// size exceeds some value.
-//
-// This was in Z_Malloc, but was freeing data at
-// unsafe times. Now it is only called when it is safe
-// to cleanup memory.
+// -----------------
+// Utility functions
+// -----------------
 
+// starting value of nextcleanup
 #define CLEANUPCOUNT 2000
 
+// number of function calls left before next cleanup
 static INT32 nextcleanup = CLEANUPCOUNT;
 
+/** This was in Z_Malloc, but was freeing data at
+  * unsafe times. Now it is only called when it is safe
+  * to cleanup memory.
+  *
+  * \todo Currently blocks >= PU_PURGELEVEL are freed every
+  *       CLEANUPCOUNT. It might be better to keep track of
+  *       the total size of all purgable memory and free it when the
+  *       size exceeds some value.
+  */
 void Z_CheckMemCleanup(void)
 {
 	if (nextcleanup-- == 0)
@@ -538,10 +620,21 @@ void Z_CheckHeap(INT32 i)
 	}
 }
 
+// ------------------------
+// Zone memory modification
+// ------------------------
+
+/** Changes a memory block's purge tag.
+  *
+  * \param ptr A pointer to allocated memory,
+  *             assumed to have been allocated with Z_Malloc/Z_Calloc.
+  * \param tag The new tag.
+  * \sa Z_SetUser
+  */
 #ifdef PARANOIA
 void Z_ChangeTag2(void *ptr, INT32 tag, const char *file, INT32 line)
 #else
-void Z_ChangeTag2(void *ptr, INT32 tag)
+void Z_ChangeTag(void *ptr, INT32 tag)
 #endif
 {
 	memblock_t *block;
@@ -583,12 +676,59 @@ void Z_ChangeTag2(void *ptr, INT32 tag)
 	block->tag = tag;
 }
 
+/** Changes a memory block's user.
+  *
+  * \param ptr A pointer to allocated memory,
+  *             assumed to have been allocated with Z_Malloc/Z_Calloc.
+  * \param newuser The new user for the memory block.
+  * \sa Z_ChangeTag
+  */
+#ifdef PARANOIA
+void Z_SetUser2(void *ptr, void **newuser, const char *file, INT32 line)
+#else
+void Z_SetUser(void *ptr, void **newuser)
+#endif
+{
+	memblock_t *block;
+	memhdr_t *hdr;
+
+	if (ptr == NULL)
+		return;
+
+	hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr);
+
+#ifdef VALGRIND_MAKE_MEM_DEFINED
+	VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
+#endif
+
+#ifdef PARANOIA
+	if (hdr->id != ZONEID) I_Error("Z_CT at %s:%d: wrong id", file, line);
+#endif
+
+	block = hdr->block;
+
+#ifdef VALGRIND_MAKE_MEM_NOACCESS
+	VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
+#endif
+
+	if (block->tag >= PU_PURGELEVEL && newuser == NULL)
+		I_Error("Internal memory management error: "
+			"tried to make block purgable but it has no owner");
+
+	block->user = (void*)newuser;
+	*newuser = ptr;
+}
+
+// -----------------
+// Zone memory usage
+// -----------------
+
 /** Calculates memory usage for a given set of tags.
+  *
   * \param lowtag The lowest tag to consider.
   * \param hightag The highest tag to consider.
   * \return Number of bytes currently allocated in the heap for the
   *         given tags.
-  * \sa Z_TagUsage
   */
 size_t Z_TagsUsage(INT32 lowtag, INT32 hightag)
 {
@@ -605,18 +745,20 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag)
 	return cnt;
 }
 
-size_t Z_TagUsage(INT32 tagnum)
-{
-	return Z_TagsUsage(tagnum, tagnum);
-}
+// -----------------------
+// Miscellaneous functions
+// -----------------------
 
-void Command_Memfree_f(void)
+/** The function called by the "memfree" console command.
+  * Prints the memory being used by each part of the game to the console.
+  */
+static void Command_Memfree_f(void)
 {
 	UINT32 freebytes, totalbytes;
 
 	Z_CheckHeap(-1);
 	CONS_Printf("\x82%s", M_GetText("Memory Info\n"));
-	CONS_Printf(M_GetText("Total heap used   : %7s KB\n"), sizeu1(Z_TagsUsage(0, INT32_MAX)>>10));
+	CONS_Printf(M_GetText("Total heap used   : %7s KB\n"), sizeu1(Z_TotalUsage()>>10));
 	CONS_Printf(M_GetText("Static            : %7s KB\n"), sizeu1(Z_TagUsage(PU_STATIC)>>10));
 	CONS_Printf(M_GetText("Static (sound)    : %7s KB\n"), sizeu1(Z_TagUsage(PU_SOUND)>>10));
 	CONS_Printf(M_GetText("Static (music)    : %7s KB\n"), sizeu1(Z_TagUsage(PU_MUSIC)>>10));
@@ -644,6 +786,11 @@ void Command_Memfree_f(void)
 }
 
 #ifdef ZDEBUG
+/** The function called by the "memdump" console command.
+  * Prints zone memory debugging information (i.e. tag, size, location in code allocated).
+  * Can be all memory allocated in game, or between a set of tags (if -min/-max args used).
+  * This command is available only if ZDEBUG is enabled.
+  */
 static void Command_Memdump_f(void)
 {
 	memblock_t *block;
@@ -665,45 +812,12 @@ static void Command_Memdump_f(void)
 }
 #endif
 
-// Creates a copy of a string.
+/** Creates a copy of a string.
+  *
+  * \param s The string to be copied.
+  * \return A copy of the string, allocated in zone memory.
+  */
 char *Z_StrDup(const char *s)
 {
 	return strcpy(ZZ_Alloc(strlen(s) + 1), s);
 }
-
-
-#ifdef PARANOIA
-void Z_SetUser2(void *ptr, void **newuser, const char *file, INT32 line)
-#else
-void Z_SetUser2(void *ptr, void **newuser)
-#endif
-{
-	memblock_t *block;
-	memhdr_t *hdr;
-
-	if (ptr == NULL)
-		return;
-
-	hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr);
-
-#ifdef VALGRIND_MAKE_MEM_DEFINED
-	VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
-#endif
-
-#ifdef PARANOIA
-	if (hdr->id != ZONEID) I_Error("Z_CT at %s:%d: wrong id", file, line);
-#endif
-
-	block = hdr->block;
-
-#ifdef VALGRIND_MAKE_MEM_NOACCESS
-	VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr);
-#endif
-
-	if (block->tag >= PU_PURGELEVEL && newuser == NULL)
-		I_Error("Internal memory management error: "
-			"tried to make block purgable but it has no owner");
-
-	block->user = (void*)newuser;
-	*newuser = ptr;
-}
diff --git a/src/z_zone.h b/src/z_zone.h
index 552fd87baeb8556611cf38e8c2eec4b24f44a188..205c9ed791060b8e312d71554817b324a521e107 100644
--- a/src/z_zone.h
+++ b/src/z_zone.h
@@ -30,92 +30,115 @@
 //#define ZDEBUG
 
 //
-// ZONE MEMORY
-// PU - purge tags.
-// Tags < PU_LEVEL are not purged until freed explicitly.
-#define PU_STATIC               1 // static entire execution time
-#define PU_LUA                  2 // static entire execution time -- used by lua so it doesn't get caught in loops forever
-
-#define PU_SOUND               11 // static while playing
-#define PU_MUSIC               12 // static while playing
-#define PU_HUDGFX              13 // static until WAD added
-
-#define PU_HWRPATCHINFO        21 // Hardware GLPatch_t struct for OpenGL texture cache
-#define PU_HWRPATCHCOLMIPMAP   22 // Hardware GLMipmap_t struct colromap variation of patch
-
-#define PU_HWRCACHE            48 // static until unlocked
-#define PU_CACHE               49 // static until unlocked
-
-// Tags s.t. PU_LEVEL <= tag < PU_PURGELEVEL are purged at level start
-#define PU_LEVEL               50 // static until level exited
-#define PU_LEVSPEC             51 // a special thinker in a level
-#define PU_HWRPLANE            52
-
-// Tags >= PU_PURGELEVEL are purgable whenever needed
-#define PU_PURGELEVEL         100
-#define PU_CACHE_UNLOCKED     101
-#define PU_HWRCACHE_UNLOCKED  102 // 'second-level' cache for graphics
-                                  // stored in hardware format and downloaded as needed
-#define PU_HWRPATCHINFO_UNLOCKED 103
+// Purge tags
+//
+// Now they are an enum! -- Monster Iestyn 15/02/18
+//
+enum
+{
+	// Tags < PU_LEVEL are not purged until freed explicitly.
+	PU_STATIC                = 1, // static entire execution time
+	PU_LUA                   = 2, // static entire execution time -- used by lua so it doesn't get caught in loops forever
+
+	PU_SOUND                 = 11, // static while playing
+	PU_MUSIC                 = 12, // static while playing
+	PU_HUDGFX                = 13, // static until WAD added
+
+	PU_HWRPATCHINFO          = 21, // Hardware GLPatch_t struct for OpenGL texture cache
+	PU_HWRPATCHCOLMIPMAP     = 22, // Hardware GLMipmap_t struct colormap variation of patch
+
+	PU_HWRCACHE              = 48, // static until unlocked
+	PU_CACHE                 = 49, // static until unlocked
+
+	// Tags s.t. PU_LEVEL <= tag < PU_PURGELEVEL are purged at level start
+	PU_LEVEL                 = 50, // static until level exited
+	PU_LEVSPEC               = 51, // a special thinker in a level
+	PU_HWRPLANE              = 52, // if ZPLANALLOC is enabled in hw_bsp.c, this is used to alloc polygons for OpenGL
+
+	// Tags >= PU_PURGELEVEL are purgable whenever needed
+	PU_PURGELEVEL            = 100, // Note: this is never actually used as a tag
+	PU_CACHE_UNLOCKED        = 101, // Note: unused
+	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
+};
 
+//
+// Zone memory initialisation
+//
 void Z_Init(void);
-void Z_FreeTags(INT32 lowtag, INT32 hightag);
-void Z_CheckMemCleanup(void);
-void Z_CheckHeap(INT32 i);
-#ifdef PARANOIA
-void Z_ChangeTag2(void *ptr, INT32 tag, const char *file, INT32 line);
-#else
-void Z_ChangeTag2(void *ptr, INT32 tag);
-#endif
 
-#ifdef PARANOIA
-void Z_SetUser2(void *ptr, void **newuser, const char *file, INT32 line);
-#else
-void Z_SetUser2(void *ptr, void **newuser);
-#endif
+//
+// Zone memory allocation
+//
+// enable ZDEBUG to get the file + line the functions were called from
+// for ZZ_Alloc, see doomdef.h
+//
 
+// Z_Free and alloc with alignment
 #ifdef ZDEBUG
-#define Z_Free(p) Z_Free2(p, __FILE__, __LINE__)
+#define Z_Free(p)                 Z_Free2(p, __FILE__, __LINE__)
+#define Z_MallocAlign(s,t,u,a)    Z_Malloc2(s, t, u, a, __FILE__, __LINE__)
+#define Z_CallocAlign(s,t,u,a)    Z_Calloc2(s, t, u, a, __FILE__, __LINE__)
+#define Z_ReallocAlign(p,s,t,u,a) Z_Realloc2(p,s, t, u, a, __FILE__, __LINE__)
 void Z_Free2(void *ptr, const char *file, INT32 line);
-#define Z_Malloc(s,t,u) Z_Malloc2(s, t, u, 0, __FILE__, __LINE__)
-#define Z_MallocAlign(s,t,u,a) Z_Malloc2(s, t, u, a, __FILE__, __LINE__)
 void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) FUNCALLOC(1);
-#define Z_Calloc(s,t,u) Z_Calloc2(s, t, u, 0, __FILE__, __LINE__)
-#define Z_CallocAlign(s,t,u,a) Z_Calloc2(s, t, u, a, __FILE__, __LINE__)
 void *Z_Calloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) FUNCALLOC(1);
-#define Z_Realloc(p,s,t,u) Z_Realloc2(p, s, t, u, 0, __FILE__, __LINE__)
-#define Z_ReallocAlign(p,s,t,u,a) Z_Realloc2(p,s, t, u, a, __FILE__, __LINE__)
 void *Z_Realloc2(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) FUNCALLOC(2);
 #else
 void Z_Free(void *ptr);
 void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(1);
-#define Z_Malloc(s,t,u) Z_MallocAlign(s, t, u, 0)
 void *Z_CallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(1);
-#define Z_Calloc(s,t,u) Z_CallocAlign(s, t, u, 0)
-void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(2) ;
-#define Z_Realloc(p, s,t,u) Z_ReallocAlign(p, s, t, u, 0)
+void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(2);
 #endif
 
-size_t Z_TagUsage(INT32 tagnum);
-size_t Z_TagsUsage(INT32 lowtag, INT32 hightag);
+// Alloc with no alignment
+#define Z_Malloc(s,t,u)    Z_MallocAlign(s, t, u, 0)
+#define Z_Calloc(s,t,u)    Z_CallocAlign(s, t, u, 0)
+#define Z_Realloc(p,s,t,u) Z_ReallocAlign(p, s, t, u, 0)
 
-char *Z_StrDup(const char *in);
+// Free all memory by tag
+// these don't give line numbers for ZDEBUG currently though
+// (perhaps this should be changed in future?)
+#define Z_FreeTag(tagnum) Z_FreeTags(tagnum, tagnum)
+void Z_FreeTags(INT32 lowtag, INT32 hightag);
 
-// This is used to get the local FILE : LINE info from CPP
-// prior to really call the function in question.
+//
+// Utility functions
+//
+void Z_CheckMemCleanup(void);
+void Z_CheckHeap(INT32 i);
+
+//
+// Zone memory modification
+//
+// enable PARANOIA to get the file + line the functions were called from
 //
 #ifdef PARANOIA
 #define Z_ChangeTag(p,t) Z_ChangeTag2(p, t, __FILE__, __LINE__)
+#define Z_SetUser(p,u)   Z_SetUser2(p, u, __FILE__, __LINE__)
+void Z_ChangeTag2(void *ptr, INT32 tag, const char *file, INT32 line);
+void Z_SetUser2(void *ptr, void **newuser, const char *file, INT32 line);
 #else
-#define Z_ChangeTag(p,t) Z_ChangeTag2(p, t)
+void Z_ChangeTag(void *ptr, INT32 tag);
+void Z_SetUser(void *ptr, void **newuser);
 #endif
 
-#ifdef PARANOIA
-#define Z_SetUser(p,u) Z_SetUser2(p, u, __FILE__, __LINE__)
-#else
-#define Z_SetUser(p,u) Z_SetUser2(p, u)
-#endif
+//
+// Zone memory usage
+//
+// Note: These give the memory used in bytes,
+// shift down by 10 to convert to KB
+//
+#define Z_TagUsage(tagnum) Z_TagsUsage(tagnum, tagnum)
+size_t Z_TagsUsage(INT32 lowtag, INT32 hightag);
+#define Z_TotalUsage() Z_TagsUsage(0, INT32_MAX)
 
-#define Z_Unlock(p) (void)p
+//
+// Miscellaneous functions
+//
+char *Z_StrDup(const char *in);
+#define Z_Unlock(p) (void)p // TODO: remove this now that NDS code has been removed
 
 #endif