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/dehacked.c b/src/dehacked.c
index 97c1cef03a8c3a8fb1e071867651eb3c68d2e03d..77a48b429c1ea5777bd46fa2fd119e34fc0fc62c 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -1820,7 +1820,6 @@ static void readframe(MYFILE *f, INT32 num)
 	char *word1;
 	char *word2 = NULL;
 	char *tmp;
-	INT32 j;
 
 	do
 	{
@@ -1835,16 +1834,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 78fc31afccceb1397b08bc40bc3a17e247ff0d89..beda40391e9d0b43ceea9b04af5b716d4e7f468f 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -581,8 +581,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
 
@@ -629,8 +629,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/sdl/i_system.c b/src/sdl/i_system.c
index 1776ff45033a2ff6666c39d132c08f1dd1696b70..c8fcd080ebd42aa5f989c60875e0cd2f4bbe1aec 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -2693,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:"
@@ -2713,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);
@@ -2747,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;
@@ -2763,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;
 	}
 
@@ -2796,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/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