diff --git a/src/doomdef.h b/src/doomdef.h
index d13ff9bc04542a69d3a9fae40b506bd63fa077b4..6c4f1fef3258a8c0eaac31587798b91d86112890 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -628,8 +628,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 #define ROTANGLES 24	// Needs to be a divisor of 360 (45, 60, 90, 120...)
 #define ROTANGDIFF (360 / ROTANGLES)
 
+/// PNG support
 #ifndef HAVE_PNG
 #define NO_PNG_LUMPS
 #endif
 
+/// Render flats on walls
+#define WALLFLATS
+
 #endif // __DOOMDEF__
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 44fc7600e803bc853b7f0c4115c87733b971cb87..ea16fb6d740626aa1f97a67be7d76041fa011d95 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -33,10 +33,6 @@
 #include "../r_patch.h"
 #include "../p_setup.h"
 
-//Hurdler: 25/04/2000: used for new colormap code in hardware mode
-//static UINT8 *gr_colormap = NULL; // by default it must be NULL ! (because colormap tables are not initialized)
-boolean firetranslucent = false;
-
 // Values set after a call to HWR_ResizeBlock()
 static INT32 blocksize, blockwidth, blockheight;
 
@@ -122,18 +118,16 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
 
 			texel = source[yfrac>>FRACBITS];
 
-			if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel))
-				alpha = 0x80;
-			else
-				alpha = 0xff;
-
-			//Hurdler: not perfect, but better than holes
-			if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED))
-				texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX;
 			//Hurdler: 25/04/2000: now support colormap in hardware mode
-			else if (mipmap->colormap)
+			if (mipmap->colormap)
 				texel = mipmap->colormap[texel];
 
+			// transparent pixel
+			if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)
+				alpha = 0x00;
+			else
+				alpha = 0xff;
+
 			// hope compiler will get this switch out of the loops (dreams...)
 			// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
 			// Alam: SRB2 uses Mingw, HUGS
@@ -236,18 +230,16 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
 
 			texel = source[yfrac>>FRACBITS];
 
-			if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel))
-				alpha = 0x80;
-			else
-				alpha = 0xff;
-
-			//Hurdler: not perfect, but better than holes
-			if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED))
-				texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX;
 			//Hurdler: 25/04/2000: now support colormap in hardware mode
-			else if (mipmap->colormap)
+			if (mipmap->colormap)
 				texel = mipmap->colormap[texel];
 
+			// transparent pixel
+			if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)
+				alpha = 0x00;
+			else
+				alpha = 0xff;
+
 			// hope compiler will get this switch out of the loops (dreams...)
 			// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
 			// Alam: SRB2 uses Mingw, HUGS
@@ -576,7 +568,7 @@ static UINT8 *MakeBlock(GLMipmap_t *grMipmap)
 {
 	UINT8 *block;
 	INT32 bpp, i;
-	UINT16 bu16 = ((0x00 <<8) | HWR_CHROMAKEY_EQUIVALENTCOLORINDEX);
+	UINT16 bu16 = ((0x00 <<8) | HWR_PATCHES_CHROMAKEY_COLORINDEX);
 
 	bpp =  format2bpp[grMipmap->grInfo.format];
 	block = Z_Malloc(blocksize*bpp, PU_HWRCACHE, &(grMipmap->grInfo.data));
@@ -606,6 +598,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex)
 	texture_t *texture;
 	texpatch_t *patch;
 	patch_t *realpatch;
+	UINT8 *pdata;
 
 	INT32 i;
 	boolean skyspecial = false; //poor hack for Legacy large skies..
@@ -638,7 +631,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex)
 		INT32 j;
 		RGBA_t col;
 
-		col = V_GetColor(HWR_CHROMAKEY_EQUIVALENTCOLORINDEX);
+		col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX);
 		for (j = 0; j < blockheight; j++)
 		{
 			for (i = 0; i < blockwidth; i++)
@@ -654,19 +647,30 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex)
 	// Composite the columns together.
 	for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
 	{
-#ifndef NO_PNG_LUMPS
+		boolean dealloc = true;
 		size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump);
-#endif
-		realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
+		pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
+		realpatch = (patch_t *)pdata;
+
 #ifndef NO_PNG_LUMPS
 		if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
 			realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false);
+		else
 #endif
-		HWR_DrawTexturePatchInCache(&grtex->mipmap,
-		                     blockwidth, blockheight,
-		                     texture, patch,
-		                     realpatch);
-		Z_Unlock(realpatch);
+#ifdef WALLFLATS
+		if (texture->type == TEXTURETYPE_FLAT)
+			realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false);
+		else
+#endif
+		{
+			(void)lumplength;
+			dealloc = false;
+		}
+
+		HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch);
+
+		if (dealloc)
+			Z_Unlock(realpatch);
 	}
 	//Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
 	if (format2bpp[grtex->mipmap.grInfo.format]==4)
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 979093dc87d6dd9e0b97aa5dde2efd60442e5581..5f2d907bdee607d0b74051bad5f99baf5d0da823 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -42,7 +42,7 @@ typedef unsigned char   FBOOLEAN;
 
 // byte value for paletted graphics, which represent the transparent color
 #define HWR_PATCHES_CHROMAKEY_COLORINDEX   255
-#define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 130
+//#define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 130
 
 // the chroma key color shows on border sprites, set it to black
 #define HWR_PATCHES_CHROMAKEY_COLORVALUE     (0x00000000)    //RGBA format as in grSstWinOpen()
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index d25f6cefd931f51f88c166fa8d2be4a60059f830..cf98e731739ce59016dd6347f531a1079c59f813 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -128,6 +128,5 @@ extern consvar_t cv_grrounddown; // on/off
 
 extern INT32 patchformat;
 extern INT32 textureformat;
-extern boolean firetranslucent;
 
 #endif //_HW_GLOB_
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 06d8aa3f54b5378a7ba1f063cb42781debda19ed..459a7c0034aa794cb7090b10160606a886623241 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -11595,13 +11595,21 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t*
 	case MT_EMERALDSPAWN:
 	case MT_TOKEN:
 	case MT_EMBLEM:
+	case MT_RING:
+	case MT_REDTEAMRING:
+	case MT_BLUETEAMRING:
+	case MT_COIN:
+	case MT_BLUESPHERE:
+	case MT_BOMBSPHERE:
+	case MT_NIGHTSCHIP:
+	case MT_NIGHTSSTAR:
 		offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0;
 		break;
 
 	// Remaining objects.
 	default:
 		if (P_WeaponOrPanel(mobjtype))
-			offset += mthing->options & MTF_AMBUSH ? 24 * FRACUNIT : 0;
+			offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0;
 	}
 
 	if (!offset) // Snap to the surfaces when there's no offset set.
@@ -13056,557 +13064,371 @@ ML_EFFECT5 : Don't stop thinking when too far away
 	mthing->mobj = mobj;
 }
 
-void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
+static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sector_t* sec, INT32 hoopsize, fixed_t sizefactor)
 {
-	mobjtype_t ringthing = MT_RING;
 	mobj_t *mobj = NULL;
-	INT32 r, i;
-	fixed_t x, y, z, finalx, finaly, finalz;
-	sector_t *sec;
+	mobj_t *nextmobj = NULL;
+	mobj_t *hoopcenter;
+	TMatrix *pitchmatrix, *yawmatrix;
+	fixed_t radius = hoopsize*sizefactor;
+	INT32 i;
+	angle_t fa;
 	TVector v, *res;
-	angle_t closestangle, fa;
-	boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
-
-	x = mthing->x << FRACBITS;
-	y = mthing->y << FRACBITS;
 
-	sec = R_PointInSubsector(x, y)->sector;
-
-	// NiGHTS hoop!
-	if (mthing->type == 1705)
-	{
-		mobj_t *nextmobj = NULL;
-		mobj_t *hoopcenter;
-		INT16 spewangle;
-
-		z = mthing->z << FRACBITS;
-
-		hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
-
-		hoopcenter->spawnpoint = mthing;
-
-		// Screw these damn hoops, I need this thinker.
-		//hoopcenter->flags |= MF_NOTHINK;
-
-		z +=
+	z +=
 #ifdef ESLOPE
-			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+		sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
-			sec->floorheight;
-
-		hoopcenter->z = z - hoopcenter->height/2;
-
-		P_UnsetThingPosition(hoopcenter);
-		hoopcenter->x = x;
-		hoopcenter->y = y;
-		P_SetThingPosition(hoopcenter);
+		sec->floorheight;
 
-		// Scale 0-255 to 0-359 =(
-		closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT,
-			360*(FRACUNIT/256)));
+	hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
+	hoopcenter->spawnpoint = mthing;
+	hoopcenter->z -= hoopcenter->height/2;
 
-		hoopcenter->movedir = FixedInt(FixedMul((mthing->angle&255)*FRACUNIT,
-			360*(FRACUNIT/256)));
-		hoopcenter->movecount = FixedInt(AngleFixed(closestangle));
+	P_UnsetThingPosition(hoopcenter);
+	hoopcenter->x = x;
+	hoopcenter->y = y;
+	P_SetThingPosition(hoopcenter);
 
-		// For the hoop when it flies away
-		hoopcenter->extravalue1 = 32;
-		hoopcenter->extravalue2 = 8 * FRACUNIT;
+	// Scale 0-255 to 0-359 =(
+	hoopcenter->movedir = ((mthing->angle & 255)*360)/256; // Pitch
+	pitchmatrix = RotateXMatrix(FixedAngle(hoopcenter->movedir << FRACBITS));
+	hoopcenter->movecount = (((UINT16)mthing->angle >> 8)*360)/256; // Yaw
+	yawmatrix = RotateZMatrix(FixedAngle(hoopcenter->movecount << FRACBITS));
 
-		spewangle = (INT16)hoopcenter->movedir;
+	// For the hoop when it flies away
+	hoopcenter->extravalue1 = hoopsize;
+	hoopcenter->extravalue2 = radius/12;
 
-		// Create the hoop!
-		for (i = 0; i < 32; i++)
-		{
-			fa = i*(FINEANGLES/32);
-			v[0] = FixedMul(FINECOSINE(fa),96*FRACUNIT);
-			v[1] = 0;
-			v[2] = FixedMul(FINESINE(fa),96*FRACUNIT);
-			v[3] = FRACUNIT;
-
-			res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
-			M_Memcpy(&v, res, sizeof (v));
-			res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
-			M_Memcpy(&v, res, sizeof (v));
-
-			finalx = x + v[0];
-			finaly = y + v[1];
-			finalz = z + v[2];
-
-			mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP);
+	// Create the hoop!
+	for (i = 0; i < hoopsize; i++)
+	{
+		fa = i*(FINEANGLES/hoopsize);
+		v[0] = FixedMul(FINECOSINE(fa), radius);
+		v[1] = 0;
+		v[2] = FixedMul(FINESINE(fa), radius);
+		v[3] = FRACUNIT;
 
-			if (maptol & TOL_XMAS)
-				P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
+		res = VectorMatrixMultiply(v, *pitchmatrix);
+		M_Memcpy(&v, res, sizeof(v));
+		res = VectorMatrixMultiply(v, *yawmatrix);
+		M_Memcpy(&v, res, sizeof(v));
 
-			mobj->z -= mobj->height/2;
-			P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
-			mobj->fuse = 0;
+		mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOP);
+		mobj->z -= mobj->height/2;
 
-			// Link all the sprites in the hoop together
-			if (nextmobj)
-			{
-				P_SetTarget(&mobj->hprev, nextmobj);
-				P_SetTarget(&mobj->hprev->hnext, mobj);
-			}
-			else
-				P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
+		if (maptol & TOL_XMAS)
+			P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
 
-			nextmobj = mobj;
-		}
+		P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
+		mobj->fuse = 0;
 
-		// Create the collision detectors!
-		for (i = 0; i < 16; i++)
+		// Link all the sprites in the hoop together
+		if (nextmobj)
 		{
-			fa = i*FINEANGLES/16;
-			v[0] = FixedMul(FINECOSINE(fa),32*FRACUNIT);
-			v[1] = 0;
-			v[2] = FixedMul(FINESINE(fa),32*FRACUNIT);
-			v[3] = FRACUNIT;
-			res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
-			M_Memcpy(&v, res, sizeof (v));
-			res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
-			M_Memcpy(&v, res, sizeof (v));
-
-			finalx = x + v[0];
-			finaly = y + v[1];
-			finalz = z + v[2];
-
-			mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE);
-			mobj->z -= mobj->height/2;
-
-			// Link all the collision sprites together.
-			P_SetTarget(&mobj->hnext, NULL);
 			P_SetTarget(&mobj->hprev, nextmobj);
 			P_SetTarget(&mobj->hprev->hnext, mobj);
-
-			nextmobj = mobj;
 		}
-		// Create the collision detectors!
-		for (i = 0; i < 16; i++)
-		{
-			fa = i*FINEANGLES/16;
-			v[0] = FixedMul(FINECOSINE(fa),64*FRACUNIT);
-			v[1] = 0;
-			v[2] = FixedMul(FINESINE(fa),64*FRACUNIT);
-			v[3] = FRACUNIT;
-			res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
-			M_Memcpy(&v, res, sizeof (v));
-			res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
-			M_Memcpy(&v, res, sizeof (v));
-
-			finalx = x + v[0];
-			finaly = y + v[1];
-			finalz = z + v[2];
-
-			mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE);
-			mobj->z -= mobj->height/2;
-
-			// Link all the collision sprites together.
-			P_SetTarget(&mobj->hnext, NULL);
-			P_SetTarget(&mobj->hprev, nextmobj);
-			P_SetTarget(&mobj->hprev->hnext, mobj);
+		else
+			P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
 
-			nextmobj = mobj;
-		}
-		return;
+		nextmobj = mobj;
 	}
-	// CUSTOMIZABLE NiGHTS hoop!
-	else if (mthing->type == 1713)
-	{
-		mobj_t *nextmobj = NULL;
-		mobj_t *hoopcenter;
-		INT16 spewangle;
-		INT32 hoopsize;
-		INT32 hoopplacement;
-
-		z = mthing->z << FRACBITS;
-
-		hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
-		hoopcenter->spawnpoint = mthing;
-
-		z +=
-#ifdef ESLOPE
-			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
-#endif
-			sec->floorheight;
-		hoopcenter->z = z - hoopcenter->height/2;
 
-		P_UnsetThingPosition(hoopcenter);
-		hoopcenter->x = x;
-		hoopcenter->y = y;
-		P_SetThingPosition(hoopcenter);
-
-		// Scale 0-255 to 0-359 =(
-		closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT,
-			360*(FRACUNIT/256)));
-
-		hoopcenter->movedir = FixedInt(FixedMul((mthing->angle&255)*FRACUNIT,
-			360*(FRACUNIT/256)));
-		hoopcenter->movecount = FixedInt(AngleFixed(closestangle));
-
-		spewangle = (INT16)hoopcenter->movedir;
-
-		// Super happy fun time
-		// For each flag add 4 fracunits to the size
-		// Default (0 flags) is 8 fracunits
-		hoopsize = 8 + (4 * (mthing->options & 0xF));
-		hoopplacement = hoopsize * (4*FRACUNIT);
+	// Create the collision detectors!
+	// Create them until the size is less than 8
+	// But always create at least ONE set of collision detectors
+	do
+	{
+		if (hoopsize >= 32)
+			hoopsize -= 16;
+		else
+			hoopsize /= 2;
 
-		// For the hoop when it flies away
-		hoopcenter->extravalue1 = hoopsize;
-		hoopcenter->extravalue2 = FixedDiv(hoopplacement, 12*FRACUNIT);
+		radius = hoopsize*sizefactor;
 
-		// Create the hoop!
 		for (i = 0; i < hoopsize; i++)
 		{
 			fa = i*(FINEANGLES/hoopsize);
-			v[0] = FixedMul(FINECOSINE(fa), hoopplacement);
+			v[0] = FixedMul(FINECOSINE(fa), radius);
 			v[1] = 0;
-			v[2] = FixedMul(FINESINE(fa), hoopplacement);
+			v[2] = FixedMul(FINESINE(fa), radius);
 			v[3] = FRACUNIT;
 
-			res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
-			M_Memcpy(&v, res, sizeof (v));
-			res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
-			M_Memcpy(&v, res, sizeof (v));
-
-			finalx = x + v[0];
-			finaly = y + v[1];
-			finalz = z + v[2];
-
-			mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP);
-
-			if (maptol & TOL_XMAS)
-				P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
+			res = VectorMatrixMultiply(v, *pitchmatrix);
+			M_Memcpy(&v, res, sizeof(v));
+			res = VectorMatrixMultiply(v, *yawmatrix);
+			M_Memcpy(&v, res, sizeof(v));
 
+			mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOPCOLLIDE);
 			mobj->z -= mobj->height/2;
-			P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
-			mobj->fuse = 0;
 
-			// Link all the sprites in the hoop together
-			if (nextmobj)
-			{
-				P_SetTarget(&mobj->hprev, nextmobj);
-				P_SetTarget(&mobj->hprev->hnext, mobj);
-			}
-			else
-				P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
+			// Link all the collision sprites together.
+			P_SetTarget(&mobj->hnext, NULL);
+			P_SetTarget(&mobj->hprev, nextmobj);
+			P_SetTarget(&mobj->hprev->hnext, mobj);
 
 			nextmobj = mobj;
 		}
+	} while (hoopsize >= 8);
+}
 
-		// Create the collision detectors!
-		// Create them until the size is less than 8
-		// But always create at least ONE set of collision detectors
-		do
-		{
-			if (hoopsize >= 32)
-				hoopsize -= 16;
-			else
-				hoopsize /= 2;
-
-			hoopplacement = hoopsize * (4*FRACUNIT);
-
-			for (i = 0; i < hoopsize; i++)
-			{
-				fa = i*FINEANGLES/hoopsize;
-				v[0] = FixedMul(FINECOSINE(fa), hoopplacement);
-				v[1] = 0;
-				v[2] = FixedMul(FINESINE(fa), hoopplacement);
-				v[3] = FRACUNIT;
-				res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
-				M_Memcpy(&v, res, sizeof (v));
-				res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
-				M_Memcpy(&v, res, sizeof (v));
-
-				finalx = x + v[0];
-				finaly = y + v[1];
-				finalz = z + v[2];
-
-				mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE);
-				mobj->z -= mobj->height/2;
-
-				// Link all the collision sprites together.
-				P_SetTarget(&mobj->hnext, NULL);
-				P_SetTarget(&mobj->hprev, nextmobj);
-				P_SetTarget(&mobj->hprev->hnext, mobj);
-
-				nextmobj = mobj;
-			}
-		} while (hoopsize >= 8);
-
-		return;
-	}
-	// ***
-	// Special placement patterns
-	// ***
+static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime, boolean nightsreplace)
+{
+	mobjtype_t ringthing = MT_RING;
+	mobj_t *mobj = NULL;
+	fixed_t z;
 
-	// Vertical Rings - Stack of 5 (handles both red and yellow)
-	else if (mthing->type == 600 || mthing->type == 601)
+	// Which ringthing to use
+	if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum)
+		ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
+	else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum)
+		ringthing = MT_BOMBSPHERE;
+	else
 	{
-		INT32 dist = 64*FRACUNIT;
-		if (mthing->type == 601)
-			dist = 128*FRACUNIT;
-
 		if (ultimatemode)
 			return; // No rings in Ultimate!
 
 		if (nightsreplace)
 			ringthing = MT_NIGHTSSTAR;
+		else if (mthing->type == mobjinfo[MT_COIN].doomednum)
+			ringthing = MT_COIN;
+		else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF
+			ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING;
+		else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto
+			ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING;
+	}
 
-		if (mthing->options & MTF_OBJECTFLIP)
-		{
-			z = (
-#ifdef ESLOPE
-				sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
-#endif
-				sec->ceilingheight) - mobjinfo[ringthing].height;
-			if (mthing->z)
-				z -= (mthing->z << FRACBITS);
-			}
-		else
-		{
-			z = (
-#ifdef ESLOPE
-				sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
-#endif
-				sec->floorheight);
-			if (mthing->z)
-				z += (mthing->z << FRACBITS);
-		}
-
-		for (r = 1; r <= 5; r++)
-		{
-			if (mthing->options & MTF_OBJECTFLIP)
-				z -= dist;
-			else
-				z += dist;
+	z = P_GetMobjSpawnHeight(ringthing, mthing, x, y);
+	mobj = P_SpawnMobj(x, y, z, ringthing);
+	mobj->spawnpoint = mthing;
 
-			mobj = P_SpawnMobj(x, y, z, ringthing);
+	if (mthing->options & MTF_OBJECTFLIP)
+	{
+		mobj->eflags |= MFE_VERTICALFLIP;
+		mobj->flags2 |= MF2_OBJECTFLIP;
+	}
 
-			if (mthing->options & MTF_OBJECTFLIP)
-			{
-				mobj->eflags |= MFE_VERTICALFLIP;
-				mobj->flags2 |= MF2_OBJECTFLIP;
-			}
+	mobj->angle = FixedAngle(mthing->angle << FRACBITS);
+	mthing->mobj = mobj;
+	if (mthing->options & MTF_AMBUSH)
+		mobj->flags2 |= MF2_AMBUSH;
 
-			mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
-			if (mthing->options & MTF_AMBUSH)
-				mobj->flags2 |= MF2_AMBUSH;
+	if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP))
+		P_SetMobjState(mobj, mobj->info->raisestate);
+	else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
+		P_SetMobjState(mobj, mobj->info->seestate);
+}
 
-			if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
-				P_SetMobjState(mobj, mobj->info->seestate);
-		}
-	}
-	// Diagonal rings (handles both types)
-	else if (mthing->type == 602 || mthing->type == 603) // Diagonal rings (5)
-	{
-		INT32 iterations = 5;
-		if (mthing->type == 603)
-			iterations = 10;
+static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace)
+{
+	mobjtype_t ringthing = MT_RING;
+	mobj_t* mobj = NULL;
+	fixed_t z;
+	INT32 r;
 
-		if (ultimatemode)
-			return; // No rings in Ultimate!
+	INT32 dist = 64*FRACUNIT;
+	if (mthing->type == 601)
+		dist = 128*FRACUNIT;
 
-		if (nightsreplace)
-			ringthing = MT_NIGHTSSTAR;
+	if (ultimatemode)
+		return; // No rings in Ultimate!
 
-		closestangle = FixedAngle(mthing->angle*FRACUNIT);
-		fa = (closestangle >> ANGLETOFINESHIFT);
+	if (nightsreplace)
+		ringthing = MT_NIGHTSSTAR;
 
-		if (mthing->options & MTF_OBJECTFLIP)
-		{
-			z = (
-#ifdef ESLOPE
-				sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
-#endif
-				sec->ceilingheight) - mobjinfo[ringthing].height;
-			if (mthing->z)
-				z -= (mthing->z << FRACBITS);
-			}
-		else
-		{
-			z = (
+	if (mthing->options & MTF_OBJECTFLIP)
+	{
+		z = (
 #ifdef ESLOPE
-				sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+			sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
 #endif
-				sec->floorheight);
-			if (mthing->z)
-				z += (mthing->z << FRACBITS);
-		}
-
-		for (r = 1; r <= iterations; r++)
-		{
-			x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
-			y += FixedMul(64*FRACUNIT, FINESINE(fa));
-
-			if (mthing->options & MTF_OBJECTFLIP)
-				z -= 64*FRACUNIT;
-			else
-				z += 64*FRACUNIT;
-
-			mobj = P_SpawnMobj(x, y, z, ringthing);
-
-			if (mthing->options & MTF_OBJECTFLIP)
-			{
-				mobj->eflags |= MFE_VERTICALFLIP;
-				mobj->flags2 |= MF2_OBJECTFLIP;
-			}
-
-			mobj->angle = closestangle;
-			if (mthing->options & MTF_AMBUSH)
-				mobj->flags2 |= MF2_AMBUSH;
-
-			if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
-				P_SetMobjState(mobj, mobj->info->seestate);
-		}
+			sec->ceilingheight) - mobjinfo[ringthing].height;
+		if (mthing->z)
+			z -= (mthing->z << FRACBITS);
 	}
-	// Rings of items (all six of them)
-	else if (mthing->type >= 604 && mthing->type <= 609)
+	else
 	{
-		INT32 numitems = 8;
-		INT32 size = 96*FRACUNIT;
-
-		if (mthing->type & 1)
-		{
-			numitems = 16;
-			size = 192*FRACUNIT;
-		}
-
-		z =
+		z = (
 #ifdef ESLOPE
 			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
-			sec->floorheight;
+			sec->floorheight);
 		if (mthing->z)
 			z += (mthing->z << FRACBITS);
+	}
+
+	for (r = 1; r <= 5; r++)
+	{
+		if (mthing->options & MTF_OBJECTFLIP)
+			z -= dist;
+		else
+			z += dist;
 
-		closestangle = FixedAngle(mthing->angle*FRACUNIT);
+		mobj = P_SpawnMobj(x, y, z, ringthing);
 
-		switch (mthing->type)
+		if (mthing->options & MTF_OBJECTFLIP)
 		{
-			case 604:
-			case 605:
-				if (ultimatemode)
-					return; // No rings in Ultimate!
-				if (nightsreplace)
-					ringthing = MT_NIGHTSSTAR;
-				break;
-			case 608:
-			case 609:
-				/*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere
-				break;*/
-			case 606:
-			case 607:
-				ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
-				break;
-			default:
-				break;
+			mobj->eflags |= MFE_VERTICALFLIP;
+			mobj->flags2 |= MF2_OBJECTFLIP;
 		}
 
-		// Create the hoop!
-		for (i = 0; i < numitems; i++)
-		{
-			if (mthing->type == 608 || mthing->type == 609)
-			{
-				if (i & 1)
-				{
-					if (ultimatemode)
-						continue; // No rings in Ultimate!
-					ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING;
-				}
-				else
-					ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
-			}
+		mobj->angle = FixedAngle(mthing->angle << FRACBITS);
+		if (mthing->options & MTF_AMBUSH)
+			mobj->flags2 |= MF2_AMBUSH;
 
-			fa = i*FINEANGLES/numitems;
-			v[0] = FixedMul(FINECOSINE(fa),size);
-			v[1] = 0;
-			v[2] = FixedMul(FINESINE(fa),size);
-			v[3] = FRACUNIT;
+		if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
+			P_SetMobjState(mobj, mobj->info->seestate);
+	}
+}
 
-			res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
-			M_Memcpy(&v, res, sizeof (v));
+static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace)
+{
+	mobjtype_t ringthing = MT_RING;
+	mobj_t *mobj = NULL;
+	fixed_t z;
+	INT32 r;
+	angle_t closestangle, fa;
 
-			finalx = x + v[0];
-			finaly = y + v[1];
-			finalz = z + v[2];
+	INT32 iterations = 5;
+	if (mthing->type == 603)
+		iterations = 10;
 
-			mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing);
-			mobj->z -= mobj->height/2;
+	if (ultimatemode)
+		return; // No rings in Ultimate!
 
-			if (mthing->options & MTF_OBJECTFLIP)
-			{
-				mobj->eflags |= MFE_VERTICALFLIP;
-				mobj->flags2 |= MF2_OBJECTFLIP;
-			}
+	if (nightsreplace)
+		ringthing = MT_NIGHTSSTAR;
 
-			mobj->angle = closestangle;
-			if (mthing->options & MTF_AMBUSH)
-				mobj->flags2 |= MF2_AMBUSH;
+	closestangle = FixedAngle(mthing->angle << FRACBITS);
+	fa = (closestangle >> ANGLETOFINESHIFT);
 
-			if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP))
-				P_SetMobjState(mobj, mobj->info->raisestate);
-			else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
-				P_SetMobjState(mobj, mobj->info->seestate);
-		}
+	if (mthing->options & MTF_OBJECTFLIP)
+	{
+		z = (
+#ifdef ESLOPE
+			sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
+#endif
+			sec->ceilingheight) - mobjinfo[ringthing].height;
+		if (mthing->z)
+			z -= (mthing->z << FRACBITS);
 	}
-	// All manners of rings and coins
 	else
 	{
+		z = (
+#ifdef ESLOPE
+			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+			sec->floorheight);
+		if (mthing->z)
+			z += (mthing->z << FRACBITS);
+	}
+
+	for (r = 1; r <= iterations; r++)
+	{
+		x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
+		y += FixedMul(64*FRACUNIT, FINESINE(fa));
 
-		// Which ringthing to use
-		if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum)
-			ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
-		else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum)
-			ringthing = MT_BOMBSPHERE;
+		if (mthing->options & MTF_OBJECTFLIP)
+			z -= 64*FRACUNIT;
 		else
-		{
-			if (ultimatemode)
-				return; // No rings in Ultimate!
+			z += 64*FRACUNIT;
 
-			if (nightsreplace)
-				ringthing = MT_NIGHTSSTAR;
-			else if (mthing->type == mobjinfo[MT_COIN].doomednum)
-				ringthing = MT_COIN;
-			else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF
-				ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING;
-			else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto
-				ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING;
-		}
+		mobj = P_SpawnMobj(x, y, z, ringthing);
 
-		// Set proper height
 		if (mthing->options & MTF_OBJECTFLIP)
 		{
-			z = (
-#ifdef ESLOPE
-			sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
-#endif
-			sec->ceilingheight) - mobjinfo[ringthing].height;
-			if (mthing->z)
-				z -= (mthing->z << FRACBITS);
+			mobj->eflags |= MFE_VERTICALFLIP;
+			mobj->flags2 |= MF2_OBJECTFLIP;
 		}
-		else
-		{
-			z =
+
+		mobj->angle = closestangle;
+		if (mthing->options & MTF_AMBUSH)
+			mobj->flags2 |= MF2_AMBUSH;
+
+		if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
+			P_SetMobjState(mobj, mobj->info->seestate);
+	}
+}
+
+static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean bonustime, boolean nightsreplace)
+{
+	mobjtype_t ringthing = MT_RING;
+	mobj_t *mobj = NULL;
+	fixed_t z, finalx, finaly, finalz;
+	angle_t closestangle, fa;
+	INT32 i;
+	TVector v, *res;
+	INT32 numitems = 8;
+	INT32 size = 96*FRACUNIT;
+
+	if (mthing->type & 1)
+	{
+		numitems = 16;
+		size = 192*FRACUNIT;
+	}
+
+	z =
 #ifdef ESLOPE
-			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+		sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
-			sec->floorheight;
-			if (mthing->z)
-				z += (mthing->z << FRACBITS);
-		}
+		sec->floorheight;
+	if (mthing->z)
+		z += (mthing->z << FRACBITS);
 
-		if (mthing->options & MTF_AMBUSH) // Special flag for rings
+	closestangle = FixedAngle(mthing->angle << FRACBITS);
+
+	switch (mthing->type)
+	{
+	case 604:
+	case 605:
+		if (ultimatemode)
+			return; // No rings in Ultimate!
+		if (nightsreplace)
+			ringthing = MT_NIGHTSSTAR;
+		break;
+	case 608:
+	case 609:
+		/*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere
+		break;*/
+	case 606:
+	case 607:
+		ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
+		break;
+	default:
+		break;
+	}
+
+	// Create the hoop!
+	for (i = 0; i < numitems; i++)
+	{
+		if (mthing->type == 608 || mthing->type == 609)
 		{
-			if (mthing->options & MTF_OBJECTFLIP)
-				z -= 24*FRACUNIT;
+			if (i & 1)
+			{
+				if (ultimatemode)
+					continue; // No rings in Ultimate!
+				ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING;
+			}
 			else
-				z += 24*FRACUNIT;
+				ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
 		}
 
-		mobj = P_SpawnMobj(x, y, z, ringthing);
-		mobj->spawnpoint = mthing;
+		fa = i * FINEANGLES/numitems;
+		v[0] = FixedMul(FINECOSINE(fa), size);
+		v[1] = 0;
+		v[2] = FixedMul(FINESINE(fa), size);
+		v[3] = FRACUNIT;
+
+		res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
+		M_Memcpy(&v, res, sizeof(v));
+
+		finalx = x + v[0];
+		finaly = y + v[1];
+		finalz = z + v[2];
+
+		mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing);
+		mobj->z -= mobj->height/2;
 
 		if (mthing->options & MTF_OBJECTFLIP)
 		{
@@ -13614,8 +13436,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			mobj->flags2 |= MF2_OBJECTFLIP;
 		}
 
-		mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
-		mthing->mobj = mobj;
+		mobj->angle = closestangle;
 		if (mthing->options & MTF_AMBUSH)
 			mobj->flags2 |= MF2_AMBUSH;
 
@@ -13626,6 +13447,47 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 	}
 }
 
+void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
+{
+	fixed_t x = mthing->x << FRACBITS;
+	fixed_t y = mthing->y << FRACBITS;
+	fixed_t z = mthing->z << FRACBITS;
+	sector_t *sec = R_PointInSubsector(x, y)->sector;
+	boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
+
+	switch (mthing->type)
+	{
+	// Special placement patterns
+	case 600: // 5 vertical rings (yellow spring)
+	case 601: // 5 vertical rings (red spring)
+		P_SpawnVerticalSpringRings(mthing, x, y, sec, nightsreplace);
+		return;
+	case 602: // 5 diagonal rings (yellow spring)
+	case 603: // 10 diagonal rings (red spring)
+		P_SpawnDiagonalSpringRings(mthing, x, y, sec, nightsreplace);
+		return;
+	case 604: // Circle of rings (8 items)
+	case 605: // Circle of rings (16 bits)
+	case 606: // Circle of blue spheres (8 items)
+	case 607: // Circle of blue spheres (16 items)
+	case 608: // Circle of rings and blue spheres (8 items)
+	case 609: // Circle of rings and blue spheres (16 items)
+		P_SpawnItemCircle(mthing, x, y, sec, bonustime, nightsreplace);
+		return;
+	// Hoops
+	case 1705: // Generic NiGHTS hoop
+		P_SpawnHoop(mthing, x, y, z, sec, 24, 4*FRACUNIT);
+		return;
+	case 1713: // Customizable NiGHTS hoop
+		// For each flag add 16 fracunits to the size
+		// Default (0 flags) is 32 fracunits
+		P_SpawnHoop(mthing, x, y, z, sec, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT);
+		return;
+	default: // All manners of rings and coins
+		P_SpawnRingItem(mthing, x, y, bonustime, nightsreplace);
+	}
+}
+
 //
 // P_CheckMissileSpawn
 // Moves the missile forward a bit and possibly explodes it right there.
diff --git a/src/p_saveg.c b/src/p_saveg.c
index c876713e4cca1c0856ea1b79ded396b189cac514..5af72cd46cc9d7f8f6d2837413775b51fc8b898e 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -777,15 +777,13 @@ static void P_NetArchiveWorld(void)
 	size_t i;
 	INT32 statsec = 0, statline = 0;
 	const line_t *li = lines;
+	const line_t *spawnli = spawnlines;
 	const side_t *si;
+	const side_t *spawnsi;
 	UINT8 *put;
 
-	// reload the map just to see difference
-	virtres_t* virt = vres_GetMap(lastloadedmaplumpnum);
-	mapsector_t  *ms  = (mapsector_t*) vres_Find(virt, "SECTORS")->data;
-	mapsidedef_t *msd = (mapsidedef_t*) vres_Find(virt, "SIDEDEFS")->data;
-	maplinedef_t *mld = (maplinedef_t*) vres_Find(virt, "LINEDEFS")->data;
 	const sector_t *ss = sectors;
+	const sector_t *spawnss = spawnsectors;
 	UINT8 diff, diff2, diff3;
 
 	// initialize colormap vars because paranoia
@@ -794,45 +792,45 @@ static void P_NetArchiveWorld(void)
 	WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
 	put = save_p;
 
-	for (i = 0; i < numsectors; i++, ss++, ms++)
+	for (i = 0; i < numsectors; i++, ss++, spawnss++)
 	{
 		diff = diff2 = diff3 = 0;
-		if (ss->floorheight != SHORT(ms->floorheight)<<FRACBITS)
+		if (ss->floorheight != spawnss->floorheight)
 			diff |= SD_FLOORHT;
-		if (ss->ceilingheight != SHORT(ms->ceilingheight)<<FRACBITS)
+		if (ss->ceilingheight != spawnss->ceilingheight)
 			diff |= SD_CEILHT;
 		//
 		// flats
 		//
-		if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
+		if (ss->floorpic != spawnss->floorpic)
 			diff |= SD_FLOORPIC;
-		if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
+		if (ss->ceilingpic != spawnss->ceilingpic)
 			diff |= SD_CEILPIC;
 
-		if (ss->lightlevel != SHORT(ms->lightlevel))
+		if (ss->lightlevel != spawnss->lightlevel)
 			diff |= SD_LIGHT;
-		if (ss->special != SHORT(ms->special))
+		if (ss->special != spawnss->special)
 			diff |= SD_SPECIAL;
 
-		if (ss->floor_xoffs != ss->spawn_flr_xoffs)
+		if (ss->floor_xoffs != spawnss->floor_xoffs)
 			diff2 |= SD_FXOFFS;
-		if (ss->floor_yoffs != ss->spawn_flr_yoffs)
+		if (ss->floor_yoffs != spawnss->floor_yoffs)
 			diff2 |= SD_FYOFFS;
-		if (ss->ceiling_xoffs != ss->spawn_ceil_xoffs)
+		if (ss->ceiling_xoffs != spawnss->ceiling_xoffs)
 			diff2 |= SD_CXOFFS;
-		if (ss->ceiling_yoffs != ss->spawn_ceil_yoffs)
+		if (ss->ceiling_yoffs != spawnss->ceiling_yoffs)
 			diff2 |= SD_CYOFFS;
-		if (ss->floorpic_angle != ss->spawn_flrpic_angle)
+		if (ss->floorpic_angle != spawnss->floorpic_angle)
 			diff2 |= SD_FLOORANG;
-		if (ss->ceilingpic_angle != ss->spawn_flrpic_angle)
+		if (ss->ceilingpic_angle != spawnss->ceilingpic_angle)
 			diff2 |= SD_CEILANG;
 
-		if (ss->tag != SHORT(ms->tag))
+		if (ss->tag != spawnss->tag)
 			diff2 |= SD_TAG;
-		if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
+		if (ss->nexttag != spawnss->nexttag || ss->firsttag != spawnss->firsttag)
 			diff3 |= SD_TAGLIST;
 
-		if (ss->extra_colormap != ss->spawn_extra_colormap)
+		if (ss->extra_colormap != spawnss->extra_colormap)
 			diff3 |= SD_COLORMAP;
 
 		// Check if any of the sector's FOFs differ from how they spawned
@@ -936,45 +934,41 @@ static void P_NetArchiveWorld(void)
 	WRITEUINT16(put, 0xffff);
 
 	// do lines
-	for (i = 0; i < numlines; i++, mld++, li++)
+	for (i = 0; i < numlines; i++, spawnli++, li++)
 	{
 		diff = diff2 = diff3 = 0;
 
-		if (li->special != SHORT(mld->special))
+		if (li->special != spawnli->special)
 			diff |= LD_SPECIAL;
 
-		if (SHORT(mld->special) == 321 || SHORT(mld->special) == 322) // only reason li->callcount would be non-zero is if either of these are involved
+		if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved
 			diff |= LD_CLLCOUNT;
 
 		if (li->sidenum[0] != 0xffff)
 		{
 			si = &sides[li->sidenum[0]];
-			if (si->textureoffset != SHORT(msd[li->sidenum[0]].textureoffset)<<FRACBITS)
+			spawnsi = &spawnsides[li->sidenum[0]];
+			if (si->textureoffset != spawnsi->textureoffset)
 				diff |= LD_S1TEXOFF;
 			//SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures.
-			if (R_CheckTextureNumForName(msd[li->sidenum[0]].toptexture) != -1
-				&& si->toptexture != R_TextureNumForName(msd[li->sidenum[0]].toptexture))
+			if (si->toptexture != spawnsi->toptexture)
 				diff |= LD_S1TOPTEX;
-			if (R_CheckTextureNumForName(msd[li->sidenum[0]].bottomtexture) != -1
-				&& si->bottomtexture != R_TextureNumForName(msd[li->sidenum[0]].bottomtexture))
+			if (si->bottomtexture != spawnsi->bottomtexture)
 				diff |= LD_S1BOTTEX;
-			if (R_CheckTextureNumForName(msd[li->sidenum[0]].midtexture) != -1
-				&& si->midtexture != R_TextureNumForName(msd[li->sidenum[0]].midtexture))
+			if (si->midtexture != spawnsi->midtexture)
 				diff |= LD_S1MIDTEX;
 		}
 		if (li->sidenum[1] != 0xffff)
 		{
 			si = &sides[li->sidenum[1]];
-			if (si->textureoffset != SHORT(msd[li->sidenum[1]].textureoffset)<<FRACBITS)
+			spawnsi = &spawnsides[li->sidenum[1]];
+			if (si->textureoffset != spawnsi->textureoffset)
 				diff2 |= LD_S2TEXOFF;
-			if (R_CheckTextureNumForName(msd[li->sidenum[1]].toptexture) != -1
-				&& si->toptexture != R_TextureNumForName(msd[li->sidenum[1]].toptexture))
+			if (si->toptexture != spawnsi->toptexture)
 				diff2 |= LD_S2TOPTEX;
-			if (R_CheckTextureNumForName(msd[li->sidenum[1]].bottomtexture) != -1
-				&& si->bottomtexture != R_TextureNumForName(msd[li->sidenum[1]].bottomtexture))
+			if (si->bottomtexture != spawnsi->bottomtexture)
 				diff2 |= LD_S2BOTTEX;
-			if (R_CheckTextureNumForName(msd[li->sidenum[1]].midtexture) != -1
-				&& si->midtexture != R_TextureNumForName(msd[li->sidenum[1]].midtexture))
+			if (si->midtexture != spawnsi->midtexture)
 				diff2 |= LD_S2MIDTEX;
 			if (diff2)
 				diff |= LD_DIFF2;
@@ -1018,7 +1012,6 @@ static void P_NetArchiveWorld(void)
 	WRITEUINT16(put, 0xffff);
 	R_ClearTextureNumCache(false);
 
-	vres_Free(virt);
 	save_p = put;
 }
 
diff --git a/src/p_setup.c b/src/p_setup.c
index bc736588e034ae2e909b3c53ac3a5af2ccb1fae3..6e6c1a72bd871984846bd3e1f39966287dee084e 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -103,6 +103,9 @@ node_t *nodes;
 line_t *lines;
 side_t *sides;
 mapthing_t *mapthings;
+sector_t *spawnsectors;
+line_t *spawnlines;
+side_t *spawnsides;
 INT32 numstarposts;
 UINT16 bossdisabled;
 boolean stoppedclock;
@@ -666,11 +669,9 @@ static void P_LoadRawSectors(UINT8 *data)
 		ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats);
 
 		ss->lightlevel = SHORT(ms->lightlevel);
-		ss->spawn_lightlevel = SHORT(ms->lightlevel);
 		ss->special = SHORT(ms->special);
 		ss->tag = SHORT(ms->tag);
 		ss->nexttag = ss->firsttag = -1;
-		ss->spawn_nexttag = ss->spawn_firsttag = -1;
 
 		memset(&ss->soundorg, 0, sizeof(ss->soundorg));
 		ss->validcount = 0;
@@ -705,9 +706,7 @@ static void P_LoadRawSectors(UINT8 *data)
 		ss->spawn_extra_colormap = NULL;
 
 		ss->floor_xoffs = ss->ceiling_xoffs = ss->floor_yoffs = ss->ceiling_yoffs = 0;
-		ss->spawn_flr_xoffs = ss->spawn_ceil_xoffs = ss->spawn_flr_yoffs = ss->spawn_ceil_yoffs = 0;
 		ss->floorpic_angle = ss->ceilingpic_angle = 0;
-		ss->spawn_flrpic_angle = ss->spawn_ceilpic_angle = 0;
 		ss->gravity = NULL;
 		ss->cullheight = NULL;
 		ss->verticalflip = false;
@@ -2775,6 +2774,15 @@ boolean P_SetupLevel(boolean skipprecip)
 		P_LoadLineDefs2();
 		P_GroupLines();
 
+		// Copy relevant map data for NetArchive purposes.
+		spawnsectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL);
+		spawnlines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL);
+		spawnsides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL);
+
+		memcpy(spawnsectors, sectors, numsectors * sizeof (*sectors));
+		memcpy(spawnlines, lines, numlines * sizeof (*lines));
+		memcpy(spawnsides, sides, numsides * sizeof (*sides));
+
 		P_PrepareRawThings(vres_Find(virt, "THINGS")->data);
 
 		P_MakeMapMD5(virt, &mapmd5);
diff --git a/src/p_spec.c b/src/p_spec.c
index b50fc66c05bc463880d13f06da7eab7d15b89e7a..297c9a4277a5cce5703bccd8e379220fd04fb1ab 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -138,6 +138,13 @@ static size_t maxanims;
 
 static animdef_t *animdefs = NULL;
 
+// Increase the size of animdefs to make room for a new animation definition
+static void GrowAnimDefs(void)
+{
+	maxanims++;
+	animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
+}
+
 // A prototype; here instead of p_spec.h, so they're "private"
 void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum);
 void P_ParseAnimationDefintion(SINT8 istexture);
@@ -347,8 +354,7 @@ void P_ParseAnimationDefintion(SINT8 istexture)
 	if (i == maxanims)
 	{
 		// Increase the size to make room for the new animation definition
-		maxanims++;
-		animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
+		GrowAnimDefs();
 		strncpy(animdefs[i].startname, animdefsToken, 9);
 	}
 
@@ -434,8 +440,17 @@ void P_ParseAnimationDefintion(SINT8 istexture)
 	}
 	animdefs[i].speed = animSpeed;
 	Z_Free(animdefsToken);
-}
 
+#ifdef WALLFLATS
+	// hehe... uhh.....
+	if (!istexture)
+	{
+		GrowAnimDefs();
+		M_Memcpy(&animdefs[maxanims-1], &animdefs[i], sizeof(animdef_t));
+		animdefs[maxanims-1].istexture = 1;
+	}
+#endif
+}
 
 /** Checks for flats in levelflats that are part of a flat animation sequence
   * and sets them up for animation.
@@ -476,7 +491,8 @@ static inline void P_FindAnimatedFlat(INT32 animnum)
 					atoi(sizeu1(i)), foundflats->name, foundflats->animseq,
 					foundflats->numpics,foundflats->speed);
 		}
-		else if (foundflats->u.flat.lumpnum >= startflatnum && foundflats->u.flat.lumpnum <= endflatnum)
+		else if ((!anims[animnum].istexture) && (foundflats->type == LEVELFLAT_FLAT)
+			&& (foundflats->u.flat.lumpnum >= startflatnum && foundflats->u.flat.lumpnum <= endflatnum))
 		{
 			foundflats->u.flat.baselumpnum = startflatnum;
 			foundflats->animseq = foundflats->u.flat.lumpnum - startflatnum;
@@ -1587,8 +1603,6 @@ static inline void P_InitTagLists(void)
 		size_t j = (unsigned)sectors[i].tag % numsectors;
 		sectors[i].nexttag = sectors[j].firsttag;
 		sectors[j].firsttag = (INT32)i;
-		sectors[i].spawn_nexttag = sectors[i].nexttag;
-		sectors[j].spawn_firsttag = sectors[j].firsttag;
 	}
 
 	for (i = numlines - 1; i != (size_t)-1; i--)
@@ -5626,7 +5640,7 @@ void P_UpdateSpecials(void)
 		if (foundflats->speed) // it is an animated flat
 		{
 			// update the levelflat texture number
-			if (foundflats->type == LEVELFLAT_TEXTURE)
+			if ((foundflats->type == LEVELFLAT_TEXTURE) && (foundflats->u.texture.basenum != -1))
 				foundflats->u.texture.num = foundflats->u.texture.basenum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics);
 			// update the levelflat lump number
 			else if ((foundflats->type == LEVELFLAT_FLAT) && (foundflats->u.flat.baselumpnum != LUMPERROR))
@@ -6389,22 +6403,16 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata
 {
 	if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set
 	{
-		sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle;
+		sector->floorpic_angle = flatangle;
 		sector->floor_xoffs += xoffs;
 		sector->floor_yoffs += yoffs;
-		// saved for netgames
-		sector->spawn_flr_xoffs = sector->floor_xoffs;
-		sector->spawn_flr_yoffs = sector->floor_yoffs;
 	}
 
 	if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set
 	{
-		sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle;
+		sector->ceilingpic_angle = flatangle;
 		sector->ceiling_xoffs += xoffs;
 		sector->ceiling_yoffs += yoffs;
-		// saved for netgames
-		sector->spawn_ceil_xoffs = sector->ceiling_xoffs;
-		sector->spawn_ceil_yoffs = sector->ceiling_yoffs;
 	}
 
 }
diff --git a/src/r_data.c b/src/r_data.c
index c3f3bf8ff7826292a44862ad8a88d0ea5979594f..12e0702c10f184e7bbb0f3b8aea3168dcebbab37 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -441,7 +441,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 	texture_t *texture;
 	texpatch_t *patch;
 	patch_t *realpatch;
-	boolean dealloc = false;
+	UINT8 *pdata;
 	int x, x1, x2, i, width, height;
 	size_t blocksize;
 	column_t *patchcol;
@@ -469,12 +469,17 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 		wadnum = patch->wad;
 		lumpnum = patch->lump;
 		lumplength = W_LumpLengthPwad(wadnum, lumpnum);
-		realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); // can't use W_CachePatchNumPwad because OpenGL
+		pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
+		realpatch = (patch_t *)pdata;
 
 #ifndef NO_PNG_LUMPS
 		if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
 			goto multipatch;
 #endif
+#ifdef WALLFLATS
+		if (texture->type == TEXTURETYPE_FLAT)
+			goto multipatch;
+#endif
 
 		// Check the patch for holes.
 		if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height))
@@ -552,6 +557,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 	// Composite the columns together.
 	for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
 	{
+		boolean dealloc = true;
 		static void (*ColumnDrawerPointer)(column_t *, UINT8 *, texpatch_t *, INT32, INT32); // Column drawing function pointer.
 		if (patch->style != AST_COPY)
 			ColumnDrawerPointer = (patch->flip & 2) ? R_DrawBlendFlippedColumnInCache : R_DrawBlendColumnInCache;
@@ -560,17 +566,25 @@ static UINT8 *R_GenerateTexture(size_t texnum)
 
 		wadnum = patch->wad;
 		lumpnum = patch->lump;
+		pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
 		lumplength = W_LumpLengthPwad(wadnum, lumpnum);
-		realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
-		dealloc = false;
+		realpatch = (patch_t *)pdata;
+		dealloc = true;
 
 #ifndef NO_PNG_LUMPS
 		if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
-		{
 			realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false);
-			dealloc = true;
-		}
+		else
+#endif
+#ifdef WALLFLATS
+		if (texture->type == TEXTURETYPE_FLAT)
+			realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false);
+		else
 #endif
+		{
+			(void)lumplength;
+			dealloc = false;
+		}
 
 		x1 = patch->originx;
 		width = SHORT(realpatch->width);
@@ -725,7 +739,6 @@ void R_LoadTextures(void)
 	for (w = 0, numtextures = 0; w < numwadfiles; w++)
 	{
 		// Count the textures from TEXTURES lumps
-
 		texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0);
 		while (texturesLumpPos != INT16_MAX)
 		{
@@ -734,7 +747,6 @@ void R_LoadTextures(void)
 		}
 
 		// Count single-patch textures
-
 		if (wadfiles[w]->type == RET_PK3)
 		{
 			texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
@@ -747,7 +759,11 @@ void R_LoadTextures(void)
 		}
 
 		if (texstart == INT16_MAX || texend == INT16_MAX)
+#ifdef WALLFLATS
+			goto countflats;
+#else
 			continue;
+#endif
 
 		texstart++; // Do not count the first marker
 
@@ -764,6 +780,40 @@ void R_LoadTextures(void)
 		{
 			numtextures += (UINT32)(texend - texstart);
 		}
+
+#ifdef WALLFLATS
+countflats:
+		// Count flats
+		if (wadfiles[w]->type == RET_PK3)
+		{
+			texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
+			texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
+		}
+		else
+		{
+			texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0);
+			texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart);
+		}
+
+		if (texstart == INT16_MAX || texend == INT16_MAX)
+			continue;
+
+		texstart++; // Do not count the first marker
+
+		// PK3s have subfolders, so we can't just make a simple sum
+		if (wadfiles[w]->type == RET_PK3)
+		{
+			for (j = texstart; j < texend; j++)
+			{
+				if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it
+					numtextures++;
+			}
+		}
+		else // Add all the textures between F_START and F_END
+		{
+			numtextures += (UINT32)(texend - texstart);
+		}
+#endif
 	}
 
 	// If no textures found by this point, bomb out
@@ -813,7 +863,11 @@ void R_LoadTextures(void)
 		}
 
 		if (texstart == INT16_MAX || texend == INT16_MAX)
+#ifdef WALLFLATS
+			goto checkflats;
+#else
 			continue;
+#endif
 
 		texstart++; // Do not count the first marker
 
@@ -857,6 +911,8 @@ void R_LoadTextures(void)
 				texture->width = SHORT(patchlump->width);
 				texture->height = SHORT(patchlump->height);
 			}
+
+			texture->type = TEXTURETYPE_SINGLEPATCH;
 			texture->patchcount = 1;
 			texture->holes = false;
 			texture->flip = 0;
@@ -875,6 +931,107 @@ void R_LoadTextures(void)
 			textureheight[i] = texture->height << FRACBITS;
 			i++;
 		}
+
+#ifdef WALLFLATS
+checkflats:
+		// Yes
+		if (wadfiles[w]->type == RET_PK3)
+		{
+			texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
+			texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
+		}
+		else
+		{
+			texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0);
+			texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart);
+		}
+
+		if (texstart == INT16_MAX || texend == INT16_MAX)
+			continue;
+
+		texstart++; // Do not count the first marker
+
+		// Work through each lump between the markers in the WAD.
+		for (j = 0; j < (texend - texstart); j++)
+		{
+			UINT8 *flatlump;
+			UINT16 wadnum = (UINT16)w;
+			lumpnum_t lumpnum = texstart + j;
+			size_t lumplength;
+			size_t flatsize = 0;
+
+			if (wadfiles[w]->type == RET_PK3)
+			{
+				if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
+					continue; // If it is then SKIP IT
+			}
+
+			flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
+			lumplength = W_LumpLengthPwad(wadnum, lumpnum);
+
+			switch (lumplength)
+			{
+				case 4194304: // 2048x2048 lump
+					flatsize = 2048;
+					break;
+				case 1048576: // 1024x1024 lump
+					flatsize = 1024;
+					break;
+				case 262144:// 512x512 lump
+					flatsize = 512;
+					break;
+				case 65536: // 256x256 lump
+					flatsize = 256;
+					break;
+				case 16384: // 128x128 lump
+					flatsize = 128;
+					break;
+				case 1024: // 32x32 lump
+					flatsize = 32;
+					break;
+				default: // 64x64 lump
+					flatsize = 64;
+					break;
+			}
+
+			//CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize);
+			texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
+
+			// Set texture properties.
+			M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
+
+#ifndef NO_PNG_LUMPS
+			if (R_IsLumpPNG((UINT8 *)flatlump, lumplength))
+			{
+				INT16 width, height;
+				R_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength);
+				texture->width = width;
+				texture->height = height;
+			}
+			else
+#endif
+				texture->width = texture->height = flatsize;
+
+			texture->type = TEXTURETYPE_FLAT;
+			texture->patchcount = 1;
+			texture->holes = false;
+			texture->flip = 0;
+
+			// Allocate information for the texture's patches.
+			patch = &texture->patches[0];
+
+			patch->originx = patch->originy = 0;
+			patch->wad = (UINT16)w;
+			patch->lump = texstart + j;
+			patch->flip = 0;
+
+			Z_Unlock(flatlump);
+
+			texturewidth[i] = texture->width;
+			textureheight[i] = texture->height << FRACBITS;
+			i++;
+		}
+#endif
 	}
 
 #ifdef HWRENDER
@@ -1191,6 +1348,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture)
 			M_Memcpy(resultTexture->name, newTextureName, 8);
 			resultTexture->width = newTextureWidth;
 			resultTexture->height = newTextureHeight;
+			resultTexture->type = TEXTURETYPE_COMPOSITE;
 		}
 		Z_Free(texturesToken);
 		texturesToken = M_GetToken(NULL);
diff --git a/src/r_data.h b/src/r_data.h
index 2ab362b7b376b1decf9104bb7834deed5953f477..3dcb22ec4989e870cf72dc623f3494a902611aba 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -45,6 +45,17 @@ typedef struct
 	enum patchalphastyle style;
 } texpatch_t;
 
+// texture type
+enum
+{
+	TEXTURETYPE_UNKNOWN,
+	TEXTURETYPE_SINGLEPATCH,
+	TEXTURETYPE_COMPOSITE,
+#ifdef WALLFLATS
+	TEXTURETYPE_FLAT,
+#endif
+};
+
 // A maptexturedef_t describes a rectangular texture,
 //  which is composed of one or more mappatch_t structures
 //  that arrange graphic patches.
@@ -52,6 +63,7 @@ typedef struct
 {
 	// Keep name for switch changing, etc.
 	char name[8];
+	UINT8 type; // TEXTURETYPE_
 	INT16 width, height;
 	boolean holes;
 	UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both
diff --git a/src/r_defs.h b/src/r_defs.h
index 3cc780545446509c55d0eaffcabaf5e77521b7bf..353dc572b6e6422337869b1871aa7ca674f05273 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -384,17 +384,6 @@ typedef struct sector_s
 	// for fade thinker
 	INT16 spawn_lightlevel;
 
-	// these are saved for netgames, so do not let Lua touch these!
-	INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
-
-	// offsets sector spawned with (via linedef type 7)
-	fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
-	fixed_t spawn_ceil_xoffs, spawn_ceil_yoffs;
-
-	// flag angles sector spawned with (via linedef type 7)
-	angle_t spawn_flrpic_angle;
-	angle_t spawn_ceilpic_angle;
-
 	// colormap structure
 	extracolormap_t *spawn_extra_colormap;
 } sector_t;
diff --git a/src/r_state.h b/src/r_state.h
index 75566923b140adfdffb47a3f64282e3f4ea3a3b5..4e1eb388e7d0a05d46a9c5ee80970c7b2545d2c9 100644
--- a/src/r_state.h
+++ b/src/r_state.h
@@ -63,6 +63,7 @@ extern seg_t *segs;
 
 extern size_t numsectors;
 extern sector_t *sectors;
+extern sector_t *spawnsectors;
 
 extern size_t numsubsectors;
 extern subsector_t *subsectors;
@@ -72,9 +73,11 @@ extern node_t *nodes;
 
 extern size_t numlines;
 extern line_t *lines;
+extern line_t *spawnlines;
 
 extern size_t numsides;
 extern side_t *sides;
+extern side_t *spawnsides;
 
 //
 // POV data.