diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index bd9158468d3845f58fa287a3d3819ad2f7277bb7..74b3339fc2252a362f615ad8b7f66e697d660942 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -4270,13 +4270,11 @@ static INT16 Consistancy(void)
 		ret += P_GetRandSeed();
 
 #ifdef MOBJCONSISTANCY
-	if (!thlist[THINK_MOBJ].next)
-	{
-		DEBFILE(va("Consistancy = %u\n", ret));
-		return ret;
-	}
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)th;
 
 		if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY))
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 5e070dcd7334bb630c765a8767543cb13c9a64dd..e6f5244f019a72cc0f8e0c859f82146f9ec73b95 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -4261,7 +4261,8 @@ static void Command_Archivetest_f(void)
 	// assign mobjnum
 	i = 1;
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
-		((mobj_t *)th)->mobjnum = i++;
+		if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
+			((mobj_t *)th)->mobjnum = i++;
 
 	// allocate buffer
 	buf = save_p = ZZ_Alloc(1024);
diff --git a/src/dehacked.c b/src/dehacked.c
index 31c17f18811fcbcd78e8f5d46c43aa3d4a25ae07..01e2b0bde61c5ea17d4a5665a94fe948e05a9a43 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -5699,7 +5699,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	"S_CEZFLOWER",
 	"S_CEZPOLE",
-	"S_CEZBANNER",
+	"S_CEZBANNER1",
+	"S_CEZBANNER2",
 	"S_PINETREE",
 	"S_CEZBUSH1",
 	"S_CEZBUSH2",
@@ -5708,7 +5709,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_FLAMEHOLDER",
 	"S_FIRETORCH",
 	"S_WAVINGFLAG",
-	"S_WAVINGFLAGSEG",
+	"S_WAVINGFLAGSEG1",
+	"S_WAVINGFLAGSEG2",
 	"S_CRAWLASTATUE",
 	"S_FACESTABBERSTATUE",
 	"S_SUSPICIOUSFACESTABBERSTATUE_WAIT",
@@ -7514,8 +7516,10 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_SMALLFIREBAR", // Small Firebar
 	"MT_BIGFIREBAR", // Big Firebar
 	"MT_CEZFLOWER", // Flower
-	"MT_CEZPOLE", // Pole
-	"MT_CEZBANNER", // Banner
+	"MT_CEZPOLE1", // Pole (with red banner)
+	"MT_CEZPOLE2", // Pole (with blue banner)
+	"MT_CEZBANNER1", // Banner (red)
+	"MT_CEZBANNER2", // Banner (blue)
 	"MT_PINETREE", // Pine Tree
 	"MT_CEZBUSH1", // Bush 1
 	"MT_CEZBUSH2", // Bush 2
@@ -7523,8 +7527,10 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_CANDLEPRICKET", // Candle pricket
 	"MT_FLAMEHOLDER", // Flame holder
 	"MT_FIRETORCH", // Fire torch
-	"MT_WAVINGFLAG", // Waving flag
-	"MT_WAVINGFLAGSEG", // Waving flag segment
+	"MT_WAVINGFLAG1", // Waving flag (red)
+	"MT_WAVINGFLAG2", // Waving flag (blue)
+	"MT_WAVINGFLAGSEG1", // Waving flag segment (red)
+	"MT_WAVINGFLAGSEG2", // Waving flag segment (blue)
 	"MT_CRAWLASTATUE", // Crawla statue
 	"MT_FACESTABBERSTATUE", // Facestabber statue
 	"MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking:
diff --git a/src/f_finale.c b/src/f_finale.c
index 1cae457a2e7f3dff9d09ab5f004ed7e000018afe..27c9ebd681b4d39209c426dd8ecfcbd8fd0f5a26 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -1695,6 +1695,9 @@ void F_TitleScreenTicker(boolean run)
 		{
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				if (!mo2)
diff --git a/src/g_game.c b/src/g_game.c
index f963cae3598846b97baad5960ff3a212189452fe..95cc2288d3dab64873657fdd50bc45c04c1ef008 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2567,6 +2567,9 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
 	// scan all thinkers
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (!(mo2->flags & MF_MISSILE))
@@ -4466,12 +4469,13 @@ void G_ConsGhostTic(void)
 				mobj = NULL;
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
 					mobj = (mobj_t *)th;
 					if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z)
 						break;
-					mobj = NULL; // wasn't this one, keep searching.
 				}
-				if (mobj && mobj->health != health) // Wasn't damaged?! This is desync! Fix it!
+				if (th != &thlist[THINK_MOBJ] && mobj->health != health) // Wasn't damaged?! This is desync! Fix it!
 				{
 					if (demosynced)
 						CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
@@ -5860,13 +5864,16 @@ void G_DoPlayMetal(void)
 	// find metal sonic
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)th;
 		if (mo->type != MT_METALSONIC_RACE)
 			continue;
 
 		break;
 	}
-	if (!mo)
+	if (th == &thlist[THINK_MOBJ])
 	{
 		CONS_Alert(CONS_ERROR, M_GetText("Failed to find bot entity.\n"));
 		Z_Free(metalbuffer);
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index b87fe65de16cd7f4cd1805ed34f30f3d1a5e6f84..a52d72869ee87e9c40fa6f6348d2d489da67f73c 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -804,6 +804,14 @@ void HWR_WallLighting(FOutVector *wlVerts)
 		FSurfaceInfo    Surf;
 		float           dist_p2d, d[4], s;
 
+		if (!dynlights->mo[j])
+			continue;
+		if (P_MobjWasRemoved(dynlights->mo[j]))
+		{
+			P_SetTarget(&dynlights->mo[j], NULL);
+			continue;
+		}
+
 		// check bounding box first
 		if (SphereTouchBBox3D(&wlVerts[2], &wlVerts[0], &LIGHT_POS(j), DL_RADIUS(j))==false)
 			continue;
@@ -854,8 +862,6 @@ void HWR_WallLighting(FOutVector *wlVerts)
 #ifdef DL_HIGH_QUALITY
 		Surf.FlatColor.s.alpha = (UINT8)((1-dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha);
 #endif
-		if (!dynlights->mo[j]->state)
-			return;
 		// next state is null so fade out with alpha
 		if (dynlights->mo[j]->state->nextstate == S_NULL)
 			Surf.FlatColor.s.alpha = (UINT8)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha);
@@ -886,6 +892,14 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts)
 		FSurfaceInfo    Surf;
 		float           dist_p2d, s;
 
+		if (!dynlights->mo[j])
+			continue;
+		if (P_MobjWasRemoved(dynlights->mo[j]))
+		{
+			P_SetTarget(&dynlights->mo[j], NULL);
+			continue;
+		}
+
 		// BP: The kickass Optimization: check if light touch bounding box
 		if (SphereTouchBBox3D(&p1, &p2, &dynlights->position[j], DL_RADIUS(j))==false)
 			continue;
@@ -917,8 +931,6 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts)
 #ifdef DL_HIGH_QUALITY
 		Surf.FlatColor.s.alpha = (unsigned char)((1 - dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha);
 #endif
-		if (!dynlights->mo[j]->state)
-			return;
 		// next state is null so fade out with alpha
 		if ((dynlights->mo[j]->state->nextstate == S_NULL))
 			Surf.FlatColor.s.alpha = (unsigned char)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha);
@@ -1049,6 +1061,14 @@ void HWR_DrawCoronas(void)
 		if (!(p_lspr->type & CORONA_SPR))
 			continue;
 
+		if (!dynlights->mo[j])
+			continue;
+		if (P_MobjWasRemoved(dynlights->mo[j]))
+		{
+			P_SetTarget(&dynlights->mo[j], NULL);
+			continue;
+		}
+
 		transform(&cx,&cy,&cz);
 
 		// more realistique corona !
@@ -1110,7 +1130,8 @@ void HWR_DrawCoronas(void)
 // --------------------------------------------------------------------------
 void HWR_ResetLights(void)
 {
-	dynlights->nb = 0;
+	while (dynlights->nb)
+		P_SetTarget(&dynlights->mo[--dynlights->nb], NULL);
 }
 
 // --------------------------------------------------------------------------
@@ -1141,24 +1162,25 @@ void HWR_DL_AddLight(gr_vissprite_t *spr, GLPatch_t *patch)
 		return;
 #endif
 
+	if (dynlights->nb >= DL_MAX_LIGHT)
+		return;
+
 	// check if sprite contain dynamic light
 	p_lspr = t_lspr[spr->mobj->sprite];
-	if ((p_lspr->type&DYNLIGHT_SPR)
-	  && ((p_lspr->type != LIGHT_SPR) || cv_grstaticlighting.value)
-	  && (dynlights->nb < DL_MAX_LIGHT)
+	if (!(p_lspr->type & DYNLIGHT_SPR))
+		return;
+	if ((p_lspr->type != LIGHT_SPR) || cv_grstaticlighting.value)
+		return;
 
-	  && spr->mobj->state)
-	{
-		LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(spr->mobj->x);
-		LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(spr->mobj->z)+FIXED_TO_FLOAT(spr->mobj->height>>1)+p_lspr->light_yoffset;
-		LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(spr->mobj->y);
+	LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(spr->mobj->x);
+	LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(spr->mobj->z)+FIXED_TO_FLOAT(spr->mobj->height>>1)+p_lspr->light_yoffset;
+	LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(spr->mobj->y);
 
-		P_SetTarget(&dynlights->mo[dynlights->nb], spr->mobj);
+	P_SetTarget(&dynlights->mo[dynlights->nb], spr->mobj);
 
-		dynlights->p_lspr[dynlights->nb] = p_lspr;
+	dynlights->p_lspr[dynlights->nb] = p_lspr;
 
-		dynlights->nb++;
-	}
+	dynlights->nb++;
 }
 
 static GLPatch_t lightmappatch;
@@ -1312,6 +1334,14 @@ static void HWR_CheckSubsector(size_t num, fixed_t *bbox)
 //			if (CircleTouchBBox(&p1, &p2, &LIGHT_POS(lightnum), DL_RADIUS(lightnum))==false)
 //				continue;
 
+			if (!dynlights->mo[lightnum])
+				continue;
+			if (P_MobjWasRemoved(dynlights->mo[lightnum]))
+			{
+				P_SetTarget(&dynlights->mo[lightnum], NULL);
+				continue;
+			}
+
 			count = sub->numlines;          // how many linedefs
 			line = &segs[sub->firstline];   // first line seg
 			while (count--)
@@ -1329,18 +1359,20 @@ static void HWR_CheckSubsector(size_t num, fixed_t *bbox)
 // --------------------------------------------------------------------------
 static void HWR_AddMobjLights(mobj_t *thing)
 {
-	if (t_lspr[thing->sprite]->type & CORONA_SPR)
-	{
-		LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(thing->x);
-		LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(thing->z) + t_lspr[thing->sprite]->light_yoffset;
-		LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(thing->y);
+	if (dynlights->nb >= DL_MAX_LIGHT)
+		return;
+	if (!(t_lspr[thing->sprite]->type & CORONA_SPR))
+		return;
 
-		dynlights->p_lspr[dynlights->nb] = t_lspr[thing->sprite];
+	LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(thing->x);
+	LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(thing->z) + t_lspr[thing->sprite]->light_yoffset;
+	LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(thing->y);
 
-		dynlights->nb++;
-		if (dynlights->nb > DL_MAX_LIGHT)
-			dynlights->nb = DL_MAX_LIGHT;
-	}
+	P_SetTarget(&dynlights->mo[dynlights->nb], thing);
+
+	dynlights->p_lspr[dynlights->nb] = t_lspr[thing->sprite];
+
+	dynlights->nb++;
 }
 
 //Hurdler: The goal of this function is to walk through all the bsp starting
@@ -1367,7 +1399,8 @@ static void HWR_SearchLightsInMobjs(void)
 
 	// search in the list of thinkers
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
-		HWR_AddMobjLights((mobj_t *)th);
+		if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
+			HWR_AddMobjLights((mobj_t *)th);
 }
 #endif
 
@@ -1379,7 +1412,7 @@ void HWR_CreateStaticLightmaps(int bspnum)
 #ifdef STATICLIGHT
 	CONS_Debug(DBG_RENDER, "HWR_CreateStaticLightmaps\n");
 
-	dynlights->nb = 0;
+	HWR_ResetLights();
 
 	// First: Searching for lights
 	// BP: if i was you, I will make it in create mobj since mobj can be create
@@ -1390,8 +1423,6 @@ void HWR_CreateStaticLightmaps(int bspnum)
 	// Second: Build all lightmap for walls covered by lights
 	validcount++; // to be sure
 	HWR_ComputeLightMapsInBSPNode(bspnum, NULL);
-
-	dynlights->nb = 0;
 #else
 	(void)bspnum;
 #endif
diff --git a/src/info.c b/src/info.c
index 631f40cdc157c0165313a38b392f1f930ce818f4..a4446d65712972ef1cae87c3ee8a0a39f865f6a9 100644
--- a/src/info.c
+++ b/src/info.c
@@ -2322,9 +2322,10 @@ state_t states[NUMSTATES] =
 	{SPR_BFBR, FF_FULLBRIGHT|15,  1, {NULL},            0, 0, S_BIGFIREBAR1},  // S_BIGFIREBAR16
 
 	{SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER
-	{SPR_BANR, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE
+	{SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE
 
-	{SPR_BANR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER
+	{SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER1
+	{SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER2
 
 	{SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE
 	{SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1
@@ -2338,7 +2339,8 @@ state_t states[NUMSTATES] =
 	{SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH
 
 	{SPR_CFLG,                0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG
-	{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG
+	{SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG1
+	{SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG2
 
 	{SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE
 
@@ -7492,7 +7494,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // painstate
 		0,              // painchance
 		sfx_s3k64,      // painsound
-		S_NULL,         // meleestate
+		S_WALLSPIKE4,   // meleestate
 		S_NULL,         // missilestate
 		S_WALLSPIKED1,  // deathstate
 		S_WALLSPIKED2,  // xdeathstate
@@ -11018,7 +11020,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_CEZPOLE
+	{           // MT_CEZPOLE1
 		1117,           // doomednum
 		S_CEZPOLE,      // spawnstate
 		1000,           // spawnhealth
@@ -11045,9 +11047,63 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_CEZBANNER
+	{           // MT_CEZPOLE2
+		1118,           // doomednum
+		S_CEZPOLE,      // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		40*FRACUNIT,    // radius
+		224*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_CEZBANNER1
 		-1,             // doomednum
-		S_CEZBANNER,    // spawnstate
+		S_CEZBANNER1,    // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		40*FRACUNIT,    // radius
+		224*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_CEZBANNER2
+		-1,             // doomednum
+		S_CEZBANNER2,    // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -11261,8 +11317,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_WAVINGFLAG
-		1118,           // doomednum
+	{           // MT_WAVINGFLAG1
+		1128,           // doomednum
 		S_WAVINGFLAG,   // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
@@ -11278,8 +11334,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
 		0,              // speed
-		4*FRACUNIT,     // radius
-		104*FRACUNIT,   // height
+		8*FRACUNIT,     // radius
+		208*FRACUNIT,   // height
 		0,              // display offset
 		100,            // mass
 		0,              // damage
@@ -11288,9 +11344,36 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_WAVINGFLAGSEG
+	{           // MT_WAVINGFLAG2
+		1129,           // doomednum
+		S_WAVINGFLAG,   // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		8*FRACUNIT,     // radius
+		208*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SOLID,       // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_WAVINGFLAGSEG1
 		-1,             // doomednum
-		S_WAVINGFLAGSEG, // spawnstate
+		S_WAVINGFLAGSEG1, // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -11305,7 +11388,34 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
 		0,              // speed
-		4*FRACUNIT,     // radius
+		8*FRACUNIT,     // radius
+		1,              // height -- this is not a typo
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_WAVINGFLAGSEG2
+		-1,             // doomednum
+		S_WAVINGFLAGSEG2, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		8*FRACUNIT,     // radius
 		1,              // height -- this is not a typo
 		0,              // display offset
 		100,            // mass
@@ -19642,7 +19752,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		0,              // display offset
 		100,            // mass
 		0,              // damage
-		sfx_None,       // activesound
+		sfx_wbreak,     // activesound
 		MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
diff --git a/src/info.h b/src/info.h
index 44f08a4e951dc2f767c50b6d2502b10258d77940..a9a0321ec0a41df08f9c9e622496f8f6692fcf7d 100644
--- a/src/info.h
+++ b/src/info.h
@@ -2458,7 +2458,8 @@ typedef enum state
 
 	S_CEZFLOWER,
 	S_CEZPOLE,
-	S_CEZBANNER,
+	S_CEZBANNER1,
+	S_CEZBANNER2,
 	S_PINETREE,
 	S_CEZBUSH1,
 	S_CEZBUSH2,
@@ -2467,7 +2468,8 @@ typedef enum state
 	S_FLAMEHOLDER,
 	S_FIRETORCH,
 	S_WAVINGFLAG,
-	S_WAVINGFLAGSEG,
+	S_WAVINGFLAGSEG1,
+	S_WAVINGFLAGSEG2,
 	S_CRAWLASTATUE,
 	S_FACESTABBERSTATUE,
 	S_SUSPICIOUSFACESTABBERSTATUE_WAIT,
@@ -4295,8 +4297,10 @@ typedef enum mobj_type
 	MT_SMALLFIREBAR, // Small Firebar
 	MT_BIGFIREBAR, // Big Firebar
 	MT_CEZFLOWER, // Flower
-	MT_CEZPOLE, // Pole
-	MT_CEZBANNER, // Banner
+	MT_CEZPOLE1, // Pole (with red banner)
+	MT_CEZPOLE2, // Pole (with blue banner)
+	MT_CEZBANNER1, // Banner (red)
+	MT_CEZBANNER2, // Banner (blue)
 	MT_PINETREE, // Pine Tree
 	MT_CEZBUSH1, // Bush 1
 	MT_CEZBUSH2, // Bush 2
@@ -4304,8 +4308,10 @@ typedef enum mobj_type
 	MT_CANDLEPRICKET, // Candle pricket
 	MT_FLAMEHOLDER, // Flame holder
 	MT_FIRETORCH, // Fire torch
-	MT_WAVINGFLAG, // Waving flag
-	MT_WAVINGFLAGSEG, // Waving flag segment
+	MT_WAVINGFLAG1, // Waving flag (red)
+	MT_WAVINGFLAG2, // Waving flag (blue)
+	MT_WAVINGFLAGSEG1, // Waving flag segment (red)
+	MT_WAVINGFLAGSEG2, // Waving flag segment (blue)
 	MT_CRAWLASTATUE, // Crawla statue
 	MT_FACESTABBERSTATUE, // Facestabber statue
 	MT_SUSPICIOUSFACESTABBERSTATUE, // :eggthinking:
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 81a17ef208f4291439f7cfbeb46037c2259df118..1d69b238bcb2558ab197fb81d0d7d3ee15935d3d 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -539,7 +539,7 @@ static int lib_pSpawnLockOn(lua_State *L)
 	if (P_IsLocalPlayer(player)) // Only display it on your own view.
 	{
 		mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
-		visual->target = lockon;
+		P_SetTarget(&visual->target, lockon);
 		visual->flags2 |= MF2_DONTDRAW;
 		P_SetMobjStateNF(visual, state);
 	}
diff --git a/src/lua_blockmaplib.c b/src/lua_blockmaplib.c
index dabbdd9f629bc9a77379e2d46749e9d6ff22455d..2383bb32e1f77812b38f8602f7bccb7765a8cf4f 100644
--- a/src/lua_blockmaplib.c
+++ b/src/lua_blockmaplib.c
@@ -54,10 +54,12 @@ static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *
 				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
 			lua_pop(gL, 1);
 			blockfuncerror = true;
+			P_SetTarget(&bnext, NULL);
 			return 0; // *shrugs*
 		}
 		if (!lua_isnil(gL, -1))
 		{ // if nil, continue
+			P_SetTarget(&bnext, NULL);
 			if (lua_toboolean(gL, -1))
 				return 2; // stop whole search
 			else
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 0a3d356c9adb804b333152c7a712aa3458bcabb6..8bbbebe1d4c1340e974bd4df7e3d9b29d8ddaa1a 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -274,10 +274,19 @@ static int mobj_get(lua_State *L)
 		// bprev -- same deal as sprev above, but for the blockmap.
 		return UNIMPLEMENTED;
 	case mobj_hnext:
+		if (mo->hnext && P_MobjWasRemoved(mo->hnext))
+		{ // don't put invalid mobj back into Lua.
+			P_SetTarget(&mo->hnext, NULL);
+			return 0;
+		}
 		LUA_PushUserdata(L, mo->hnext, META_MOBJ);
 		break;
 	case mobj_hprev:
-		// implimented differently from sprev and bprev because SSNTails.
+		if (mo->hprev && P_MobjWasRemoved(mo->hprev))
+		{ // don't put invalid mobj back into Lua.
+			P_SetTarget(&mo->hprev, NULL);
+			return 0;
+		}
 		LUA_PushUserdata(L, mo->hprev, META_MOBJ);
 		break;
 	case mobj_type:
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index f3eb978f6163a1d7ef1ccd89c34a74e3f7199e4c..700dab21100acb79d222be025ae3ca4b728ab8a0 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -476,7 +476,12 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"followitem"))
 		plr->followitem = luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"followmobj"))
-		P_SetTarget(&plr->followmobj, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
+	{
+		mobj_t *mo = NULL;
+		if (!lua_isnil(L, 3))
+			mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
+		P_SetTarget(&plr->followmobj, mo);
+	}
 	else if (fastcmp(field,"actionspd"))
 		plr->actionspd = (INT32)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"mindash"))
@@ -560,9 +565,19 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"old_angle_pos"))
 		plr->old_angle_pos = luaL_checkangle(L, 3);
 	else if (fastcmp(field,"axis1"))
-		P_SetTarget(&plr->axis1, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
+	{
+		mobj_t *mo = NULL;
+		if (!lua_isnil(L, 3))
+			mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
+		P_SetTarget(&plr->axis1, mo);
+	}
 	else if (fastcmp(field,"axis2"))
-		P_SetTarget(&plr->axis2, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
+	{
+		mobj_t *mo = NULL;
+		if (!lua_isnil(L, 3))
+			mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
+		P_SetTarget(&plr->axis2, mo);
+	}
 	else if (fastcmp(field,"bumpertime"))
 		plr->bumpertime = (tic_t)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"flyangle"))
diff --git a/src/lua_script.c b/src/lua_script.c
index 85b9c403893a8d4b131fb03336b34cfea2cf1b13..deb644dc0351c169c60cb859952627278538241c 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -1127,14 +1127,15 @@ void LUA_Archive(void)
 		ArchiveExtVars(&players[i], "player");
 	}
 
-	for (i = 0; i < NUM_THINKERLISTS; i++)
-		for (th = thlist[i].next; th != &thlist[i]; th = th->next)
-			if (th->function.acp1 == (actionf_p1)P_MobjThinker)
-			{
-				// archive function will determine when to skip mobjs,
-				// and write mobjnum in otherwise.
-				ArchiveExtVars(th, "mobj");
-			}
+	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
+	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
+		// archive function will determine when to skip mobjs,
+		// and write mobjnum in otherwise.
+		ArchiveExtVars(th, "mobj");
+	}
 
 	WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
 
@@ -1163,11 +1164,14 @@ void LUA_UnArchive(void)
 
 	do {
 		mobjnum = READUINT32(save_p); // read a mobjnum
-		for (i = 0; i < NUM_THINKERLISTS; i++)
-			for (th = thlist[i].next; th != &thlist[i]; th = th->next)
-				if (th->function.acp1 == (actionf_p1)P_MobjThinker
-				&& ((mobj_t *)th)->mobjnum == mobjnum) // find matching mobj
-				UnArchiveExtVars(th); // apply variables
+		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
+		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+			if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
+				continue;
+			UnArchiveExtVars(th); // apply variables
+		}
 	} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
 
 	LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 734a7ae1831f917c7e0945ab5341d508ff2f1ff9..29e8c8a0231425ea2440227d28ee7377b898e514 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -579,6 +579,9 @@ void Command_Teleport_f(void)
 
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				if (mo2->type != MT_STARPOST)
@@ -1068,10 +1071,14 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
 
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo = (mobj_t *)th;
 			// get offset from mt, which points to old mapthings, then add new location
-			if (mo->spawnpoint)
-				mo->spawnpoint = (mo->spawnpoint - mt) + mapthings;
+			if (!mo->spawnpoint)
+				continue;
+			mo->spawnpoint = (mo->spawnpoint - mt) + mapthings;
 		}
 	}
 
diff --git a/src/m_menu.c b/src/m_menu.c
index dca2e552d734f9ee4b77f041adf6a06f9e7771bf..d9d3a6ba0b52ea33ab4083bc626698ea71de7e6a 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -2288,21 +2288,24 @@ static boolean MIT_SetCurBackground(UINT32 menutype, INT32 level, INT32 *retval,
 	(void)retval;
 	(void)fromoldest;
 
+	if (!menutype) // if there's nothing in this level, do nothing
+		return false;
+
 	if (menupres[menutype].bgcolor >= 0)
 	{
 		curbgcolor = menupres[menutype].bgcolor;
 		return true;
 	}
-	else if (menupres[menutype].bgname[0] && (!menupres[menutype].bghide || !titlemapinaction))
+	else if (menupres[menutype].bghide && titlemapinaction) // hide the background
 	{
-		strncpy(curbgname, menupres[menutype].bgname, 8);
-		curbgxspeed = menupres[menutype].titlescrollxspeed != INT32_MAX ? menupres[menutype].titlescrollxspeed : titlescrollxspeed;
-		curbgyspeed = menupres[menutype].titlescrollyspeed != INT32_MAX ? menupres[menutype].titlescrollyspeed : titlescrollyspeed;
+		curbghide = true;
 		return true;
 	}
-	else if (menupres[menutype].bghide && titlemapinaction) // hide the background
+	else if (menupres[menutype].bgname[0])
 	{
-		curbghide = true;
+		strncpy(curbgname, menupres[menutype].bgname, 8);
+		curbgxspeed = menupres[menutype].titlescrollxspeed != INT32_MAX ? menupres[menutype].titlescrollxspeed : titlescrollxspeed;
+		curbgyspeed = menupres[menutype].titlescrollyspeed != INT32_MAX ? menupres[menutype].titlescrollyspeed : titlescrollyspeed;
 		return true;
 	}
 	else if (!level)
@@ -2328,6 +2331,9 @@ static boolean MIT_ChangeMusic(UINT32 menutype, INT32 level, INT32 *retval, void
 	(void)retval;
 	(void)fromoldest;
 
+	if (!menutype) // if there's nothing in this level, do nothing
+		return false;
+
 	if (menupres[menutype].musname[0])
 	{
 		S_ChangeMusic(menupres[menutype].musname, menupres[menutype].mustrack, menupres[menutype].muslooping);
@@ -2352,6 +2358,9 @@ static boolean MIT_SetCurFadeValue(UINT32 menutype, INT32 level, INT32 *retval,
 	(void)retval;
 	(void)fromoldest;
 
+	if (!menutype) // if there's nothing in this level, do nothing
+		return false;
+
 	if (menupres[menutype].fadestrength >= 0)
 	{
 		curfadevalue = (menupres[menutype].fadestrength % 32);
@@ -2368,6 +2377,9 @@ static boolean MIT_SetCurHideTitlePics(UINT32 menutype, INT32 level, INT32 *retv
 	(void)retval;
 	(void)fromoldest;
 
+	if (!menutype) // if there's nothing in this level, do nothing
+		return false;
+
 	if (menupres[menutype].hidetitlepics >= 0)
 	{
 		curhidepics = menupres[menutype].hidetitlepics;
@@ -2469,7 +2481,7 @@ static void M_HandleMenuPresState(menu_t *newMenu)
 	curbgcolor = -1;
 	curbgxspeed = titlescrollxspeed;
 	curbgyspeed = titlescrollyspeed;
-	curbghide = true;
+	curbghide = (gamestate != GS_TIMEATTACK); // show in time attack, hide in other menus
 
 	// don't do the below during the in-game menus
 	if (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK)
@@ -8234,6 +8246,7 @@ static void M_TimeAttack(INT32 choice)
 	M_PatchSkinNameTable();
 
 	G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching
+	titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
 	M_SetupNextMenu(&SP_TimeAttackDef);
 	if (!M_CanShowLevelInList(cv_nextmap.value-1, -1) && levelselect.rows[0].maplist[0])
 		CV_SetValue(&cv_nextmap, levelselect.rows[0].maplist[0]);
@@ -8415,6 +8428,7 @@ static void M_NightsAttack(INT32 choice)
 
 	G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching
 	M_SetupNextMenu(&SP_NightsAttackDef);
+	titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
 	if (!M_CanShowLevelInList(cv_nextmap.value-1, -1) && levelselect.rows[0].maplist[0])
 		CV_SetValue(&cv_nextmap, levelselect.rows[0].maplist[0]);
 	else
diff --git a/src/p_enemy.c b/src/p_enemy.c
index f33ce68100b219c761a42b550b6e9b5516759ddb..88405437cc7865a4103f9a517934a93411e3acb7 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1391,7 +1391,7 @@ void A_StatueBurst(mobj_t *actor)
 		return;
 
 	new->angle = actor->angle;
-	new->target = actor->target;
+	P_SetTarget(&new->target, actor->target);
 	if (locvar2)
 		P_SetMobjState(new, (statenum_t)locvar2);
 	S_StartSound(new, new->info->attacksound);
@@ -2155,7 +2155,7 @@ void A_CrushclawLaunch(mobj_t *actor)
 		for (i = 0; (i < CSEGS); i++)
 		{
 			mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate);
-			prevchain->target = newchain;
+			P_SetTarget(&prevchain->target, newchain);
 			prevchain = newchain;
 		}
 		actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y);
@@ -3088,7 +3088,7 @@ void A_Boss1Laser(mobj_t *actor)
 	if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1)
 	{
 		point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE);
-		point->target = actor;
+		P_SetTarget(&point->target, actor);
 		point->destscale = 3*FRACUNIT;
 		point->scalespeed = FRACUNIT>>2;
 		point->fuse = TICRATE;
@@ -3488,9 +3488,11 @@ void A_1upThinker(mobj_t *actor)
 
 	if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0)
 	{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
-		if (actor->tracer) {
-			P_RemoveMobj(actor->tracer);
-			actor->tracer = NULL;
+		if (actor->tracer)
+		{
+			mobj_t *tracer = actor->tracer;
+			P_SetTarget(&actor->tracer, NULL);
+			P_RemoveMobj(tracer);
 		}
 		return;
 	}
@@ -3786,6 +3788,9 @@ void A_BossDeath(mobj_t *mo)
 	// if all bosses are dead
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 		if (mo2 != mo && (mo2->flags & MF_BOSS) && mo2->health > 0)
 			goto bossjustdie; // other boss not dead - just go straight to dying!
@@ -3884,6 +3889,9 @@ bossjustdie:
 			// scan the thinkers to find the runaway point
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				if (mo2->type != MT_BOSSFLYPOINT)
@@ -6137,6 +6145,9 @@ void A_RingExplode(mobj_t *actor)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2 == actor) // Don't explode yourself! Endless loop!
@@ -7263,7 +7274,7 @@ void A_Boss2PogoTarget(mobj_t *actor)
 	if (actor->info->missilestate) // spawn the pogo stick collision box
 	{
 		mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate);
-		pogo->target = actor;
+		P_SetTarget(&pogo->target, actor);
 	}
 
 	actor->reactiontime = 1;
@@ -7835,6 +7846,9 @@ void A_Boss3Path(mobj_t *actor)
 			// the number
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 				if (mo2->type != MT_BOSS3WAYPOINT)
 					continue;
@@ -8227,6 +8241,9 @@ void A_FindTarget(mobj_t *actor)
 	// scan the thinkers
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2->type == (mobjtype_t)locvar1)
@@ -8289,6 +8306,9 @@ void A_FindTracer(mobj_t *actor)
 	// scan the thinkers
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2->type == (mobjtype_t)locvar1)
@@ -8873,6 +8893,9 @@ void A_RemoteAction(mobj_t *actor)
 		// scan the thinkers
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
 			if (mo2->type == (mobjtype_t)locvar1)
@@ -9136,6 +9159,9 @@ void A_SetObjectTypeState(mobj_t *actor)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2->type == (mobjtype_t)loc2lw)
@@ -9771,6 +9797,9 @@ void A_CheckThingCount(mobj_t *actor)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2->type == (mobjtype_t)loc1up)
@@ -13061,9 +13090,10 @@ static boolean PIT_TNTExplode(mobj_t *nearby)
 		if (barrel->target == nearby)
 		{
 			mobj_t *tar = barrel->target; // temporarily store barrel's target
-			barrel->target = NULL;
+			P_SetTarget(&barrel->target, NULL);
 			P_DamageMobj(nearby, barrel, NULL, 1, 0);
-			barrel->target = tar;
+			if (!P_MobjWasRemoved(barrel))
+				P_SetTarget(&barrel->target, tar);
 		}
 		else
 		{
@@ -13565,7 +13595,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
 	door->extravalue2 = 0;
 
 	// Origin door
-	door->tracer = actor;
+	P_SetTarget(&door->tracer, actor);
 
 	//Back
 	door = P_SpawnMobj(x - c*d, y - s*d, z, MT_SALOONDOOR);
@@ -13578,7 +13608,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
 	door->extravalue2 = 0;
 
 	// Origin door
-	door->tracer = actor;
+	P_SetTarget(&door->tracer, actor);
 }
 
 // Function: A_MinecartSparkThink
diff --git a/src/p_floor.c b/src/p_floor.c
index ed2afd13d6ee6e06afeb64e813ed317c2bd59a37..c01e568d02f5c5a63d5604e2e745c526d1c9f70a 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1975,22 +1975,27 @@ void T_ThwompSector(levelspecthink_t *thwomp)
 	}
 	else // Not going anywhere, so look for players.
 	{
-		thinker_t *th;
-		mobj_t *mo;
-
 		if (!rover || (rover->flags & FF_EXISTS))
 		{
-			// scan the thinkers to find players!
-			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
+			UINT8 i;
+			// scan the players to find victims!
+			for (i = 0; i < MAXPLAYERS; i++)
 			{
-				mo = (mobj_t *)th;
-				if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator
-				    && mo->z <= thwomp->sector->ceilingheight
-					&& P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT)
-				{
-					thwomp->direction = -1;
-					break;
-				}
+				if (!playeringame[i])
+					continue;
+				if (players[i].spectator)
+					continue;
+				if (!players[i].mo)
+					continue;
+				if (!players[i].mo->health)
+					continue;
+				if (players[i].mo->z > thwomp->sector->ceilingheight)
+					continue;
+				if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96 * FRACUNIT)
+					continue;
+
+				thwomp->direction = -1;
+				break;
 			}
 		}
 
diff --git a/src/p_inter.c b/src/p_inter.c
index bdf88ff44a8ab73db753341329c97d7550afff5a..abf33429fa973f470499613c667771de0cde35fc 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -99,6 +99,9 @@ void P_ClearStarPost(INT32 postnum)
 	// scan the thinkers
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2->type != MT_STARPOST)
@@ -125,10 +128,15 @@ void P_ResetStarposts(void)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		post = (mobj_t *)th;
 
-		if (post->type == MT_STARPOST)
-			P_SetMobjState(post, post->info->spawnstate);
+		if (post->type != MT_STARPOST)
+			continue;
+
+		P_SetMobjState(post, post->info->spawnstate);
 	}
 }
 
@@ -828,19 +836,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 						// scan the thinkers to find the corresponding anchorpoint
 						for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 						{
+							if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+								continue;
+
 							mo2 = (mobj_t *)th;
 
-							if (mo2->type == MT_IDEYAANCHOR)
-							{
-								if (mo2->health == toucher->tracer->health) // do ideya numberes match?
-									anchorpoint = mo2;
-								else if (toucher->tracer->hnext && mo2->health == toucher->tracer->hnext->health)
-									anchorpoint2 = mo2;
+							if (mo2->type != MT_IDEYAANCHOR)
+								continue;
 
-								if ((!toucher->tracer->hnext && anchorpoint)
-									|| (toucher->tracer->hnext && anchorpoint && anchorpoint2))
-									break;
-							}
+							if (mo2->health == toucher->tracer->health) // do ideya numberes match?
+								anchorpoint = mo2;
+							else if (toucher->tracer->hnext && mo2->health == toucher->tracer->hnext->health)
+								anchorpoint2 = mo2;
+
+							if ((!toucher->tracer->hnext && anchorpoint)
+								|| (toucher->tracer->hnext && anchorpoint && anchorpoint2))
+								break;
 						}
 
 						if (anchorpoint)
@@ -919,6 +930,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				// scan the remaining thinkers
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (mo2 == special)
@@ -966,6 +980,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				// in from the paraloop. Isn't this just so efficient?
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > gatherradius)
@@ -1337,6 +1354,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				// scan the remaining thinkers to find koopa
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (mo2->type != MT_KOOPA)
@@ -1434,6 +1454,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (mo2->type != MT_STARPOST)
@@ -2572,9 +2595,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 				UINT32 i = 0; // to check how many clones we've removed
 
 				// scan the thinkers to make sure all the old pinch dummies are gone on death
-				// this can happen if the boss was hurt earlier than expected
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo = (mobj_t *)th;
 					if (mo->type != (mobjtype_t)target->info->mass)
 						continue;
diff --git a/src/p_local.h b/src/p_local.h
index 5216286c09886a2e28fc07a606d2727c6dc22592..cb8f95533fd2fde2922baa48b8950f52909895c3 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -61,8 +61,8 @@
 #define P_GetPlayerHeight(player) FixedMul(player->height, player->mo->scale)
 #define P_GetPlayerSpinHeight(player) FixedMul(player->spinheight, player->mo->scale)
 
-typedef enum{
-	THINK_LIMBO,
+typedef enum
+{
 	THINK_POLYOBJ,
 	THINK_MAIN,
 	THINK_MOBJ,
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 1be57399cba4ab3e7e12595adc8988975e08651a..0ca84096abd042cda08bfbba3d22f7c42b3ab387 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -1093,7 +1093,10 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *))
 	{
 		P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
 		if (!func(mobj))
+		{
+			P_SetTarget(&bnext, NULL);
 			return false;
+		}
 		if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue.
 		|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
 		{
diff --git a/src/p_mobj.c b/src/p_mobj.c
index d13b9a57ce6ff06ecfef61a887afe4aa3093bf38..633850892f1ea8d9f73dd7e589ef4e1a9ba5d29a 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -716,6 +716,9 @@ void P_EmeraldManager(void)
 
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)think;
 
 		if (mo->type == MT_EMERALDSPAWN)
@@ -3694,6 +3697,9 @@ void P_DestroyRobots(void)
 
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)think;
 		if (mo->health <= 0 || !(mo->flags & (MF_ENEMY|MF_BOSS)))
 			continue; // not a valid enemy
@@ -4426,6 +4432,9 @@ static void P_Boss3Thinker(mobj_t *mobj)
 			// this can happen if the boss was hurt earlier than expected
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 				if (mo2->type != (mobjtype_t)mobj->info->mass)
 					continue;
@@ -4524,6 +4533,9 @@ static void P_Boss3Thinker(mobj_t *mobj)
 			// the number
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 				if (mo2->type != MT_BOSS3WAYPOINT)
 					continue;
@@ -4832,8 +4844,8 @@ static void P_Boss4Thinker(mobj_t *mobj)
 				P_SetTarget(&seg->target, mobj);
 				for (i = 0; i < 9; i++)
 				{
-					seg->hnext = P_SpawnMobj(mobj->x, mobj->y, z, MT_EGGMOBILE4_MACE);
-					seg->hnext->hprev = seg;
+					P_SetTarget(&seg->hnext, P_SpawnMobj(mobj->x, mobj->y, z, MT_EGGMOBILE4_MACE));
+					P_SetTarget(&seg->hnext->hprev, seg);
 					seg = seg->hnext;
 				}
 			}
@@ -5245,6 +5257,9 @@ static void P_Boss7Thinker(mobj_t *mobj)
 				// Find waypoint he is closest to
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 					if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint)
 					{
@@ -5297,6 +5312,9 @@ static void P_Boss7Thinker(mobj_t *mobj)
 		// the waypoint to use
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 			if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && (mo2->spawnpoint->options & 7) == waypointNum)
 			{
@@ -5427,14 +5445,17 @@ static void P_Boss9Thinker(mobj_t *mobj)
 		// Build a hoop linked list of 'em!
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 			if (mo2->type == MT_BOSS9GATHERPOINT)
 			{
 				if (last)
-					last->hnext = mo2;
+					P_SetTarget(&last->hnext, mo2);
 				else
-					mobj->hnext = mo2;
-				mo2->hprev = last;
+					P_SetTarget(&mobj->hnext, mo2);
+				P_SetTarget(&mo2->hprev, last);
 				last = mo2;
 			}
 		}
@@ -6072,6 +6093,9 @@ mobj_t *P_GetClosestAxis(mobj_t *source)
 	// scan the thinkers to find the closest axis point
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2->type == MT_AXIS)
@@ -6841,12 +6865,14 @@ static void P_RemoveOverlay(mobj_t *thing)
 {
 	mobj_t *mo;
 	for (mo = overlaycap; mo; mo = mo->hnext)
-		if (mo->hnext == thing)
-		{
-			P_SetTarget(&mo->hnext, thing->hnext);
-			P_SetTarget(&thing->hnext, NULL);
-			return;
-		}
+	{
+		if (mo->hnext != thing)
+			continue;
+
+		P_SetTarget(&mo->hnext, thing->hnext);
+		P_SetTarget(&thing->hnext, NULL);
+		return;
+	}
 }
 
 void A_BossDeath(mobj_t *mo);
@@ -8046,7 +8072,8 @@ void P_MobjThinker(mobj_t *mobj)
 						mobj->tracer->z += mobj->height;
 				}
 				break;
-			case MT_WAVINGFLAG:
+			case MT_WAVINGFLAG1:
+			case MT_WAVINGFLAG2:
 				{
 					fixed_t base = (leveltime<<(FRACBITS+1));
 					mobj_t *seg = mobj->tracer, *prev = mobj;
@@ -9649,15 +9676,14 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 		case MT_BIGMINE:
 			mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS;
 			break;
-		case MT_WAVINGFLAG:
+		case MT_WAVINGFLAG1:
+		case MT_WAVINGFLAG2:
 			{
 				mobj_t *prev = mobj, *cur;
 				UINT8 i;
-				mobj->destscale <<= 2;
-				P_SetScale(mobj, mobj->destscale);
 				for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version
 				{
-					cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_WAVINGFLAGSEG);
+					cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, ((mobj->type == MT_WAVINGFLAG1) ? MT_WAVINGFLAGSEG1 : MT_WAVINGFLAGSEG2));;
 					P_SetTarget(&prev->tracer, cur);
 					cur->extravalue1 = i;
 					prev = cur;
@@ -9751,7 +9777,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			mobj->momx = 1; //stack hack
 			break;
 		case MT_MINECARTEND:
-			mobj->tracer = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID);
+			P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID));
 			mobj->tracer->angle = mobj->angle + ANGLE_90;
 			break;
 		default:
@@ -9960,37 +9986,28 @@ void P_RemoveMobj(mobj_t *mobj)
 
 	P_SetTarget(&mobj->hnext, P_SetTarget(&mobj->hprev, NULL));
 
-	// free block
 	// DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
-	if (mobj->flags & MF_NOTHINK && !mobj->thinker.next)
+#ifdef SCRAMBLE_REMOVED
+	// Invalidate mobj_t data to cause crashes if accessed!
+	memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
+#endif
+
+	// free block
+	if (!mobj->thinker.next)
 	{ // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through!
+		INT32 prevreferences;
 		if (!mobj->thinker.references)
 		{
-#ifdef SCRAMBLE_REMOVED
-			// Invalidate mobj_t data to cause crashes if accessed!
-			memset(mobj, 0xff, sizeof(mobj_t));
-#endif
-			Z_Free(mobj); // No refrences? Can be removed immediately! :D
-		}
-		else
-		{ // Add thinker just to delay removing it until refrences are gone.
-			mobj->flags &= ~MF_NOTHINK;
-			P_AddThinker(THINK_MOBJ, (thinker_t *)mobj);
-#ifdef SCRAMBLE_REMOVED
-			// Invalidate mobj_t data to cause crashes if accessed!
-			memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
-#endif
-			P_RemoveThinker((thinker_t *)mobj);
+			Z_Free(mobj); // No refrrences? Can be removed immediately! :D
+			return;
 		}
+
+		prevreferences = mobj->thinker.references;
+		P_AddThinker(THINK_MOBJ, (thinker_t *)mobj);
+		mobj->thinker.references = prevreferences;
 	}
-	else
-	{
-#ifdef SCRAMBLE_REMOVED
-		// Invalidate mobj_t data to cause crashes if accessed!
-		memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
-#endif
-		P_RemoveThinker((thinker_t *)mobj);
-	}
+
+	P_RemoveThinker((thinker_t *)mobj);
 }
 
 // This does not need to be added to Lua.
@@ -11737,13 +11754,14 @@ ML_EFFECT5 : Don't stop thinking when too far away
 			P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0,          0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270;
 		}
 		break;
-	case MT_CEZPOLE:
+	case MT_CEZPOLE1:
+	case MT_CEZPOLE2:
 		{ // Spawn the banner
 			angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS);
 			P_SpawnMobjFromMobj(mobj,
 				P_ReturnThrustX(mobj, mobjangle, 4<<FRACBITS),
 				P_ReturnThrustY(mobj, mobjangle, 4<<FRACBITS),
-				0, MT_CEZBANNER)->angle = mobjangle + ANGLE_90;
+				0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90;
 		}
 			break;
 	case MT_HHZTREE_TOP:
@@ -11821,6 +11839,9 @@ ML_EFFECT5 : Don't stop thinking when too far away
 		// See if other starposts exist in this level that have the same value.
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
 			if (mo2 == mobj)
@@ -12136,11 +12157,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			// Link all the sprites in the hoop together
 			if (nextmobj)
 			{
-				mobj->hprev = nextmobj;
-				mobj->hprev->hnext = mobj;
+				P_SetTarget(&mobj->hprev, nextmobj);
+				P_SetTarget(&mobj->hprev->hnext, mobj);
 			}
 			else
-				mobj->hprev = mobj->hnext = NULL;
+				P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
 
 			nextmobj = mobj;
 		}
@@ -12166,9 +12187,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			mobj->z -= mobj->height/2;
 
 			// Link all the collision sprites together.
-			mobj->hnext = NULL;
-			mobj->hprev = nextmobj;
-			mobj->hprev->hnext = mobj;
+			P_SetTarget(&mobj->hnext, NULL);
+			P_SetTarget(&mobj->hprev, nextmobj);
+			P_SetTarget(&mobj->hprev->hnext, mobj);
 
 			nextmobj = mobj;
 		}
@@ -12193,9 +12214,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			mobj->z -= mobj->height/2;
 
 			// Link all the collision sprites together.
-			mobj->hnext = NULL;
-			mobj->hprev = nextmobj;
-			mobj->hprev->hnext = mobj;
+			P_SetTarget(&mobj->hnext, NULL);
+			P_SetTarget(&mobj->hprev, nextmobj);
+			P_SetTarget(&mobj->hprev->hnext, mobj);
 
 			nextmobj = mobj;
 		}
@@ -12278,11 +12299,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			// Link all the sprites in the hoop together
 			if (nextmobj)
 			{
-				mobj->hprev = nextmobj;
-				mobj->hprev->hnext = mobj;
+				P_SetTarget(&mobj->hprev, nextmobj);
+				P_SetTarget(&mobj->hprev->hnext, mobj);
 			}
 			else
-				mobj->hprev = mobj->hnext = NULL;
+				P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
 
 			nextmobj = mobj;
 		}
@@ -12319,9 +12340,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 				mobj->z -= mobj->height/2;
 
 				// Link all the collision sprites together.
-				mobj->hnext = NULL;
-				mobj->hprev = nextmobj;
-				mobj->hprev->hnext = mobj;
+				P_SetTarget(&mobj->hnext, NULL);
+				P_SetTarget(&mobj->hprev, nextmobj);
+				P_SetTarget(&mobj->hprev->hnext, mobj);
 
 				nextmobj = mobj;
 			}
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index 09d449b3964944ff724c2c1edfd5a6281f6301d0..475fa41b725b03b3146e2f34322333e32b46d574 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -1495,6 +1495,7 @@ void Polyobj_InitLevel(void)
 	mqueue_t    anchorqueue;
 	mobjqitem_t *qitem;
 	INT32 i, numAnchors = 0;
+	mobj_t *mo;
 
 	M_QueueInit(&spawnqueue);
 	M_QueueInit(&anchorqueue);
@@ -1510,7 +1511,10 @@ void Polyobj_InitLevel(void)
 	// the mobj_t pointers on a queue for use below.
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
-		mobj_t *mo = (mobj_t *)th;
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
+		mo = (mobj_t *)th;
 
 		if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM ||
 			mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM)
@@ -1815,6 +1819,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 	// We redo this each tic to make savegame compatibility easier.
 	for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
 	{
+		if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)wp;
 
 		if (mo2->type != MT_TUBEWAYPOINT)
@@ -1893,28 +1900,31 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 			// Find next waypoint
 			for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
 			{
+				if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)wp;
 
 				if (mo2->type != MT_TUBEWAYPOINT)
 					continue;
 
-				if (mo2->threshold == th->sequence)
+				if (mo2->threshold != th->sequence)
+					continue;
+
+				if (th->direction == -1)
 				{
-					if (th->direction == -1)
+					if (mo2->health == target->health - 1)
 					{
-						if (mo2->health == target->health - 1)
-						{
-							waypoint = mo2;
-							break;
-						}
+						waypoint = mo2;
+						break;
 					}
-					else
+				}
+				else
+				{
+					if (mo2->health == target->health + 1)
 					{
-						if (mo2->health == target->health + 1)
-						{
-							waypoint = mo2;
-							break;
-						}
+						waypoint = mo2;
+						break;
 					}
 				}
 			}
@@ -1929,27 +1939,30 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 
 				for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
 				{
+					if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)wp;
 
 					if (mo2->type != MT_TUBEWAYPOINT)
 						continue;
 
-					if (mo2->threshold == th->sequence)
+					if (mo2->threshold != th->sequence)
+						continue;
+
+					if (th->direction == -1)
 					{
-						if (th->direction == -1)
-						{
-							if (waypoint == NULL)
-								waypoint = mo2;
-							else if (mo2->health > waypoint->health)
-								waypoint = mo2;
-						}
-						else
+						if (waypoint == NULL)
+							waypoint = mo2;
+						else if (mo2->health > waypoint->health)
+							waypoint = mo2;
+					}
+					else
+					{
+						if (mo2->health == 0)
 						{
-							if (mo2->health == 0)
-							{
-								waypoint = mo2;
-								break;
-							}
+							waypoint = mo2;
+							break;
 						}
 					}
 				}
@@ -1963,28 +1976,31 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 
 				for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
 				{
+					if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)wp;
 
 					if (mo2->type != MT_TUBEWAYPOINT)
 						continue;
 
-					if (mo2->threshold == th->sequence)
+					if (mo2->threshold != th->sequence)
+						continue;
+
+					if (th->direction == -1)
 					{
-						if (th->direction == -1)
+						if (mo2->health == target->health - 1)
 						{
-							if (mo2->health == target->health - 1)
-							{
-								waypoint = mo2;
-								break;
-							}
+							waypoint = mo2;
+							break;
 						}
-						else
+					}
+					else
+					{
+						if (mo2->health == target->health + 1)
 						{
-							if (mo2->health == target->health + 1)
-							{
-								waypoint = mo2;
-								break;
-							}
+							waypoint = mo2;
+							break;
 						}
 					}
 				}
@@ -2511,36 +2527,39 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 	// Find the first waypoint we need to use
 	for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
 	{
+		if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)wp;
 
 		if (mo2->type != MT_TUBEWAYPOINT)
 			continue;
 
-		if (mo2->threshold == th->sequence)
+		if (mo2->threshold != th->sequence)
+			continue;
+
+		if (th->direction == -1) // highest waypoint #
 		{
-			if (th->direction == -1) // highest waypoint #
+			if (mo2->health == 0)
+				last = mo2;
+			else
 			{
-				if (mo2->health == 0)
-					last = mo2;
-				else
-				{
-					if (first == NULL)
-						first = mo2;
-					else if (mo2->health > first->health)
-						first = mo2;
-				}
+				if (first == NULL)
+					first = mo2;
+				else if (mo2->health > first->health)
+					first = mo2;
 			}
-			else // waypoint 0
+		}
+		else // waypoint 0
+		{
+			if (mo2->health == 0)
+				first = mo2;
+			else
 			{
-				if (mo2->health == 0)
-					first = mo2;
-				else
-				{
-					if (last == NULL)
-						last = mo2;
-					else if (mo2->health > last->health)
-						last = mo2;
-				}
+				if (last == NULL)
+					last = mo2;
+				else if (mo2->health > last->health)
+					last = mo2;
 			}
 		}
 	}
@@ -2579,28 +2598,31 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 	target = first;
 	/*for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
 	{
+		if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)wp;
 
 		if (mo2->type != MT_TUBEWAYPOINT)
 			continue;
 
-		if (mo2->threshold == th->sequence)
+		if (mo2->threshold != th->sequence)
+			continue;
+
+		if (th->direction == -1) // highest waypoint #
 		{
-			if (th->direction == -1) // highest waypoint #
+			if (mo2->health == first->health - 1)
 			{
-				if (mo2->health == first->health - 1)
-				{
-					target = mo2;
-					break;
-				}
+				target = mo2;
+				break;
 			}
-			else // waypoint 0
+		}
+		else // waypoint 0
+		{
+			if (mo2->health == first->health + 1)
 			{
-				if (mo2->health == first->health + 1)
-				{
-					target = mo2;
-					break;
-				}
+				target = mo2;
+				break;
 			}
 		}
 	}*/
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 06baa952811e65825376e5869472ba320967d872..09df38eb07416af7e5f3cbda308d05d332acdb54 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -2174,7 +2174,6 @@ static void P_NetArchiveThinkers(void)
 	for (i = 0; i < NUM_THINKERLISTS; i++)
 	{
 		UINT32 numsaved = 0;
-
 		// save off the current thinkers
 		for (th = thlist[i].next; th != &thlist[i]; th = th->next)
 		{
@@ -2405,12 +2404,12 @@ static void P_NetArchiveThinkers(void)
 			}
 #endif // ESLOPE
 #ifdef PARANOIA
-			else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection
+			else if (th->function.acp1 != P_RemoveThinkerDelayed) // wait garbage collection
 				I_Error("unknown thinker type %p", th->function.acp1);
 #endif
 		}
 
-		CONS_Debug(DBG_NETPLAY, "%u thinkers saved\n", numsaved);
+		CONS_Debug(DBG_NETPLAY, "%u thinkers saved in list %d\n", numsaved, i);
 
 		WRITEUINT8(save_p, tc_end);
 	}
@@ -2427,9 +2426,14 @@ mobj_t *P_FindNewPosition(UINT32 oldposition)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mobj = (mobj_t *)th;
-		if (mobj->mobjnum == oldposition)
-			return mobj;
+		if (mobj->mobjnum != oldposition)
+			continue;
+
+		return mobj;
 	}
 	CONS_Debug(DBG_GAMELOGIC, "mobj not found\n");
 	return NULL;
@@ -3404,7 +3408,7 @@ static void P_NetUnArchiveThinkers(void)
 	{
 		for (;;)
 		{
-			thinker_t* th;
+			thinker_t* th = NULL;
 			tclass = READUINT8(save_p);
 
 			if (tclass == tc_end)
@@ -3597,22 +3601,22 @@ static void P_NetUnArchiveThinkers(void)
 				P_AddThinker(i, th);
 		}
 
-		CONS_Debug(DBG_NETPLAY, "%u thinkers loaded\n", numloaded);
+		CONS_Debug(DBG_NETPLAY, "%u thinkers loaded in list %d\n", numloaded, i);
+	}
 
-		if (restoreNum)
+	if (restoreNum)
+	{
+		executor_t *delay = NULL;
+		UINT32 mobjnum;
+		for (currentthinker = thlist[i].next; currentthinker != &thlist[i];
+		currentthinker = currentthinker->next)
 		{
-			executor_t *delay = NULL;
-			UINT32 mobjnum;
-			for (currentthinker = thlist[i].next; currentthinker != &thlist[i];
-				currentthinker = currentthinker->next)
-			{
-				if (currentthinker->function.acp1 == (actionf_p1)T_ExecutorDelay)
-				{
-					delay = (void *)currentthinker;
-					if ((mobjnum = (UINT32)(size_t)delay->caller))
-						delay->caller = P_FindNewPosition(mobjnum);
-				}
-			}
+			if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay)
+				continue;
+			delay = (void *)currentthinker;
+			if (!(mobjnum = (UINT32)(size_t)delay->caller))
+				continue;
+			delay->caller = P_FindNewPosition(mobjnum);
 		}
 	}
 }
@@ -3723,6 +3727,9 @@ static inline void P_FinishMobjs(void)
 	for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
 		currentthinker = currentthinker->next)
 	{
+		if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mobj = (mobj_t *)currentthinker;
 		mobj->info = &mobjinfo[mobj->type];
 	}
@@ -3738,6 +3745,9 @@ static void P_RelinkPointers(void)
 	for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
 		currentthinker = currentthinker->next)
 	{
+		if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mobj = (mobj_t *)currentthinker;
 
 		if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
@@ -4115,6 +4125,9 @@ void P_SaveNetGame(void)
 	// Assign the mobjnumber for pointer tracking
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mobj = (mobj_t *)th;
 		if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
 			continue;
diff --git a/src/p_setup.c b/src/p_setup.c
index 7aaad233d3aa160ecfcdd2c326fa0939a113cae9..c0aa7ffa355c109933a6180d559c0cf9032617b8 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -817,6 +817,9 @@ void P_ReloadRings(void)
 	// scan the thinkers to find rings/spheres/hoops to unset
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)th;
 
 		if (mo->type == MT_HOOPCENTER)
@@ -883,6 +886,9 @@ void P_SwitchSpheresBonusMode(boolean bonustime)
 	// scan the thinkers to find spheres to switch
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)th;
 
 		if (mo->type != MT_BLUESPHERE && mo->type != MT_NIGHTSCHIP
@@ -2284,7 +2290,6 @@ static void P_LevelInitStuff(void)
 void P_LoadThingsOnly(void)
 {
 	// Search through all the thinkers.
-	mobj_t *mo;
 	thinker_t *think;
 	INT32 i, viewid = -1, centerid = -1; // for skyboxes
 
@@ -2301,10 +2306,9 @@ void P_LoadThingsOnly(void)
 
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
-		mo = (mobj_t *)think;
-
-		if (mo)
-			P_RemoveMobj(mo);
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+		P_RemoveMobj((mobj_t *)think);
 	}
 
 	P_LevelInitStuff();
@@ -2864,7 +2868,10 @@ boolean P_SetupLevel(boolean skipprecip)
 
 		// reset the player starts
 		for (i = 0; i < MAXPLAYERS; i++)
-			playerstarts[i] = NULL;
+			playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
+
+		for (i = 0; i < MAX_DM_STARTS; i++)
+			deathmatchstarts[i] = NULL;
 
 		for (i = 0; i < 2; i++)
 			skyboxmo[i] = NULL;
@@ -2900,7 +2907,10 @@ boolean P_SetupLevel(boolean skipprecip)
 
 		// reset the player starts
 		for (i = 0; i < MAXPLAYERS; i++)
-			playerstarts[i] = NULL;
+			playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
+
+		for (i = 0; i < MAX_DM_STARTS; i++)
+			deathmatchstarts[i] = NULL;
 
 		for (i = 0; i < 2; i++)
 			skyboxmo[i] = NULL;
diff --git a/src/p_spec.c b/src/p_spec.c
index 4a7ec59e94d47b70f62d82938a611453227b09ef..3cd0461e242f13e6149121f192a869df83ff9124 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -2260,7 +2260,7 @@ void P_SwitchWeather(INT32 weathernum)
 		thinker_t *think;
 		precipmobj_t *precipmobj;
 
-		for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
+		for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next)
 		{
 			if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
 				continue; // not a precipmobj thinker
@@ -2276,7 +2276,7 @@ void P_SwitchWeather(INT32 weathernum)
 		precipmobj_t *precipmobj;
 		state_t *st;
 
-		for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
+		for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next)
 		{
 			if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
 				continue; // not a precipmobj thinker
@@ -3992,6 +3992,9 @@ void P_SetupSignExit(player_t *player)
 	// spin all signposts in the level then.
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		thing = (mobj_t *)think;
 		if (thing->type != MT_SIGN)
 			continue;
@@ -4017,20 +4020,18 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
 {
 	thinker_t *think;
 	mobj_t *mo;
-	INT32 specialnum = 0;
+	INT32 specialnum = (flag == MT_REDFLAG) ? 3 : 4;
 
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)think;
 
 		if (mo->type != flag)
 			continue;
 
-		if (mo->type == MT_REDFLAG)
-			specialnum = 3;
-		else if (mo->type == MT_BLUEFLAG)
-			specialnum = 4;
-
 		if (GETSECSPECIAL(mo->subsector->sector->special, 4) == specialnum)
 			return true;
 		else if (mo->subsector->sector->ffloors) // Check the 3D floors
@@ -4045,9 +4046,11 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
 				if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum)
 					continue;
 
-				if (mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
-					&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
-					return true;
+				if (!(mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
+					&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)))
+					continue;
+
+				return true;
 			}
 		}
 	}
@@ -4451,9 +4454,12 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
 			// The chimps are my friends.. heeheeheheehehee..... - LouisJM
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
 				mo2 = (mobj_t *)th;
-				if (mo2->type == MT_EGGTRAP)
-					P_KillMobj(mo2, NULL, player->mo, 0);
+				if (mo2->type != MT_EGGTRAP)
+					continue;
+				P_KillMobj(mo2, NULL, player->mo, 0);
 			}
 
 			// clear the special so you can't push the button twice.
@@ -4754,14 +4760,20 @@ DoneSection2:
 				// to find the first waypoint
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
-					if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence
-						&& mo2->health == 0)
-					{
-						waypoint = mo2;
-						break;
-					}
+					if (mo2->type != MT_TUBEWAYPOINT)
+						continue;
+					if (mo2->threshold != sequence)
+						continue;
+					if (mo2->health != 0)
+						continue;
+
+					waypoint = mo2;
+					break;
 				}
 
 				if (!waypoint)
@@ -4830,15 +4842,20 @@ DoneSection2:
 				// to find the last waypoint
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
-					if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence)
-					{
-						if (!waypoint)
-							waypoint = mo2;
-						else if (mo2->health > waypoint->health)
-							waypoint = mo2;
-					}
+					if (mo2->type != MT_TUBEWAYPOINT)
+						continue;
+					if (mo2->threshold != sequence)
+						continue;
+
+					if (!waypoint)
+						waypoint = mo2;
+					else if (mo2->health > waypoint->health)
+						waypoint = mo2;
 				}
 
 				if (!waypoint)
@@ -4979,6 +4996,9 @@ DoneSection2:
 				// to find the first waypoint
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (mo2->type != MT_TUBEWAYPOINT)
@@ -5014,6 +5034,9 @@ DoneSection2:
 				// Find waypoint before this one (waypointlow)
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (mo2->type != MT_TUBEWAYPOINT)
@@ -5038,6 +5061,9 @@ DoneSection2:
 				// Find waypoint after this one (waypointhigh)
 				for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 				{
+					if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+						continue;
+
 					mo2 = (mobj_t *)th;
 
 					if (mo2->type != MT_TUBEWAYPOINT)
diff --git a/src/p_tick.c b/src/p_tick.c
index 56f91d820e4200eb7cfc8f73d1a6dd3b6868a26d..a0f6edef9b8f6cac74b987204d9845dfbb832f9e 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -44,6 +44,9 @@ void Command_Numthinkers_f(void)
 	INT32 count = 0;
 	actionf_p1 action;
 	thinker_t *think;
+	thinklistnum_t start = 0;
+	thinklistnum_t end = NUM_THINKERLISTS - 1;
+	thinklistnum_t i;
 
 	if (gamestate != GS_LEVEL)
 	{
@@ -70,6 +73,7 @@ void Command_Numthinkers_f(void)
 	switch (num)
 	{
 		case 1:
+			start = end = THINK_MOBJ;
 			action = (actionf_p1)P_MobjThinker;
 			CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
 			break;
@@ -82,14 +86,17 @@ void Command_Numthinkers_f(void)
 			CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
 			break;*/
 		case 2:
+			start = end = THINK_PRECIP;
 			action = (actionf_p1)P_NullPrecipThinker;
 			CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");
 			break;
 		case 3:
+			start = end = THINK_MAIN;
 			action = (actionf_p1)T_Friction;
 			CONS_Printf(M_GetText("Number of %s: "), "T_Friction");
 			break;
 		case 4:
+			start = end = THINK_MAIN;
 			action = (actionf_p1)T_Pusher;
 			CONS_Printf(M_GetText("Number of %s: "), "T_Pusher");
 			break;
@@ -102,12 +109,15 @@ void Command_Numthinkers_f(void)
 			return;
 	}
 
-	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
+	for (i = start; i <= end; i++)
 	{
-		if (think->function.acp1 != action)
-			continue;
+		for (think = thlist[i].next; think != &thlist[i]; think = think->next)
+		{
+			if (think->function.acp1 != action)
+				continue;
 
-		count++;
+			count++;
+		}
 	}
 
 	CONS_Printf("%d\n", count);
@@ -141,6 +151,9 @@ void Command_CountMobjs_f(void)
 
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				if (((mobj_t *)th)->type == i)
 					count++;
 			}
@@ -158,6 +171,9 @@ void Command_CountMobjs_f(void)
 
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			if (((mobj_t *)th)->type == i)
 				count++;
 		}
@@ -180,6 +196,10 @@ void P_InitThinkers(void)
 // Adds a new thinker at the end of the list.
 void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
 {
+#ifdef PARANOIA
+	I_Assert(n >= 0 && n < NUM_THINKERLISTS);
+#endif
+
 	thlist[n].prev->next = thinker;
 	thinker->next = &thlist[n];
 	thinker->prev = thlist[n].prev;
@@ -206,22 +226,33 @@ static thinker_t *currentthinker;
 // remove it, and set currentthinker to one node preceeding it, so
 // that the next step in P_RunThinkers() will get its successor.
 //
-void P_RemoveThinkerDelayed(void *pthinker)
+void P_RemoveThinkerDelayed(thinker_t *thinker)
 {
-	thinker_t *thinker = pthinker;
-	if (!thinker->references)
+	thinker_t *next;
+#ifdef PARANOIA
+#define BEENAROUNDBIT (0x40000000) // has to be sufficiently high that it's unlikely to happen in regular gameplay. If you change this, pay attention to the bit pattern of INT32_MIN.
+	if (thinker->references & ~BEENAROUNDBIT)
 	{
-		{
-			/* Remove from main thinker list */
-			thinker_t *next = thinker->next;
-			/* Note that currentthinker is guaranteed to point to us,
-			 * and since we're freeing our memory, we had better change that. So
-			 * point it to thinker->prev, so the iterator will correctly move on to
-			 * thinker->prev->next = thinker->next */
-			(next->prev = currentthinker = thinker->prev)->next = next;
-		}
-		Z_Free(thinker);
+		if (thinker->references & BEENAROUNDBIT) // Usually gets cleared up in one frame; what's going on here, then?
+			CONS_Printf("Number of potentially faulty references: %d\n", (thinker->references & ~BEENAROUNDBIT));
+		thinker->references |= BEENAROUNDBIT;
+		return;
 	}
+#undef BEENAROUNDBIT
+#else
+	if (thinker->references)
+		return;
+#endif
+
+	/* Remove from main thinker list */
+	next = thinker->next;
+	/* Note that currentthinker is guaranteed to point to us,
+	* and since we're freeing our memory, we had better change that. So
+	* point it to thinker->prev, so the iterator will correctly move on to
+	* thinker->prev->next = thinker->next */
+	(next->prev = currentthinker = thinker->prev)->next = next;
+
+	Z_Free(thinker);
 }
 
 //
@@ -238,23 +269,10 @@ void P_RemoveThinkerDelayed(void *pthinker)
 //
 void P_RemoveThinker(thinker_t *thinker)
 {
-	thinker_t *next = thinker->next;
 #ifdef HAVE_BLUA
 	LUA_InvalidateUserdata(thinker);
 #endif
-	thinker->function.acp1 = P_RemoveThinkerDelayed;
-
-	if (currentthinker == thinker)
-		currentthinker = thinker->prev;
-
-	// Remove thinker from its current list.
-	(next->prev = thinker->prev)->next = next;
-
-	// Now add it to the limbo list
-	thlist[THINK_LIMBO].prev->next = thinker;
-	thinker->next = &thlist[THINK_LIMBO];
-	thinker->prev = thlist[THINK_LIMBO].prev;
-	thlist[THINK_LIMBO].prev = thinker;
+	thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed;
 }
 
 /*
@@ -307,8 +325,10 @@ static inline void P_RunThinkers(void)
 	{
 		for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next)
 		{
-			if (currentthinker->function.acp1)
-				currentthinker->function.acp1(currentthinker);
+#ifdef PARANOIA
+			I_Assert(currentthinker->function.acp1 != NULL)
+#endif
+			currentthinker->function.acp1(currentthinker);
 		}
 	}
 
diff --git a/src/p_tick.h b/src/p_tick.h
index 169c54c8e798f099d7bbca00e720dacdc86f42ef..8551ccc7606015b895c928c197328f2ee1247289 100644
--- a/src/p_tick.h
+++ b/src/p_tick.h
@@ -27,7 +27,7 @@ void Command_CountMobjs_f(void);
 void P_Ticker(boolean run);
 void P_PreTicker(INT32 frames);
 void P_DoTeamscrambling(void);
-void P_RemoveThinkerDelayed(void *pthinker); //killed
+void P_RemoveThinkerDelayed(thinker_t *thinker); //killed
 mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target);   // killough 11/98
 
 #endif
diff --git a/src/p_user.c b/src/p_user.c
index 79a726fe6169020e2dd927a021dae267ae17d4bc..b758cebe49a5e033184d58cbb9439f929cedb2ef 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -345,9 +345,16 @@ UINT8 P_FindLowestMare(void)
 	// to find the egg capsule with the lowest mare
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
-		if (mo2->type == MT_EGGCAPSULE && mo2->health > 0)
+		if (mo2->type != MT_EGGCAPSULE)
+			continue;
+		if (mo2->health <= 0)
+			continue;
+
 		{
 			const UINT8 threshold = (UINT8)mo2->threshold;
 			if (mare == 255)
@@ -391,29 +398,32 @@ boolean P_TransferToNextMare(player_t *player)
 	// to find the closest axis point
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
-		if (mo2->type == MT_AXIS)
+		if (mo2->type != MT_AXIS)
+			continue;
+
+		if (mo2->threshold != mare)
+			continue;
+
+		if (closestaxis == NULL)
 		{
-			if (mo2->threshold == mare)
-			{
-				if (closestaxis == NULL)
-				{
-					closestaxis = mo2;
-					lowestaxisnum = mo2->health;
-					dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
-				}
-				else if (mo2->health < lowestaxisnum)
-				{
-					dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
+			closestaxis = mo2;
+			lowestaxisnum = mo2->health;
+			dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
+		}
+		else if (mo2->health < lowestaxisnum)
+		{
+			dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
 
-					if (dist1 < dist2)
-					{
-						closestaxis = mo2;
-						lowestaxisnum = mo2->health;
-						dist2 = dist1;
-					}
-				}
+			if (dist1 < dist2)
+			{
+				closestaxis = mo2;
+				lowestaxisnum = mo2->health;
+				dist2 = dist1;
 			}
 		}
 	}
@@ -439,17 +449,22 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
 	// to find the closest axis point
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		// Axis things are only at beginning of list.
 		if (!(mo2->flags2 & MF2_AXIS))
 			return NULL;
 
-		if (mo2->type == MT_AXIS)
-		{
-			if (mo2->health == axisnum && mo2->threshold == mare)
-				return mo2;
-		}
+		if (mo2->type != MT_AXIS)
+			continue;
+		if (mo2->health != axisnum)
+			continue;
+		if (mo2->threshold != mare)
+			continue;
+		return mo2;
 	}
 
 	return NULL;
@@ -469,17 +484,22 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
 	// to find the closest axis point
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		// Axis things are only at beginning of list.
 		if (!(mo2->flags2 & MF2_AXIS))
 			return NULL;
 
-		if (mo2->type == type)
-		{
-			if (mo2->health == axisnum && mo2->threshold == mare)
-				return mo2;
-		}
+		if (mo2->type != type)
+			continue;
+		if (mo2->health != axisnum)
+			continue;
+		if (mo2->threshold != mare)
+			continue;
+		return mo2;
 	}
 
 	return NULL;
@@ -505,27 +525,31 @@ void P_TransferToAxis(player_t *player, INT32 axisnum)
 	// to find the closest axis point
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
-		if (mo2->type == MT_AXIS)
+		if (mo2->type != MT_AXIS)
+			continue;
+		if (mo2->health != axisnum)
+			continue;
+		if (mo2->threshold != mare)
+			continue;
+
+		if (closestaxis == NULL)
 		{
-			if (mo2->health == axisnum && mo2->threshold == mare)
-			{
-				if (closestaxis == NULL)
-				{
-					closestaxis = mo2;
-					dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
-				}
-				else
-				{
-					dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y)-mo2->radius;
+			closestaxis = mo2;
+			dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
+		}
+		else
+		{
+			dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
 
-					if (dist1 < dist2)
-					{
-						closestaxis = mo2;
-						dist2 = dist1;
-					}
-				}
+			if (dist1 < dist2)
+			{
+				closestaxis = mo2;
+				dist2 = dist1;
 			}
 		}
 	}
@@ -602,6 +626,9 @@ static void P_DeNightserizePlayer(player_t *player)
 	// Check to see if the player should be killed.
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 		if (!(mo2->type == MT_NIGHTSDRONE))
 			continue;
@@ -1617,6 +1644,9 @@ void P_SpawnShieldOrb(player_t *player)
 	// blaze through the thinkers to see if an orb already exists!
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		shieldobj = (mobj_t *)th;
 
 		if (shieldobj->type == orbtype && shieldobj->target == player->mo)
@@ -2019,7 +2049,7 @@ boolean P_PlayerHitFloor(player_t *player)
 					fixed_t mu = FixedMul(player->maxdash, player->mo->scale);
 					fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy);
 					fixed_t ev;
-					mobj_t *missile;
+					mobj_t *missile = NULL;
 					if (mu2 < mu)
 						mu2 = mu;
 					ev = (50*FRACUNIT - (mu/25))/50;
@@ -3625,7 +3655,8 @@ static void P_DoTeeter(player_t *player)
 		if (teeter) // only bother with objects as a last resort if you were already teetering
 		{
 			mobj_t *oldtmthing = tmthing;
-			tmthing = teeterer = player->mo;
+			teeterer = player->mo;
+			P_SetTarget(&tmthing, teeterer);
 			teeterxl = teeterxh = player->mo->x;
 			teeteryl = teeteryh = player->mo->y;
 			couldteeter = false;
@@ -3639,7 +3670,7 @@ static void P_DoTeeter(player_t *player)
 				}
 teeterdone:
 			teeter = solidteeter;
-			tmthing = oldtmthing; // restore old tmthing, goodness knows what the game does with this before mobj thinkers
+			P_SetTarget(&tmthing, oldtmthing); // restore old tmthing, goodness knows what the game does with this before mobj thinkers
 		}
 	}
 	if (teeter)
@@ -4314,7 +4345,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 							if (P_IsLocalPlayer(player)) // Only display it on your own view.
 							{
 								mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
-								visual->target = lockon;
+								P_SetTarget(&visual->target, lockon);
 							}
 						}
 						if ((cmd->buttons & BT_USE) && !(player->pflags & PF_USEDOWN))
@@ -4589,6 +4620,9 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
 		if (mo2 == player->mo)
@@ -4637,7 +4671,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 		if (P_IsLocalPlayer(player)) // Only display it on your own view.
 		{
 			mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
-			visual->target = lockon;
+			P_SetTarget(&visual->target, lockon);
 		}
 	}
 
@@ -5783,29 +5817,32 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 		// Find next waypoint
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
 			// Axis things are only at beginning of list.
 			if (!(mo2->flags2 & MF2_AXIS))
 				break;
+			if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
+				continue;
+			if (mo2->threshold != sequence)
+				continue;
 
-			if ((mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE)
-				&& mo2->threshold == sequence)
+			if (player->pflags & PF_TRANSFERTOCLOSEST)
 			{
-				if (player->pflags & PF_TRANSFERTOCLOSEST)
-				{
-					if (mo2->health == player->axis1->health)
-						transfer1 = mo2;
-					else if (mo2->health == player->axis2->health)
-						transfer2 = mo2;
-				}
-				else
-				{
-					if (mo2->health == player->mo->target->health)
-						transfer1 = mo2;
-					else if (mo2->health == player->mo->target->health + 1)
-						transfer2 = mo2;
-				}
+				if (mo2->health == player->axis1->health)
+					transfer1 = mo2;
+				else if (mo2->health == player->axis2->health)
+					transfer2 = mo2;
+			}
+			else
+			{
+				if (mo2->health == player->mo->target->health)
+					transfer1 = mo2;
+				else if (mo2->health == player->mo->target->health + 1)
+					transfer2 = mo2;
 			}
 		}
 
@@ -5816,24 +5853,28 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 		{
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				// Axis things are only at beginning of list.
 				if (!(mo2->flags2 & MF2_AXIS))
 					break;
+				if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
+					continue;
+				if (mo2->threshold != sequence)
+					continue;
 
-				if (mo2->threshold == sequence && (mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
+				if (!transfer1)
 				{
-					if (!transfer1)
-					{
-						transfer1 = mo2;
-						transfer1last = true;
-					}
-					else if (mo2->health > transfer1->health)
-					{
-						transfer1 = mo2;
-						transfer1last = true;
-					}
+					transfer1 = mo2;
+					transfer1last = true;
+				}
+				else if (mo2->health > transfer1->health)
+				{
+					transfer1 = mo2;
+					transfer1last = true;
 				}
 			}
 		}
@@ -5841,24 +5882,28 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 		{
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				// Axis things are only at beginning of list.
 				if (!(mo2->flags2 & MF2_AXIS))
 					break;
+				if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
+					continue;
+				if (mo2->threshold != sequence)
+					continue;
 
-				if (mo2->threshold == sequence && (mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
+				if (!transfer2)
 				{
-					if (!transfer2)
-					{
-						transfer2 = mo2;
-						transfer2last = true;
-					}
-					else if (mo2->health > transfer2->health)
-					{
-						transfer2 = mo2;
-						transfer2last = true;
-					}
+					transfer2 = mo2;
+					transfer2last = true;
+				}
+				else if (mo2->health > transfer2->health)
+				{
+					transfer2 = mo2;
+					transfer2last = true;
 				}
 			}
 		}
@@ -6545,31 +6590,32 @@ static void P_NiGHTSMovement(player_t *player)
 		// to find the closest axis point
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
-			if (mo2->type == MT_AXIS)
+			if (mo2->type != MT_AXIS)
+				continue;
+			if (mo2->threshold != player->mare)
+				continue;
+
+			if (closestaxis == NULL)
 			{
-				if (mo2->threshold == player->mare)
-				{
-					if (closestaxis == NULL)
-					{
-						closestaxis = mo2;
-						dist2 = R_PointToDist2(newx, newy, mo2->x, mo2->y)-mo2->radius;
-					}
-					else
-					{
-						dist1 = R_PointToDist2(newx, newy, mo2->x, mo2->y)-mo2->radius;
+				closestaxis = mo2;
+				dist2 = R_PointToDist2(newx, newy, mo2->x, mo2->y) - mo2->radius;
+			}
+			else
+			{
+				dist1 = R_PointToDist2(newx, newy, mo2->x, mo2->y) - mo2->radius;
 
-						if (dist1 < dist2)
-						{
-							closestaxis = mo2;
-							dist2 = dist1;
-						}
-					}
+				if (dist1 < dist2)
+				{
+					closestaxis = mo2;
+					dist2 = dist1;
 				}
 			}
 		}
-
 		P_SetTarget(&player->mo->target, closestaxis);
 	}
 
@@ -7352,6 +7398,9 @@ static void P_MovePlayer(player_t *player)
 
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				if (mo2->type == MT_EGGCAPSULE
@@ -7855,7 +7904,7 @@ static void P_MovePlayer(player_t *player)
 				if (P_IsLocalPlayer(player)) // Only display it on your own view.
 				{
 					mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
-					visual->target = lockon;
+					P_SetTarget(&visual->target, lockon);
 					P_SetMobjStateNF(visual, visual->info->spawnstate+1);
 				}
 			}
@@ -8256,20 +8305,25 @@ static void P_DoZoomTube(player_t *player)
 		// Find next waypoint
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
 			if (mo2->type != MT_TUBEWAYPOINT)
 				continue;
 
-			if (mo2->threshold == sequence)
-			{
-				if ((reverse && mo2->health == player->mo->tracer->health - 1)
-					|| (!reverse && mo2->health == player->mo->tracer->health + 1))
-				{
-					waypoint = mo2;
-					break;
-				}
-			}
+			if (mo2->threshold != sequence)
+				continue;
+
+			if (reverse && mo2->health != player->mo->tracer->health - 1)
+				continue;
+
+			if (!reverse && mo2->health != player->mo->tracer->health + 1)
+				continue;
+
+			waypoint = mo2;
+			break;
 		}
 
 		if (waypoint)
@@ -8387,19 +8441,22 @@ static void P_DoRopeHang(player_t *player)
 		// Find next waypoint
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
 			if (mo2->type != MT_TUBEWAYPOINT)
 				continue;
 
-			if (mo2->threshold == sequence)
-			{
-				if (mo2->health == player->mo->tracer->health + 1)
-				{
-					waypoint = mo2;
-					break;
-				}
-			}
+			if (mo2->threshold != sequence)
+				continue;
+
+			if (mo2->health != player->mo->tracer->health + 1)
+				continue;
+
+			waypoint = mo2;
+			break;
 		}
 
 		if (!(player->mo->tracer->flags & MF_SLIDEME) && !waypoint)
@@ -8409,19 +8466,22 @@ static void P_DoRopeHang(player_t *player)
 			// Wrap around back to first waypoint
 			for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 			{
+				if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+					continue;
+
 				mo2 = (mobj_t *)th;
 
 				if (mo2->type != MT_TUBEWAYPOINT)
 					continue;
 
-				if (mo2->threshold == sequence)
-				{
-					if (mo2->health == 0)
-					{
-						waypoint = mo2;
-						break;
-					}
-				}
+				if (mo2->threshold != sequence)
+					continue;
+
+				if (mo2->health != 0)
+					continue;
+
+				waypoint = mo2;
+				break;
 			}
 		}
 
@@ -8468,22 +8528,22 @@ static void P_DoRopeHang(player_t *player)
 static void P_NukeAllPlayers(player_t *player)
 {
 	mobj_t *mo;
-	thinker_t *think;
+	UINT8 i;
 
-	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
+	for (i = 0; i < MAXPLAYERS; i++)
 	{
-		mo = (mobj_t *)think;
-
-		if (!mo->player)
+		if (!playeringame[i])
 			continue;
-
-		if (mo->health <= 0) // dead
+		if (players[i].spectator)
 			continue;
-
-		if (mo == player->mo)
+		if (!players[i].mo)
+			continue;
+		if (players[i].mo == player->mo)
+			continue;
+		if (players[i].mo->health <= 0)
 			continue;
 
-		P_DamageMobj(mo, player->mo, player->mo, 1, 0);
+		P_DamageMobj(players[i].mo, player->mo, player->mo, 1, 0);
 	}
 
 	CONS_Printf(M_GetText("%s caused a world of pain.\n"), player_names[player-players]);
@@ -8517,6 +8577,9 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
 
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)think;
 
 		if (!(mo->flags & MF_SHOOTABLE) && !(mo->type == MT_EGGGUARD || mo->type == MT_MINUS))
@@ -8565,6 +8628,9 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
 
 	for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
 	{
+		if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo = (mobj_t *)think;
 		if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
 			continue; // not a valid target
@@ -8706,6 +8772,9 @@ void P_FindEmerald(void)
 	// to find all emeralds
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 		if (mo2->type == MT_EMERHUNT)
 		{
@@ -9931,6 +10000,9 @@ static mobj_t *P_GetAxis(INT32 num)
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mobj = (mobj_t *)th;
 
 		// NiGHTS axes spawn before anything else. If this mobj doesn't have MF2_AXIS, it means we reached the axes' end.
@@ -9943,6 +10015,7 @@ static mobj_t *P_GetAxis(INT32 num)
 
 		return mobj;
 	}
+
 	CONS_Alert(CONS_WARNING, "P_GetAxis: Track segment %d is missing!\n", num);
 	return NULL;
 }
@@ -10569,6 +10642,9 @@ void P_PlayerThink(player_t *player)
 
 		for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 		{
+			if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+				continue;
+
 			mo2 = (mobj_t *)th;
 
 			if (!(mo2->type == MT_RING || mo2->type == MT_COIN
diff --git a/src/r_data.c b/src/r_data.c
index c490cc7da6f63846e388e02cd21026355e493ae0..6889bdddebf587ce22b3526066fca43aec364ceb 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -2276,7 +2276,8 @@ void R_PrecacheLevel(void)
 	if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel");
 
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
-		spritepresent[((mobj_t *)th)->sprite] = 1;
+		if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
+			spritepresent[((mobj_t *)th)->sprite] = 1;
 
 	spritememory = 0;
 	for (i = 0; i < numsprites; i++)
diff --git a/src/r_things.c b/src/r_things.c
index 4b1586455e6f2eea2c3de86ca6d43ffe86e0313b..c791571ac28be2ad61b93f241123d835d6676982 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -2446,9 +2446,11 @@ static void R_DrawMaskedList (drawnode_t* head)
 
 void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
 {
-	drawnode_t heads[nummasks];	/**< Drawnode lists; as many as number of views/portals. */
+	drawnode_t *heads;	/**< Drawnode lists; as many as number of views/portals. */
 	SINT8 i;
 
+	heads = calloc(nummasks, sizeof(drawnode_t));
+
 	for (i = 0; i < nummasks; i++)
 	{
 		heads[i].next = heads[i].prev = &heads[i];
@@ -2474,6 +2476,8 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
 		R_DrawMaskedList(&heads[nummasks - 1]);
 		R_ClearDrawNodes(&heads[nummasks - 1]);
 	}
+
+	free(heads);
 }
 
 // ==========================================================================
diff --git a/src/s_sound.c b/src/s_sound.c
index 2db8392d7484e3ef24838b0713bb81c1a63e5eef..66b5d4f72a23fe7b80d4ca24f51dfc219f0b6155 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -1988,8 +1988,10 @@ void GameMIDIMusic_OnChange(void)
 	}
 }
 
+#ifdef HAVE_OPENMPT
 void ModFilter_OnChange(void)
 {
 	if (openmpt_mhandle)
 		openmpt_module_set_render_param(openmpt_mhandle, OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, cv_modfilter.value);
-}
\ No newline at end of file
+}
+#endif
\ No newline at end of file
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index d05a0d32414e38ea9906ad8cef3cf0b24960e2f8..72c38b3dc090061f370d6822d7050912ed2f34ca 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -277,6 +277,7 @@
     <ClInclude Include="..\r_local.h" />
     <ClInclude Include="..\r_main.h" />
     <ClInclude Include="..\r_plane.h" />
+    <ClInclude Include="..\r_portal.h" />
     <ClInclude Include="..\r_segs.h" />
     <ClInclude Include="..\r_sky.h" />
     <ClInclude Include="..\r_splats.h" />
@@ -430,6 +431,7 @@
     </ClCompile>
     <ClCompile Include="..\r_main.c" />
     <ClCompile Include="..\r_plane.c" />
+    <ClCompile Include="..\r_portal.c" />
     <ClCompile Include="..\r_segs.c" />
     <ClCompile Include="..\r_sky.c" />
     <ClCompile Include="..\r_splats.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index ca6bd38d211e4c4be9cbd853d5630e6492203694..9e442000fdc1a5ad0a2e6643cd06eb99ddd8cf11 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -453,6 +453,9 @@
     <ClInclude Include="..\hardware\hw_clip.h">
       <Filter>Hw_Hardware</Filter>
     </ClInclude>
+    <ClInclude Include="..\r_portal.h">
+      <Filter>R_Rend</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\tmap.nas">
@@ -894,6 +897,10 @@
     <ClCompile Include="..\hardware\hw_clip.c">
       <Filter>Hw_Hardware</Filter>
     </ClCompile>
+    <ClCompile Include="..\apng.c" />
+    <ClCompile Include="..\r_portal.c">
+      <Filter>R_Rend</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <Image Include="Srb2SDL.ico">
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 3932d23d3374b0c3e323e48ab623ac175bfc3c34..7bf67559ca2f0dc7c2f26152fd70452a907634ed 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -108,14 +108,16 @@ static UINT16 current_track;
 #endif
 
 #ifdef HAVE_OPENMPT
-int mod_err = OPENMPT_ERROR_OK;
+static int mod_err = OPENMPT_ERROR_OK;
 static const char *mod_err_str;
 static UINT16 current_subsong;
+static size_t probesize;
+static int result;
 #endif
 
 static void var_cleanup(void)
 {
-	loop_point = song_length = 0.0f;
+	song_length = loop_point = 0.0f;
 	music_bytes = fading_source = fading_target =\
 	 fading_timer = fading_duration = 0;
 
@@ -388,7 +390,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
 					gme_track_info(emu, &info, 0);
 
 					len = (info->play_length * 441 / 10) << 2;
-					mem = malloc(len);
+					mem = Z_Malloc(len, PU_SOUND, 0);
 					gme_play(emu, len >> 1, mem);
 					gme_free_info(info);
 					gme_delete(emu);
@@ -461,7 +463,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
 		gme_track_info(emu, &info, 0);
 
 		len = (info->play_length * 441 / 10) << 2;
-		mem = malloc(len);
+		mem = Z_Malloc(len, PU_SOUND, 0);
 		gme_play(emu, len >> 1, mem);
 		gme_free_info(info);
 		gme_delete(emu);
@@ -1112,6 +1114,36 @@ boolean I_LoadSong(char *data, size_t len)
 	}
 #endif
 
+#ifdef HAVE_OPENMPT
+	/*
+		If the size of the data to be checked is bigger than the recommended size (> 2048)
+		Let's just set the probe size to the recommended size
+		Otherwise let's give it the full data size
+	*/
+
+	if (len > openmpt_probe_file_header_get_recommended_size())
+		probesize = openmpt_probe_file_header_get_recommended_size();
+	else
+		probesize = len;
+
+	result = openmpt_probe_file_header(OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, data, probesize, len, NULL, NULL, NULL, NULL, NULL, NULL);
+
+	if (result == OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS) // We only cared if it succeeded, continue on if not.
+	{
+		openmpt_mhandle = openmpt_module_create_from_memory2(data, len, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+		if (!openmpt_mhandle) // Failed to create module handle? Show error and return!
+		{
+			mod_err = openmpt_module_error_get_last(openmpt_mhandle);
+			mod_err_str = openmpt_error_string(mod_err);
+			CONS_Alert(CONS_ERROR, "openmpt_module_create_from_memory2: %s\n", mod_err_str);
+			return false;
+		}
+		else
+			return true; // All good and we're ready for music playback!
+	}
+#endif
+
+	// Let's see if Mixer is able to load this.
 	rw = SDL_RWFromMem(data, len);
 	if (rw != NULL)
 	{
@@ -1123,40 +1155,6 @@ boolean I_LoadSong(char *data, size_t len)
 		return false;
 	}
 
-#ifdef HAVE_OPENMPT
-	switch(Mix_GetMusicType(music))
-	{
-		case MUS_MODPLUG:
-		case MUS_MOD:
-			openmpt_mhandle = openmpt_module_create_from_memory2(data, len, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-			if (!openmpt_mhandle)
-			{
-				mod_err = openmpt_module_error_get_last(openmpt_mhandle);
-				mod_err_str = openmpt_error_string(mod_err);
-				CONS_Alert(CONS_ERROR, "openmpt_module_create_from_memory2: %s\n", mod_err_str);
-				Mix_FreeMusic(music);
-				music = NULL;
-				return false;
-			}
-			else
-			{
-				Mix_FreeMusic(music);
-				music = NULL;
-				return true;
-			}
-			break;
-		case MUS_WAV:
-		case MUS_MID:
-		case MUS_OGG:
-		case MUS_MP3:
-		case MUS_FLAC:
-			Mix_HookMusic(NULL, NULL);
-			break;
-		default:
-			break;
-	}
-#endif
-
 	// Find the OGG loop point.
 	loop_point = 0.0f;
 	song_length = 0.0f;
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 132eada06506bec11a11a07b2372c0002ec823ca..4122793ad4a3f6cdfc4cc807a40b12d2dbf9ff73 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -2308,27 +2308,31 @@ static void ST_doItemFinderIconsAndSound(void)
 	// Scan thinkers to find emblem mobj with these ids
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
+		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
+			continue;
+
 		mo2 = (mobj_t *)th;
 
-		if (mo2->type == MT_EMBLEM)
-		{
-			if (!(mo2->flags & MF_SPECIAL))
-				continue;
+		if (mo2->type != MT_EMBLEM)
+			continue;
+
+		if (!(mo2->flags & MF_SPECIAL))
+			continue;
 
-			for (i = 0; i < stemblems; ++i)
+		for (i = 0; i < stemblems; ++i)
+		{
+			if (mo2->health == emblems[i] + 1)
 			{
-				if (mo2->health == emblems[i]+1)
-				{
-					soffset = (i * 20) - ((stemblems-1) * 10);
+				soffset = (i * 20) - ((stemblems - 1) * 10);
 
-					newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset);
-					if (newinterval && (!interval || newinterval < interval))
-						interval = newinterval;
+				newinterval = ST_drawEmeraldHuntIcon(mo2, itemhoming, soffset);
+				if (newinterval && (!interval || newinterval < interval))
+					interval = newinterval;
 
-					break;
-				}
+				break;
 			}
 		}
+
 	}
 
 	if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index acab2507a37d995112b6402e7c83ac0d6f0dd57a..c0fe8eda9ad5f2d73f7a0c2cd7f1a2023a02dd0e 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -293,6 +293,7 @@
     </ClCompile>
     <ClCompile Include="..\r_main.c" />
     <ClCompile Include="..\r_plane.c" />
+    <ClCompile Include="..\r_portal.c" />
     <ClCompile Include="..\r_segs.c" />
     <ClCompile Include="..\r_sky.c" />
     <ClCompile Include="..\r_splats.c" />
@@ -443,6 +444,7 @@
     <ClInclude Include="..\r_local.h" />
     <ClInclude Include="..\r_main.h" />
     <ClInclude Include="..\r_plane.h" />
+    <ClInclude Include="..\r_portal.h" />
     <ClInclude Include="..\r_segs.h" />
     <ClInclude Include="..\r_sky.h" />
     <ClInclude Include="..\r_splats.h" />
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index c21cedb8a4bf258af6efa2d9a2faba1de00da325..93806e3951066fff4172cdc9f60a0315171e74f4 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -456,6 +456,10 @@
     <ClCompile Include="..\hardware\hw_clip.c">
       <Filter>Hw_Hardware</Filter>
     </ClCompile>
+    <ClCompile Include="..\apng.c" />
+    <ClCompile Include="..\r_portal.c">
+      <Filter>R_Rend</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="afxres.h">
@@ -857,6 +861,10 @@
     <ClInclude Include="..\hardware\hw_clip.h">
       <Filter>Hw_Hardware</Filter>
     </ClInclude>
+    <ClInclude Include="..\apng.h" />
+    <ClInclude Include="..\r_portal.h">
+      <Filter>R_Rend</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Image Include="Srb2win.ico">