diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 7f8c55af0b369cf45566feb671df61e2b9d0e332..6796389e10f04c0e4f8108116228be9cacd28a5a 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -4228,12 +4228,12 @@ static INT16 Consistancy(void)
 		ret += P_GetRandSeed();
 
 #ifdef MOBJCONSISTANCY
-	if (!thinkercap.next)
+	if (!thlist[THINK_MAIN].next)
 	{
 		DEBFILE(va("Consistancy = %u\n", ret));
 		return ret;
 	}
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 392f0e5af13533ddb61f9adfde9d3882e18c4bb0..4a31070b9bf04898305e363db2109e96e8595d50 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -4260,7 +4260,7 @@ static void Command_Archivetest_f(void)
 
 	// assign mobjnum
 	i = 1;
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 			((mobj_t *)th)->mobjnum = i++;
 
diff --git a/src/f_finale.c b/src/f_finale.c
index a89e0d5774241fd99510bfaf32e3829fa5a14f23..0d9fffabdf5b06c48c295d013251c2999e154d06 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -1661,7 +1661,7 @@ void F_TitleScreenTicker(boolean run)
 		mobj_t *mo2;
 		mobj_t *cameraref = NULL;
 
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 				continue;
diff --git a/src/g_game.c b/src/g_game.c
index 4a9dedf508ca82b65c50edee9e0896a15c3ad577..e02d545cb790bf02ec65c7470e9bf24ba18d61b7 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2557,7 +2557,7 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
 	I_Assert((oldmo != NULL) && (newmo != NULL));
 
 	// scan all thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -4455,7 +4455,7 @@ void G_ConsGhostTic(void)
 				demo_p += sizeof(angle_t); // angle, unnecessary for cons.
 
 				mobj = NULL;
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -5851,7 +5851,7 @@ void G_DoPlayMetal(void)
 		metalbuffer = metal_p = W_CacheLumpNum(l, PU_STATIC);
 
 	// find metal sonic
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index dfb2c43518f653078c18f1aa4495c1e0f4022b34..6e05d6feb4419274c484d1d22b35b8d28b98dd0f 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -1335,7 +1335,7 @@ static void HWR_SearchLightsInMobjs(void)
 	//mobj_t *            mobj;
 
 	// search in the list of thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		// a mobj ?
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
diff --git a/src/lua_script.c b/src/lua_script.c
index 04aa55cf07a9423cde72f9ea770273bc090e1cf6..5ec923159ac3e4b80fb8dba64798e19f3825a4e9 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -421,7 +421,7 @@ void LUA_InvalidateLevel(void)
 	if (!gL)
 		return;
 
-	for (th = thinkercap.next; th && th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th && th != &thlist[THINK_MAIN]; th = th->next)
 		LUA_InvalidateUserdata(th);
 
 	LUA_InvalidateMapthings();
@@ -1127,7 +1127,7 @@ void LUA_Archive(void)
 		ArchiveExtVars(&players[i], "player");
 	}
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 		{
 			// archive function will determine when to skip mobjs,
@@ -1161,7 +1161,7 @@ void LUA_UnArchive(void)
 
 	do {
 		mobjnum = READUINT32(save_p); // read a mobjnum
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			if (th->function.acp1 == (actionf_p1)P_MobjThinker
 			&& ((mobj_t *)th)->mobjnum == mobjnum) // find matching mobj
 				UnArchiveExtVars(th); // apply variables
diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c
index ae648613a9ad77ec7b752a13e2ca0b092cfed61d..29bf7bb56ae34d174e7a1c476793c9ef734a9f74 100644
--- a/src/lua_thinkerlib.c
+++ b/src/lua_thinkerlib.c
@@ -64,7 +64,7 @@ static int lib_iterateThinkers(lua_State *L)
 	lua_settop(L, 2);
 
 	if (lua_isnil(L, 2))
-		th = &thinkercap;
+		th = &thlist[THINK_MAIN];
 	else if (lua_isuserdata(L, 2))
 	{
 		if (lua_islightuserdata(L, 2))
@@ -94,11 +94,11 @@ static int lib_iterateThinkers(lua_State *L)
 	if (!next)
 		return luaL_error(L, "next thinker invalidated during iteration");
 
-	for (; next != &thinkercap; next = next->next)
+	for (; next != &thlist[THINK_MAIN]; next = next->next)
 		if (!it->filter || next->function.acp1 == it->filter)
 		{
 			push_thinker(next);
-			if (next->next != &thinkercap)
+			if (next->next != &thlist[THINK_MAIN])
 			{
 				push_thinker(next->next);
 				it->next = luaL_ref(L, LUA_REGISTRYINDEX);
diff --git a/src/m_cheat.c b/src/m_cheat.c
index bee60087fec00c0d44beb4665779d907d4360d74..92b953f7a1cdbf06e60a0d4918e4475cdd74b61a 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -577,7 +577,7 @@ void Command_Teleport_f(void)
 			INT32 starpostmax = 0;
 			intz = starpostpath; // variable reuse - counting down for selection purposes
 
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -600,7 +600,7 @@ void Command_Teleport_f(void)
 				break;
 			}
 
-			if (th == &thinkercap)
+			if (th == &thlist[THINK_MAIN])
 			{
 				if (intz == starpostpath)
 					CONS_Alert(CONS_NOTICE, M_GetText("No starpost of position %d found (%d max).\n"), starpostnum, starpostmax);
@@ -1069,7 +1069,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
 		thinker_t *th;
 		mobj_t *mo;
 
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
diff --git a/src/p_ceilng.c b/src/p_ceilng.c
index 757edebae120e882c7cfd498f0076b46a4aa36a1..5395f618c5e6dd8361b168bb9bd1c58101f650b3 100644
--- a/src/p_ceilng.c
+++ b/src/p_ceilng.c
@@ -409,7 +409,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type)
 		// new door thinker
 		rtn = 1;
 		ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
-		P_AddThinker(&ceiling->thinker);
+		P_AddThinker(THINK_MAIN, &ceiling->thinker);
 		sec->ceilingdata = ceiling;
 		ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
 		ceiling->sector = sec;
@@ -629,7 +629,7 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type)
 		// new door thinker
 		rtn = 1;
 		ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
-		P_AddThinker(&ceiling->thinker);
+		P_AddThinker(THINK_MAIN, &ceiling->thinker);
 		sec->ceilingdata = ceiling;
 		ceiling->thinker.function.acp1 = (actionf_p1)T_CrushCeiling;
 		ceiling->sector = sec;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 9d2425e531fddfc65b38b6e6d6f366427aee4317..5364c4207e422deb381df60641febb8f7c4ccae0 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -3514,7 +3514,7 @@ void A_BossDeath(mobj_t *mo)
 
 	// scan the remaining thinkers to see
 	// if all bosses are dead
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -3573,7 +3573,7 @@ bossjustdie:
 
 		// Flee! Flee! Find a point to escape to! If none, just shoot upward!
 		// scan the thinkers to find the runaway point
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -5759,7 +5759,7 @@ void A_RingExplode(mobj_t *actor)
 
 	S_StartSound(actor, sfx_prloop);
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -7435,7 +7435,7 @@ void A_Boss3Path(mobj_t *actor)
 		// scan the thinkers
 		// to find a point that matches
 		// the number
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -7826,7 +7826,7 @@ void A_FindTarget(mobj_t *actor)
 	CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
 
 	// scan the thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -7891,7 +7891,7 @@ void A_FindTracer(mobj_t *actor)
 	CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
 
 	// scan the thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -8454,7 +8454,7 @@ void A_RemoteAction(mobj_t *actor)
 		fixed_t dist1 = 0, dist2 = 0;
 
 		// scan the thinkers
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -8720,7 +8720,7 @@ void A_SetObjectTypeState(mobj_t *actor)
 		return;
 #endif
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -9358,7 +9358,7 @@ void A_CheckThingCount(mobj_t *actor)
 		return;
 #endif
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
diff --git a/src/p_floor.c b/src/p_floor.c
index a1b1c45fc08dc51ab30eab179bf740290713bdbf..131cc29d1e5d9c95a682a9392d7c8c769ff27a60 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1981,7 +1981,7 @@ void T_ThwompSector(levelspecthink_t *thwomp)
 		if (!rover || (rover->flags & FF_EXISTS))
 		{
 			// scan the thinkers to find players!
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -2701,7 +2701,7 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype)
 		// new floor thinker
 		rtn = 1;
 		dofloor = Z_Calloc(sizeof (*dofloor), PU_LEVSPEC, NULL);
-		P_AddThinker(&dofloor->thinker);
+		P_AddThinker(THINK_MAIN, &dofloor->thinker);
 
 		// make sure another floor thinker won't get started over this one
 		sec->floordata = dofloor;
@@ -2922,7 +2922,7 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed)
 		// create and initialize new elevator thinker
 		rtn = 1;
 		elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
-		P_AddThinker(&elevator->thinker);
+		P_AddThinker(THINK_MAIN, &elevator->thinker);
 		sec->floordata = elevator;
 		sec->ceilingdata = elevator;
 		elevator->thinker.function.acp1 = (actionf_p1)T_MoveElevator;
@@ -3149,7 +3149,7 @@ INT32 EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline)
 		return 0;
 
 	bouncer = Z_Calloc(sizeof (*bouncer), PU_LEVSPEC, NULL);
-	P_AddThinker(&bouncer->thinker);
+	P_AddThinker(THINK_MAIN, &bouncer->thinker);
 	sec->ceilingdata = bouncer;
 	bouncer->thinker.function.acp1 = (actionf_p1)T_BounceCheese;
 
@@ -3183,7 +3183,7 @@ INT32 EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, bool
 
 	// create and initialize new thinker
 	faller = Z_Calloc(sizeof (*faller), PU_LEVSPEC, NULL);
-	P_AddThinker(&faller->thinker);
+	P_AddThinker(THINK_MAIN, &faller->thinker);
 	faller->thinker.function.acp1 = (actionf_p1)T_ContinuousFalling;
 
 	// set up the fields
@@ -3232,7 +3232,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
 
 	// create and initialize new elevator thinker
 	elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
-	P_AddThinker(&elevator->thinker);
+	P_AddThinker(THINK_MAIN, &elevator->thinker);
 	elevator->thinker.function.acp1 = (actionf_p1)T_StartCrumble;
 
 	// Does this crumbler return?
@@ -3311,7 +3311,7 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
 		// create and initialize new elevator thinker
 
 		block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
-		P_AddThinker(&block->thinker);
+		P_AddThinker(THINK_MAIN, &block->thinker);
 		roversec->floordata = block;
 		roversec->ceilingdata = block;
 		block->thinker.function.acp1 = (actionf_p1)T_MarioBlock;
diff --git a/src/p_inter.c b/src/p_inter.c
index 177b8d16e8c5378d1f0f90727973d4949682f69b..0d8dfcbeb748038e2d379a9e8184a11b66398338 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -97,7 +97,7 @@ void P_ClearStarPost(INT32 postnum)
 	mobj_t *mo2;
 
 	// scan the thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -126,7 +126,7 @@ void P_ResetStarposts(void)
 	thinker_t *th;
 	mobj_t *post;
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -807,7 +807,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 						// The player might have two Ideyas: toucher->tracer and toucher->tracer->hnext
 						// so handle their anchorpoints accordingly.
 						// scan the thinkers to find the corresponding anchorpoint
-						for (th = thinkercap.next; th != &thinkercap; th = th->next)
+						for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 						{
 							if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 								continue;
@@ -901,7 +901,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				count = 1;
 
 				// scan the remaining thinkers
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -951,7 +951,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 				// Now we RE-scan all the thinkers to find close objects to pull
 				// in from the paraloop. Isn't this just so efficient?
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -1325,7 +1325,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				EV_DoElevator(&junk, bridgeFall, false);
 
 				// scan the remaining thinkers to find koopa
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -1424,7 +1424,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				thinker_t *th;
 				mobj_t *mo2;
 
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -2461,7 +2461,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 
 				// 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 = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
diff --git a/src/p_lights.c b/src/p_lights.c
index 67ec55e80b42125ded814d2ba48ffdb8235b737a..8459d9ea044d066e5ba02c37b2717d549849b9ce 100644
--- a/src/p_lights.c
+++ b/src/p_lights.c
@@ -76,7 +76,7 @@ fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxse
 	P_RemoveLighting(maxsector); // out with the old, in with the new
 	flick = Z_Calloc(sizeof (*flick), PU_LEVSPEC, NULL);
 
-	P_AddThinker(&flick->thinker);
+	P_AddThinker(THINK_MAIN, &flick->thinker);
 
 	flick->thinker.function.acp1 = (actionf_p1)T_FireFlicker;
 	flick->sector = maxsector;
@@ -155,7 +155,7 @@ void P_SpawnLightningFlash(sector_t *sector)
 
 	flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
 
-	P_AddThinker(&flash->thinker);
+	P_AddThinker(THINK_MAIN, &flash->thinker);
 
 	flash->thinker.function.acp1 = (actionf_p1)T_LightningFlash;
 	flash->sector = sector;
@@ -214,7 +214,7 @@ strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector,
 	P_RemoveLighting(maxsector); // out with the old, in with the new
 	flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
 
-	P_AddThinker(&flash->thinker);
+	P_AddThinker(THINK_MAIN, &flash->thinker);
 
 	flash->sector = maxsector;
 	flash->darktime = darktime;
@@ -289,7 +289,7 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector,
 	P_RemoveLighting(maxsector); // out with the old, in with the new
 	g = Z_Calloc(sizeof (*g), PU_LEVSPEC, NULL);
 
-	P_AddThinker(&g->thinker);
+	P_AddThinker(THINK_MAIN, &g->thinker);
 
 	g->sector = maxsector;
 	g->minlight = minsector->lightlevel;
@@ -349,7 +349,7 @@ void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean
 	ll->thinker.function.acp1 = (actionf_p1)T_LightFade;
 	sector->lightingdata = ll; // set it to the lightlevel_t
 
-	P_AddThinker(&ll->thinker); // add thinker
+	P_AddThinker(THINK_MAIN, &ll->thinker); // add thinker
 
 	ll->sector = sector;
 	ll->sourcelevel = sector->lightlevel;
diff --git a/src/p_local.h b/src/p_local.h
index b686b9f09ce13a43ff4230cf1976a59b72e3ace8..254705ad6c7a449e97bcc08043cec3352cce553c 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -61,15 +61,16 @@
 #define P_GetPlayerHeight(player) FixedMul(player->height, player->mo->scale)
 #define P_GetPlayerSpinHeight(player) FixedMul(player->spinheight, player->mo->scale)
 
-//
-// P_TICK
-//
-
 // both the head and tail of the thinker list
-extern thinker_t thinkercap;
+typedef enum{
+	THINK_POLYOBJ,
+	THINK_MAIN,
+	NUM_THINKERLISTS
+} thinklistnum_t; /**< Thinker lists. */
+extern thinker_t thlist[];
 
 void P_InitThinkers(void);
-void P_AddThinker(thinker_t *thinker);
+void P_AddThinker(const thinklistnum_t n, thinker_t *thinker);
 void P_RemoveThinker(thinker_t *thinker);
 
 //
diff --git a/src/p_map.c b/src/p_map.c
index ceaa6ca241adea5a2b5c43586e4df1a68fcc67da..e63fe02dc5efdb1f9d80c7f4b21cd5ce318e918d 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -3872,7 +3872,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
 						thinker_t *think;
 						elevator_t *crumbler;
 
-						for (think = thinkercap.next; think != &thinkercap; think = think->next)
+						for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 						{
 							if (think->function.acp1 != (actionf_p1)T_StartCrumble)
 								continue;
diff --git a/src/p_mobj.c b/src/p_mobj.c
index bfed9a2c0effc4af06762c8fd669d548e92a2807..ff07e2f2af8429c4748a36db0c20ac5225925551 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -713,7 +713,7 @@ void P_EmeraldManager(void)
 		spawnpoints[i] = NULL;
 	}
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -3699,7 +3699,7 @@ void P_DestroyRobots(void)
 	mobj_t *mo;
 	thinker_t *think;
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -4483,7 +4483,7 @@ static void P_Boss3Thinker(mobj_t *mobj)
 
 			// scan the thinkers to make sure all the old pinch dummies are gone before making new ones
 			// this can happen if the boss was hurt earlier than expected
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -4574,7 +4574,7 @@ static void P_Boss3Thinker(mobj_t *mobj)
 		// scan the thinkers
 		// to find a point that matches
 		// the number
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -5195,7 +5195,7 @@ static void P_Boss7Thinker(mobj_t *mobj)
 				closestdist = INT32_MAX; // Just in case...
 
 				// Find waypoint he is closest to
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -5250,7 +5250,7 @@ static void P_Boss7Thinker(mobj_t *mobj)
 
 		// scan the thinkers to find
 		// the waypoint to use
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -5382,7 +5382,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 
 		// Run through the thinkers ONCE and find all of the MT_BOSS9GATHERPOINT in the map.
 		// Build a hoop linked list of 'em!
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -5848,7 +5848,7 @@ mobj_t *P_GetClosestAxis(mobj_t *source)
 	fixed_t dist1, dist2 = 0;
 
 	// scan the thinkers to find the closest axis point
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -9047,7 +9047,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 	}
 
 	if (!(mobj->flags & MF_NOTHINK))
-		P_AddThinker(&mobj->thinker);
+		P_AddThinker(THINK_MAIN, &mobj->thinker);
 
 	// Call action functions when the state is set
 	if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC))
@@ -9122,7 +9122,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
 	mobj->momz = mobjinfo[type].speed;
 
 	mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker;
-	P_AddThinker(&mobj->thinker);
+	P_AddThinker(THINK_MAIN, &mobj->thinker);
 
 	CalculatePrecipFloor(mobj);
 
@@ -9246,7 +9246,7 @@ void P_RemoveMobj(mobj_t *mobj)
 		else
 		{ // Add thinker just to delay removing it until refrences are gone.
 			mobj->flags &= ~MF_NOTHINK;
-			P_AddThinker((thinker_t *)mobj);
+			P_AddThinker(THINK_MAIN, (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));
@@ -11085,7 +11085,7 @@ ML_EFFECT4 : Don't clip inside the ground
 		mobj->health = (mthing->angle / 360) + 1;
 
 		// See if other starposts exist in this level that have the same value.
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index dfa9906ba76d51b9eed428b1ccf98547f3f62cce..05c2c9a65b3b64c40542b6ea3f1d18a78b32fc55 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -146,16 +146,6 @@ FUNCINLINE static ATTRINLINE void Polyobj_vecSub2(vertex_t *dst, vertex_t *v1, v
 	dst->y = v1->y - v2->y;
 }
 
-// Add the polyobject's thinker to the thinker list
-// Unlike P_AddThinker, this adds it to the front of the list instead of the back, so that carrying physics can work right. -Red
-FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th)
-{
-	thinkercap.next->prev = th;
-	th->next = thinkercap.next;
-	th->prev = &thinkercap;
-	thinkercap.next = th;
-}
-
 //
 // P_PointInsidePolyobj
 //
@@ -1518,7 +1508,7 @@ void Polyobj_InitLevel(void)
 
 	// run down the thinker list, count the number of spawn points, and save
 	// the mobj_t pointers on a queue for use below.
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 		{
@@ -1826,7 +1816,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 
 	// Find out target first.
 	// We redo this each tic to make savegame compatibility easier.
-	for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
+	for (wp = thlist[THINK_MAIN].next; wp != &thlist[THINK_MAIN]; wp = wp->next)
 	{
 		if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 			continue;
@@ -1907,7 +1897,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 			CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n");
 
 			// Find next waypoint
-			for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
+			for (wp = thlist[THINK_MAIN].next; wp != &thlist[THINK_MAIN]; wp = wp->next)
 			{
 				if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 					continue;
@@ -1946,7 +1936,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 					th->stophere = true;
 				}
 
-				for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
+				for (wp = thlist[THINK_MAIN].next; wp != &thlist[THINK_MAIN]; wp = wp->next)
 				{
 					if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 						continue;
@@ -1983,7 +1973,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
 				if (!th->continuous)
 					th->comeback = false;
 
-				for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
+				for (wp = thlist[THINK_MAIN].next; wp != &thlist[THINK_MAIN]; wp = wp->next)
 				{
 					if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 						continue;
@@ -2390,7 +2380,7 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polyrotate_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotate;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
@@ -2455,7 +2445,7 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjMove;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
@@ -2516,7 +2506,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polywaypoint_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjWaypoint;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
@@ -2534,7 +2524,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 	th->stophere = false;
 
 	// Find the first waypoint we need to use
-	for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
+	for (wp = thlist[THINK_MAIN].next; wp != &thlist[THINK_MAIN]; wp = wp->next)
 	{
 		if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 			continue;
@@ -2605,7 +2595,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 
 	// Find the actual target movement waypoint
 	target = first;
-	/*for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
+	/*for (wp = thlist[THINK_MAIN].next; wp != &thlist[THINK_MAIN]; wp = wp->next)
 	{
 		if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 			continue;
@@ -2662,7 +2652,7 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata)
 	// allocate and add a new slide door thinker
 	th = Z_Malloc(sizeof(polyslidedoor_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSlide;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 
 	// point the polyobject to this thinker
 	po->thinker = &th->thinker;
@@ -2710,7 +2700,7 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata)
 	// allocate and add a new swing door thinker
 	th = Z_Malloc(sizeof(polyswingdoor_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSwing;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 
 	// point the polyobject to this thinker
 	po->thinker = &th->thinker;
@@ -2792,7 +2782,7 @@ INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polydisplace_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjDisplace;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
@@ -2838,7 +2828,7 @@ INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polyrotdisplace_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotDisplace;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
@@ -2939,7 +2929,7 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjFlag;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
@@ -3089,7 +3079,7 @@ INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata)
 	// create a new thinker
 	th = Z_Malloc(sizeof(polyfade_t), PU_LEVSPEC, NULL);
 	th->thinker.function.acp1 = (actionf_p1)T_PolyObjFade;
-	PolyObj_AddThinker(&th->thinker);
+	P_AddThinker(THINK_POLYOBJ, &th->thinker);
 	po->thinker = &th->thinker;
 
 	// set fields
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 0d58387b9e6be03187077ebf3642cda67cd7365b..b72b055aee7b472f7529da741d780457d82c2c9c 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -2135,236 +2135,241 @@ static inline void SaveWhatThinker(const thinker_t *th, const UINT8 type)
 static void P_NetArchiveThinkers(void)
 {
 	const thinker_t *th;
-	UINT32 numsaved = 0;
+	UINT32 i;
 
 	WRITEUINT32(save_p, ARCHIVEBLOCK_THINKERS);
 
-	// save off the current thinkers
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (i = 0; i < NUM_THINKERLISTS; i++)
 	{
-		if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed
-		 || th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
-			numsaved++;
+		UINT32 numsaved = 0;
 
-		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
-		{
-			SaveMobjThinker(th, tc_mobj);
-			continue;
-		}
-#ifdef PARANOIA
-		else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker);
-#endif
-		else if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
-		{
-			SaveCeilingThinker(th, tc_ceiling);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_CrushCeiling)
-		{
-			SaveCeilingThinker(th, tc_crushceiling);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_MoveFloor)
-		{
-			SaveFloormoveThinker(th, tc_floor);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_LightningFlash)
-		{
-			SaveLightflashThinker(th, tc_flash);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
-		{
-			SaveStrobeThinker(th, tc_strobe);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_Glow)
-		{
-			SaveGlowThinker(th, tc_glow);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_FireFlicker)
-		{
-			SaveFireflickerThinker(th, tc_fireflicker);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_MoveElevator)
-		{
-			SaveElevatorThinker(th, tc_elevator);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_ContinuousFalling)
-		{
-			SaveSpecialLevelThinker(th, tc_continuousfalling);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_ThwompSector)
-		{
-			SaveSpecialLevelThinker(th, tc_thwomp);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector)
-		{
-			SaveSpecialLevelThinker(th, tc_noenemies);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_EachTimeThinker)
-		{
-			SaveSpecialLevelThinker(th, tc_eachtime);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_RaiseSector)
-		{
-			SaveSpecialLevelThinker(th, tc_raisesector);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_CameraScanner)
-		{
-			SaveElevatorThinker(th, tc_camerascanner);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_Scroll)
-		{
-			SaveScrollThinker(th, tc_scroll);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_Friction)
-		{
-			SaveFrictionThinker(th, tc_friction);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_Pusher)
-		{
-			SavePusherThinker(th, tc_pusher);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_BounceCheese)
-		{
-			SaveSpecialLevelThinker(th, tc_bouncecheese);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_StartCrumble)
-		{
-			SaveElevatorThinker(th, tc_startcrumble);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_MarioBlock)
-		{
-			SaveSpecialLevelThinker(th, tc_marioblock);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker)
-		{
-			SaveSpecialLevelThinker(th, tc_marioblockchecker);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_SpikeSector)
-		{
-			SaveSpecialLevelThinker(th, tc_spikesector);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_FloatSector)
-		{
-			SaveSpecialLevelThinker(th, tc_floatsector);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_BridgeThinker)
-		{
-			SaveSpecialLevelThinker(th, tc_bridgethinker);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_LaserFlash)
-		{
-			SaveLaserThinker(th, tc_laserflash);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_LightFade)
-		{
-			SaveLightlevelThinker(th, tc_lightfade);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_ExecutorDelay)
-		{
-			SaveExecutorThinker(th, tc_executor);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_Disappear)
-		{
-			SaveDisappearThinker(th, tc_disappear);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_Fade)
-		{
-			SaveFadeThinker(th, tc_fade);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_FadeColormap)
-		{
-			SaveFadeColormapThinker(th, tc_fadecolormap);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace)
-		{
-			SavePlaneDisplaceThinker(th, tc_planedisplace);
-			continue;
-		}
-#ifdef POLYOBJECTS
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
+		// save off the current thinkers
+		for (th = thlist[i].next; th != &thlist[i]; th = th->next)
 		{
-			SavePolyrotatetThinker(th, tc_polyrotate);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjMove)
-		{
-			SavePolymoveThinker(th, tc_polymove);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjWaypoint)
-		{
-			SavePolywaypointThinker(th, tc_polywaypoint);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyDoorSlide)
-		{
-			SavePolyslidedoorThinker(th, tc_polyslidedoor);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyDoorSwing)
-		{
-			SavePolyswingdoorThinker(th, tc_polyswingdoor);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjFlag)
-		{
-			SavePolymoveThinker(th, tc_polyflag);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjDisplace)
-		{
-			SavePolydisplaceThinker(th, tc_polydisplace);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjRotDisplace)
-		{
-			SavePolyrotdisplaceThinker(th, tc_polyrotdisplace);
-			continue;
-		}
-		else if (th->function.acp1 == (actionf_p1)T_PolyObjFade)
-		{
-			SavePolyfadeThinker(th, tc_polyfade);
-			continue;
-		}
+			if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed
+			 || th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
+				numsaved++;
+
+			if (th->function.acp1 == (actionf_p1)P_MobjThinker)
+			{
+				SaveMobjThinker(th, tc_mobj);
+				continue;
+			}
+	#ifdef PARANOIA
+			else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker);
+	#endif
+			else if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
+			{
+				SaveCeilingThinker(th, tc_ceiling);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_CrushCeiling)
+			{
+				SaveCeilingThinker(th, tc_crushceiling);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_MoveFloor)
+			{
+				SaveFloormoveThinker(th, tc_floor);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_LightningFlash)
+			{
+				SaveLightflashThinker(th, tc_flash);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
+			{
+				SaveStrobeThinker(th, tc_strobe);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_Glow)
+			{
+				SaveGlowThinker(th, tc_glow);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_FireFlicker)
+			{
+				SaveFireflickerThinker(th, tc_fireflicker);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_MoveElevator)
+			{
+				SaveElevatorThinker(th, tc_elevator);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_ContinuousFalling)
+			{
+				SaveSpecialLevelThinker(th, tc_continuousfalling);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_ThwompSector)
+			{
+				SaveSpecialLevelThinker(th, tc_thwomp);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector)
+			{
+				SaveSpecialLevelThinker(th, tc_noenemies);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_EachTimeThinker)
+			{
+				SaveSpecialLevelThinker(th, tc_eachtime);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_RaiseSector)
+			{
+				SaveSpecialLevelThinker(th, tc_raisesector);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_CameraScanner)
+			{
+				SaveElevatorThinker(th, tc_camerascanner);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_Scroll)
+			{
+				SaveScrollThinker(th, tc_scroll);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_Friction)
+			{
+				SaveFrictionThinker(th, tc_friction);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_Pusher)
+			{
+				SavePusherThinker(th, tc_pusher);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_BounceCheese)
+			{
+				SaveSpecialLevelThinker(th, tc_bouncecheese);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_StartCrumble)
+			{
+				SaveElevatorThinker(th, tc_startcrumble);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_MarioBlock)
+			{
+				SaveSpecialLevelThinker(th, tc_marioblock);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker)
+			{
+				SaveSpecialLevelThinker(th, tc_marioblockchecker);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_SpikeSector)
+			{
+				SaveSpecialLevelThinker(th, tc_spikesector);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_FloatSector)
+			{
+				SaveSpecialLevelThinker(th, tc_floatsector);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_BridgeThinker)
+			{
+				SaveSpecialLevelThinker(th, tc_bridgethinker);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_LaserFlash)
+			{
+				SaveLaserThinker(th, tc_laserflash);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_LightFade)
+			{
+				SaveLightlevelThinker(th, tc_lightfade);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_ExecutorDelay)
+			{
+				SaveExecutorThinker(th, tc_executor);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_Disappear)
+			{
+				SaveDisappearThinker(th, tc_disappear);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_Fade)
+			{
+				SaveFadeThinker(th, tc_fade);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_FadeColormap)
+			{
+				SaveFadeColormapThinker(th, tc_fadecolormap);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace)
+			{
+				SavePlaneDisplaceThinker(th, tc_planedisplace);
+				continue;
+			}
+	#ifdef POLYOBJECTS
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
+			{
+				SavePolyrotatetThinker(th, tc_polyrotate);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjMove)
+			{
+				SavePolymoveThinker(th, tc_polymove);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjWaypoint)
+			{
+				SavePolywaypointThinker(th, tc_polywaypoint);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyDoorSlide)
+			{
+				SavePolyslidedoorThinker(th, tc_polyslidedoor);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyDoorSwing)
+			{
+				SavePolyswingdoorThinker(th, tc_polyswingdoor);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjFlag)
+			{
+				SavePolymoveThinker(th, tc_polyflag);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjDisplace)
+			{
+				SavePolydisplaceThinker(th, tc_polydisplace);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjRotDisplace)
+			{
+				SavePolyrotdisplaceThinker(th, tc_polyrotdisplace);
+				continue;
+			}
+			else if (th->function.acp1 == (actionf_p1)T_PolyObjFade)
+			{
+				SavePolyfadeThinker(th, tc_polyfade);
+				continue;
+			}
 #endif
 #ifdef PARANOIA
-		else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection
-			I_Error("unknown thinker type %p", th->function.acp1);
+			else if (th->function.acv != 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\n", numsaved);
 
-	WRITEUINT8(save_p, tc_end);
+		WRITEUINT8(save_p, tc_end);
+	}
 }
 
 // Now save the pointers, tracer and target, but at load time we must
@@ -2376,7 +2381,7 @@ mobj_t *P_FindNewPosition(UINT32 oldposition)
 	thinker_t *th;
 	mobj_t *mobj;
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -2418,7 +2423,7 @@ static inline player_t *LoadPlayer(UINT32 player)
 //
 // Loads a mobj_t from a save game
 //
-static void LoadMobjThinker(actionf_p1 thinker)
+static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 {
 	thinker_t *next;
 	mobj_t *mobj;
@@ -2479,7 +2484,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
 		if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
 		{
 			P_SpawnHoopsAndRings(&mapthings[spawnpointnum], false);
-			return;
+			return NULL;
 		}
 
 		mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
@@ -2686,9 +2691,9 @@ static void LoadMobjThinker(actionf_p1 thinker)
 			mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight;
 	}
 
-	P_AddThinker(&mobj->thinker);
-
 	mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
+
+	return &mobj->thinker;
 }
 
 //
@@ -2702,7 +2707,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
 //		2 - Ceiling Only
 //		3 - Both
 //
-static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
+static thinker_t* LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
 {
 	levelspecthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	size_t i;
@@ -2723,7 +2728,7 @@ static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
 			ht->sector->floordata = ht;
 	}
 
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2731,7 +2736,7 @@ static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
 //
 // Loads a ceiling_t from a save game
 //
-static void LoadCeilingThinker(actionf_p1 thinker)
+static thinker_t* LoadCeilingThinker(actionf_p1 thinker)
 {
 	ceiling_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2752,7 +2757,7 @@ static void LoadCeilingThinker(actionf_p1 thinker)
 	ht->sourceline = READFIXED(save_p);
 	if (ht->sector)
 		ht->sector->ceilingdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2760,7 +2765,7 @@ static void LoadCeilingThinker(actionf_p1 thinker)
 //
 // Loads a floormove_t from a save game
 //
-static void LoadFloormoveThinker(actionf_p1 thinker)
+static thinker_t* LoadFloormoveThinker(actionf_p1 thinker)
 {
 	floormove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2776,7 +2781,7 @@ static void LoadFloormoveThinker(actionf_p1 thinker)
 	ht->delaytimer = READFIXED(save_p);
 	if (ht->sector)
 		ht->sector->floordata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2784,7 +2789,7 @@ static void LoadFloormoveThinker(actionf_p1 thinker)
 //
 // Loads a lightflash_t from a save game
 //
-static void LoadLightflashThinker(actionf_p1 thinker)
+static thinker_t* LoadLightflashThinker(actionf_p1 thinker)
 {
 	lightflash_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2793,7 +2798,7 @@ static void LoadLightflashThinker(actionf_p1 thinker)
 	ht->minlight = READINT32(save_p);
 	if (ht->sector)
 		ht->sector->lightingdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2801,7 +2806,7 @@ static void LoadLightflashThinker(actionf_p1 thinker)
 //
 // Loads a strobe_t from a save game
 //
-static void LoadStrobeThinker(actionf_p1 thinker)
+static thinker_t* LoadStrobeThinker(actionf_p1 thinker)
 {
 	strobe_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2813,7 +2818,7 @@ static void LoadStrobeThinker(actionf_p1 thinker)
 	ht->brighttime = READINT32(save_p);
 	if (ht->sector)
 		ht->sector->lightingdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2821,7 +2826,7 @@ static void LoadStrobeThinker(actionf_p1 thinker)
 //
 // Loads a glow_t from a save game
 //
-static void LoadGlowThinker(actionf_p1 thinker)
+static thinker_t* LoadGlowThinker(actionf_p1 thinker)
 {
 	glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2832,14 +2837,14 @@ static void LoadGlowThinker(actionf_p1 thinker)
 	ht->speed = READINT32(save_p);
 	if (ht->sector)
 		ht->sector->lightingdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 //
 // LoadFireflickerThinker
 //
 // Loads a fireflicker_t from a save game
 //
-static void LoadFireflickerThinker(actionf_p1 thinker)
+static thinker_t* LoadFireflickerThinker(actionf_p1 thinker)
 {
 	fireflicker_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2850,14 +2855,14 @@ static void LoadFireflickerThinker(actionf_p1 thinker)
 	ht->minlight = READINT32(save_p);
 	if (ht->sector)
 		ht->sector->lightingdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 //
 // LoadElevatorThinker
 //
 // Loads a elevator_t from a save game
 //
-static void LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
+static thinker_t* LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
 {
 	elevator_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2887,7 +2892,7 @@ static void LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
 			ht->sector->floordata = ht;
 	}
 
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2895,7 +2900,7 @@ static void LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
 //
 // Loads a scroll_t from a save game
 //
-static void LoadScrollThinker(actionf_p1 thinker)
+static thinker_t* LoadScrollThinker(actionf_p1 thinker)
 {
 	scroll_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2909,7 +2914,7 @@ static void LoadScrollThinker(actionf_p1 thinker)
 	ht->accel = READINT32(save_p);
 	ht->exclusive = READINT32(save_p);
 	ht->type = READUINT8(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2917,7 +2922,7 @@ static void LoadScrollThinker(actionf_p1 thinker)
 //
 // Loads a friction_t from a save game
 //
-static inline void LoadFrictionThinker(actionf_p1 thinker)
+static inline thinker_t* LoadFrictionThinker(actionf_p1 thinker)
 {
 	friction_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2926,7 +2931,7 @@ static inline void LoadFrictionThinker(actionf_p1 thinker)
 	ht->affectee = READINT32(save_p);
 	ht->referrer = READINT32(save_p);
 	ht->roverfriction = READUINT8(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2934,7 +2939,7 @@ static inline void LoadFrictionThinker(actionf_p1 thinker)
 //
 // Loads a pusher_t from a save game
 //
-static void LoadPusherThinker(actionf_p1 thinker)
+static thinker_t* LoadPusherThinker(actionf_p1 thinker)
 {
 	pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2952,7 +2957,7 @@ static void LoadPusherThinker(actionf_p1 thinker)
 	ht->exclusive = READINT32(save_p);
 	ht->slider = READINT32(save_p);
 	ht->source = P_GetPushThing(ht->affectee);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2960,7 +2965,7 @@ static void LoadPusherThinker(actionf_p1 thinker)
 //
 // Loads a laserthink_t from a save game
 //
-static inline void LoadLaserThinker(actionf_p1 thinker)
+static inline thinker_t* LoadLaserThinker(actionf_p1 thinker)
 {
 	laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ffloor_t *rover = NULL;
@@ -2972,7 +2977,7 @@ static inline void LoadLaserThinker(actionf_p1 thinker)
 		if (rover->secnum == (size_t)(ht->sec - sectors)
 		&& rover->master == ht->sourceline)
 			ht->ffloor = rover;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -2980,7 +2985,7 @@ static inline void LoadLaserThinker(actionf_p1 thinker)
 //
 // Loads a lightlevel_t from a save game
 //
-static inline void LoadLightlevelThinker(actionf_p1 thinker)
+static inline thinker_t* LoadLightlevelThinker(actionf_p1 thinker)
 {
 	lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -2992,7 +2997,7 @@ static inline void LoadLightlevelThinker(actionf_p1 thinker)
 	ht->timer = READINT32(save_p);
 	if (ht->sector)
 		ht->sector->lightingdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3000,7 +3005,7 @@ static inline void LoadLightlevelThinker(actionf_p1 thinker)
 //
 // Loads a executor_t from a save game
 //
-static inline void LoadExecutorThinker(actionf_p1 thinker)
+static inline thinker_t* LoadExecutorThinker(actionf_p1 thinker)
 {
 	executor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3008,7 +3013,7 @@ static inline void LoadExecutorThinker(actionf_p1 thinker)
 	ht->caller = LoadMobj(READUINT32(save_p));
 	ht->sector = LoadSector(READUINT32(save_p));
 	ht->timer = READINT32(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3016,7 +3021,7 @@ static inline void LoadExecutorThinker(actionf_p1 thinker)
 //
 // Loads a disappear_t thinker
 //
-static inline void LoadDisappearThinker(actionf_p1 thinker)
+static inline thinker_t* LoadDisappearThinker(actionf_p1 thinker)
 {
 	disappear_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3027,7 +3032,7 @@ static inline void LoadDisappearThinker(actionf_p1 thinker)
 	ht->affectee = READINT32(save_p);
 	ht->sourceline = READINT32(save_p);
 	ht->exists = READINT32(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3035,7 +3040,7 @@ static inline void LoadDisappearThinker(actionf_p1 thinker)
 //
 // Loads a fade_t thinker
 //
-static inline void LoadFadeThinker(actionf_p1 thinker)
+static inline thinker_t* LoadFadeThinker(actionf_p1 thinker)
 {
 	sector_t *ss;
 	fade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
@@ -3074,14 +3079,14 @@ static inline void LoadFadeThinker(actionf_p1 thinker)
 			j++;
 		}
 	}
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 // LoadFadeColormapThinker
 //
 // Loads a fadecolormap_t from a save game
 //
-static inline void LoadFadeColormapThinker(actionf_p1 thinker)
+static inline thinker_t* LoadFadeColormapThinker(actionf_p1 thinker)
 {
 	fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3093,7 +3098,7 @@ static inline void LoadFadeColormapThinker(actionf_p1 thinker)
 	ht->timer = READINT32(save_p);
 	if (ht->sector)
 		ht->sector->fadecolormapdata = ht;
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3101,7 +3106,7 @@ static inline void LoadFadeColormapThinker(actionf_p1 thinker)
 //
 // Loads a planedisplace_t thinker
 //
-static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker)
 {
 	planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3110,7 +3115,7 @@ static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
 	ht->last_height = READFIXED(save_p);
 	ht->speed = READFIXED(save_p);
 	ht->type = READUINT8(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 #ifdef POLYOBJECTS
@@ -3120,14 +3125,14 @@ static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
 //
 // Loads a polyrotate_t thinker
 //
-static inline void LoadPolyrotatetThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPolyrotatetThinker(actionf_p1 thinker)
 {
 	polyrotate_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
 	ht->polyObjNum = READINT32(save_p);
 	ht->speed = READINT32(save_p);
 	ht->distance = READINT32(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3135,7 +3140,7 @@ static inline void LoadPolyrotatetThinker(actionf_p1 thinker)
 //
 // Loads a polymovet_t thinker
 //
-static void LoadPolymoveThinker(actionf_p1 thinker)
+static thinker_t* LoadPolymoveThinker(actionf_p1 thinker)
 {
 	polymove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3145,7 +3150,7 @@ static void LoadPolymoveThinker(actionf_p1 thinker)
 	ht->momy = READFIXED(save_p);
 	ht->distance = READINT32(save_p);
 	ht->angle = READANGLE(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3153,7 +3158,7 @@ static void LoadPolymoveThinker(actionf_p1 thinker)
 //
 // Loads a polywaypoint_t thinker
 //
-static inline void LoadPolywaypointThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker)
 {
 	polywaypoint_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3169,7 +3174,7 @@ static inline void LoadPolywaypointThinker(actionf_p1 thinker)
 	ht->diffx = READFIXED(save_p);
 	ht->diffy = READFIXED(save_p);
 	ht->diffz = READFIXED(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3177,7 +3182,7 @@ static inline void LoadPolywaypointThinker(actionf_p1 thinker)
 //
 // loads a polyslidedoor_t thinker
 //
-static inline void LoadPolyslidedoorThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPolyslidedoorThinker(actionf_p1 thinker)
 {
 	polyslidedoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3194,7 +3199,7 @@ static inline void LoadPolyslidedoorThinker(actionf_p1 thinker)
 	ht->momx = READFIXED(save_p);
 	ht->momy = READFIXED(save_p);
 	ht->closing = READUINT8(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3202,7 +3207,7 @@ static inline void LoadPolyslidedoorThinker(actionf_p1 thinker)
 //
 // Loads a polyswingdoor_t thinker
 //
-static inline void LoadPolyswingdoorThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPolyswingdoorThinker(actionf_p1 thinker)
 {
 	polyswingdoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3214,7 +3219,7 @@ static inline void LoadPolyswingdoorThinker(actionf_p1 thinker)
 	ht->initDistance = READINT32(save_p);
 	ht->distance = READINT32(save_p);
 	ht->closing = READUINT8(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3222,7 +3227,7 @@ static inline void LoadPolyswingdoorThinker(actionf_p1 thinker)
 //
 // Loads a polydisplace_t thinker
 //
-static inline void LoadPolydisplaceThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPolydisplaceThinker(actionf_p1 thinker)
 {
 	polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3231,10 +3236,10 @@ static inline void LoadPolydisplaceThinker(actionf_p1 thinker)
 	ht->dx = READFIXED(save_p);
 	ht->dy = READFIXED(save_p);
 	ht->oldHeights = READFIXED(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
-static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker)
+static inline thinker_t* LoadPolyrotdisplaceThinker(actionf_p1 thinker)
 {
 	polyrotdisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3243,7 +3248,7 @@ static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker)
 	ht->rotscale = READFIXED(save_p);
 	ht->turnobjs = READUINT8(save_p);
 	ht->oldHeights = READFIXED(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 
 //
@@ -3251,7 +3256,7 @@ static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker)
 //
 // Loads a polyfadet_t thinker
 //
-static void LoadPolyfadeThinker(actionf_p1 thinker)
+static thinker_t* LoadPolyfadeThinker(actionf_p1 thinker)
 {
 	polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
@@ -3263,7 +3268,7 @@ static void LoadPolyfadeThinker(actionf_p1 thinker)
 	ht->ticbased = (boolean)READUINT8(save_p);
 	ht->duration = READINT32(save_p);
 	ht->timer = READINT32(save_p);
-	P_AddThinker(&ht->thinker);
+	return &ht->thinker;
 }
 #endif
 
@@ -3296,15 +3301,18 @@ static void P_NetUnArchiveThinkers(void)
 		I_Error("Bad $$$.sav at archive block Thinkers");
 
 	// remove all the current thinkers
-	currentthinker = thinkercap.next;
-	for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = next)
+	for (i = 0; i < NUM_THINKERLISTS; i++)
 	{
-		next = currentthinker->next;
+		currentthinker = thlist[i].next;
+		for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = next)
+		{
+			next = currentthinker->next;
 
-		if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
-			P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it
-		else
-			Z_Free(currentthinker);
+			if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
+				P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it
+			else
+				Z_Free(currentthinker);
+		}
 	}
 
 	// we don't want the removed mobjs to come back
@@ -3318,202 +3326,208 @@ static void P_NetUnArchiveThinkers(void)
 	}
 
 	// read in saved thinkers
-	for (;;)
+	for (i = 0; i < NUM_THINKERLISTS; i++)
 	{
-		tclass = READUINT8(save_p);
+		for (;;)
+		{
+			thinker_t* th;
+			tclass = READUINT8(save_p);
 
-		if (tclass == tc_end)
-			break; // leave the saved thinker reading loop
-		numloaded++;
+			if (tclass == tc_end)
+				break; // leave the saved thinker reading loop
+			numloaded++;
 
-		switch (tclass)
-		{
-			case tc_mobj:
-				LoadMobjThinker((actionf_p1)P_MobjThinker);
-				break;
+			switch (tclass)
+			{
+				case tc_mobj:
+					th = LoadMobjThinker((actionf_p1)P_MobjThinker);
+					break;
 
-			case tc_ceiling:
-				LoadCeilingThinker((actionf_p1)T_MoveCeiling);
-				break;
+				case tc_ceiling:
+					th = LoadCeilingThinker((actionf_p1)T_MoveCeiling);
+					break;
 
-			case tc_crushceiling:
-				LoadCeilingThinker((actionf_p1)T_CrushCeiling);
-				break;
+				case tc_crushceiling:
+					th = LoadCeilingThinker((actionf_p1)T_CrushCeiling);
+					break;
 
-			case tc_floor:
-				LoadFloormoveThinker((actionf_p1)T_MoveFloor);
-				break;
+				case tc_floor:
+					th = LoadFloormoveThinker((actionf_p1)T_MoveFloor);
+					break;
 
-			case tc_flash:
-				LoadLightflashThinker((actionf_p1)T_LightningFlash);
-				break;
+				case tc_flash:
+					th = LoadLightflashThinker((actionf_p1)T_LightningFlash);
+					break;
 
-			case tc_strobe:
-				LoadStrobeThinker((actionf_p1)T_StrobeFlash);
-				break;
+				case tc_strobe:
+					th = LoadStrobeThinker((actionf_p1)T_StrobeFlash);
+					break;
 
-			case tc_glow:
-				LoadGlowThinker((actionf_p1)T_Glow);
-				break;
+				case tc_glow:
+					th = LoadGlowThinker((actionf_p1)T_Glow);
+					break;
 
-			case tc_fireflicker:
-				LoadFireflickerThinker((actionf_p1)T_FireFlicker);
-				break;
+				case tc_fireflicker:
+					th = LoadFireflickerThinker((actionf_p1)T_FireFlicker);
+					break;
 
-			case tc_elevator:
-				LoadElevatorThinker((actionf_p1)T_MoveElevator, 3);
-				break;
+				case tc_elevator:
+					th = LoadElevatorThinker((actionf_p1)T_MoveElevator, 3);
+					break;
 
-			case tc_continuousfalling:
-				LoadSpecialLevelThinker((actionf_p1)T_ContinuousFalling, 3);
-				break;
+				case tc_continuousfalling:
+					th = LoadSpecialLevelThinker((actionf_p1)T_ContinuousFalling, 3);
+					break;
 
-			case tc_thwomp:
-				LoadSpecialLevelThinker((actionf_p1)T_ThwompSector, 3);
-				break;
+				case tc_thwomp:
+					th = LoadSpecialLevelThinker((actionf_p1)T_ThwompSector, 3);
+					break;
 
-			case tc_noenemies:
-				LoadSpecialLevelThinker((actionf_p1)T_NoEnemiesSector, 0);
-				break;
+				case tc_noenemies:
+					th = LoadSpecialLevelThinker((actionf_p1)T_NoEnemiesSector, 0);
+					break;
 
-			case tc_eachtime:
-				LoadSpecialLevelThinker((actionf_p1)T_EachTimeThinker, 0);
-				break;
+				case tc_eachtime:
+					th = LoadSpecialLevelThinker((actionf_p1)T_EachTimeThinker, 0);
+					break;
 
-			case tc_raisesector:
-				LoadSpecialLevelThinker((actionf_p1)T_RaiseSector, 0);
-				break;
+				case tc_raisesector:
+					th = LoadSpecialLevelThinker((actionf_p1)T_RaiseSector, 0);
+					break;
 
-			/// \todo rewrite all the code that uses an elevator_t but isn't an elevator
-			/// \note working on it!
-			case tc_camerascanner:
-				LoadElevatorThinker((actionf_p1)T_CameraScanner, 0);
-				break;
+				/// \todo rewrite all the code that uses an elevator_t but isn't an elevator
+				/// \note working on it!
+				case tc_camerascanner:
+					th = LoadElevatorThinker((actionf_p1)T_CameraScanner, 0);
+					break;
 
-			case tc_bouncecheese:
-				LoadSpecialLevelThinker((actionf_p1)T_BounceCheese, 2);
-				break;
+				case tc_bouncecheese:
+					th = LoadSpecialLevelThinker((actionf_p1)T_BounceCheese, 2);
+					break;
 
-			case tc_startcrumble:
-				LoadElevatorThinker((actionf_p1)T_StartCrumble, 1);
-				break;
+				case tc_startcrumble:
+					th = LoadElevatorThinker((actionf_p1)T_StartCrumble, 1);
+					break;
 
-			case tc_marioblock:
-				LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3);
-				break;
+				case tc_marioblock:
+					th = LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3);
+					break;
 
-			case tc_marioblockchecker:
-				LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0);
-				break;
+				case tc_marioblockchecker:
+					th = LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0);
+					break;
 
-			case tc_spikesector:
-				LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0);
-				break;
+				case tc_spikesector:
+					th = LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0);
+					break;
 
-			case tc_floatsector:
-				LoadSpecialLevelThinker((actionf_p1)T_FloatSector, 0);
-				break;
+				case tc_floatsector:
+					th = LoadSpecialLevelThinker((actionf_p1)T_FloatSector, 0);
+					break;
 
-			case tc_bridgethinker:
-				LoadSpecialLevelThinker((actionf_p1)T_BridgeThinker, 3);
-				break;
+				case tc_bridgethinker:
+					th = LoadSpecialLevelThinker((actionf_p1)T_BridgeThinker, 3);
+					break;
 
-			case tc_laserflash:
-				LoadLaserThinker((actionf_p1)T_LaserFlash);
-				break;
+				case tc_laserflash:
+					th = LoadLaserThinker((actionf_p1)T_LaserFlash);
+					break;
 
-			case tc_lightfade:
-				LoadLightlevelThinker((actionf_p1)T_LightFade);
-				break;
+				case tc_lightfade:
+					th = LoadLightlevelThinker((actionf_p1)T_LightFade);
+					break;
 
-			case tc_executor:
-				LoadExecutorThinker((actionf_p1)T_ExecutorDelay);
-				restoreNum = true;
-				break;
+				case tc_executor:
+					th = LoadExecutorThinker((actionf_p1)T_ExecutorDelay);
+					restoreNum = true;
+					break;
 
-			case tc_disappear:
-				LoadDisappearThinker((actionf_p1)T_Disappear);
-				break;
+				case tc_disappear:
+					th = LoadDisappearThinker((actionf_p1)T_Disappear);
+					break;
 
-			case tc_fade:
-				LoadFadeThinker((actionf_p1)T_Fade);
-				break;
+				case tc_fade:
+					th = LoadFadeThinker((actionf_p1)T_Fade);
+					break;
 
-			case tc_fadecolormap:
-				LoadFadeColormapThinker((actionf_p1)T_FadeColormap);
-				break;
+				case tc_fadecolormap:
+					th = LoadFadeColormapThinker((actionf_p1)T_FadeColormap);
+					break;
 
-			case tc_planedisplace:
-				LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
-				break;
-#ifdef POLYOBJECTS
-			case tc_polyrotate:
-				LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
-				break;
+				case tc_planedisplace:
+					th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
+					break;
+	#ifdef POLYOBJECTS
+				case tc_polyrotate:
+					th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
+					break;
 
-			case tc_polymove:
-				LoadPolymoveThinker((actionf_p1)T_PolyObjMove);
-				break;
+				case tc_polymove:
+					th = LoadPolymoveThinker((actionf_p1)T_PolyObjMove);
+					break;
 
-			case tc_polywaypoint:
-				LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
-				break;
+				case tc_polywaypoint:
+					th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
+					break;
 
-			case tc_polyslidedoor:
-				LoadPolyslidedoorThinker((actionf_p1)T_PolyDoorSlide);
-				break;
+				case tc_polyslidedoor:
+					th = LoadPolyslidedoorThinker((actionf_p1)T_PolyDoorSlide);
+					break;
 
-			case tc_polyswingdoor:
-				LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing);
-				break;
+				case tc_polyswingdoor:
+					th = LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing);
+					break;
 
-			case tc_polyflag:
-				LoadPolymoveThinker((actionf_p1)T_PolyObjFlag);
-				break;
+				case tc_polyflag:
+					th = LoadPolymoveThinker((actionf_p1)T_PolyObjFlag);
+					break;
 
-			case tc_polydisplace:
-				LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace);
-				break;
+				case tc_polydisplace:
+					th = LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace);
+					break;
 
-			case tc_polyrotdisplace:
-				LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace);
-				break;
+				case tc_polyrotdisplace:
+					th = LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace);
+					break;
 
-			case tc_polyfade:
-				LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
-				break;
-#endif
-			case tc_scroll:
-				LoadScrollThinker((actionf_p1)T_Scroll);
-				break;
+				case tc_polyfade:
+					th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
+					break;
+	#endif
+				case tc_scroll:
+					th = LoadScrollThinker((actionf_p1)T_Scroll);
+					break;
 
-			case tc_friction:
-				LoadFrictionThinker((actionf_p1)T_Friction);
-				break;
+				case tc_friction:
+					th = LoadFrictionThinker((actionf_p1)T_Friction);
+					break;
 
-			case tc_pusher:
-				LoadPusherThinker((actionf_p1)T_Pusher);
-				break;
+				case tc_pusher:
+					th = LoadPusherThinker((actionf_p1)T_Pusher);
+					break;
 
-			default:
-				I_Error("P_UnarchiveSpecials: Unknown tclass %d in savegame", tclass);
+				default:
+					I_Error("P_UnarchiveSpecials: Unknown tclass %d in savegame", tclass);
+			}
+			if (th)
+				P_AddThinker(i, th);
 		}
-	}
 
-	CONS_Debug(DBG_NETPLAY, "%u thinkers loaded\n", numloaded);
+		CONS_Debug(DBG_NETPLAY, "%u thinkers loaded\n", numloaded);
 
-	if (restoreNum)
-	{
-		executor_t *delay = NULL;
-		UINT32 mobjnum;
-		for (currentthinker = thinkercap.next; currentthinker != &thinkercap;
-			currentthinker = currentthinker->next)
+		if (restoreNum)
 		{
-			if (currentthinker->function.acp1 == (actionf_p1)T_ExecutorDelay)
+			executor_t *delay = NULL;
+			UINT32 mobjnum;
+			for (currentthinker = thlist[i].next; currentthinker != &thlist[i];
+				currentthinker = currentthinker->next)
 			{
-				delay = (void *)currentthinker;
-				if ((mobjnum = (UINT32)(size_t)delay->caller))
-					delay->caller = P_FindNewPosition(mobjnum);
+				if (currentthinker->function.acp1 == (actionf_p1)T_ExecutorDelay)
+				{
+					delay = (void *)currentthinker;
+					if ((mobjnum = (UINT32)(size_t)delay->caller))
+						delay->caller = P_FindNewPosition(mobjnum);
+				}
 			}
 		}
 	}
@@ -3622,7 +3636,7 @@ static inline void P_FinishMobjs(void)
 	mobj_t *mobj;
 
 	// put info field there real value
-	for (currentthinker = thinkercap.next; currentthinker != &thinkercap;
+	for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN];
 		currentthinker = currentthinker->next)
 	{
 		if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
@@ -3640,7 +3654,7 @@ static void P_RelinkPointers(void)
 	UINT32 temp;
 
 	// use info field (value = oldposition) to relink mobjs
-	for (currentthinker = thinkercap.next; currentthinker != &thinkercap;
+	for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN];
 		currentthinker = currentthinker->next)
 	{
 		if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
@@ -4021,7 +4035,7 @@ void P_SaveNetGame(void)
 	P_NetArchiveMisc();
 
 	// Assign the mobjnumber for pointer tracking
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 		{
diff --git a/src/p_setup.c b/src/p_setup.c
index 3dd6739069e62997c6e9d66a19be8043b0fe2742..61389a131a4ba2c16ce0cbbbfb804152dafc489f 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -814,7 +814,7 @@ void P_ReloadRings(void)
 	mapthing_t *mt = mapthings;
 
 	// scan the thinkers to find rings/spheres/hoops to unset
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -883,7 +883,7 @@ void P_SwitchSpheresBonusMode(boolean bonustime)
 #endif
 
 	// scan the thinkers to find spheres to switch
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -2298,7 +2298,7 @@ void P_LoadThingsOnly(void)
 		}
 
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
diff --git a/src/p_spec.c b/src/p_spec.c
index 44edec870f832e700a6df1d95041718c263a1035..2c54eb2ab824320cccdf613a6a4d18062cb86f90 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1644,7 +1644,7 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj, sector_t *sector)
 	e->sector = sector;
 	e->timer = (line->backsector->ceilingheight>>FRACBITS)+(line->backsector->floorheight>>FRACBITS);
 	P_SetTarget(&e->caller, mobj); // Use P_SetTarget to make sure the mobj doesn't get freed while we're delaying.
-	P_AddThinker(&e->thinker);
+	P_AddThinker(THINK_MAIN, &e->thinker);
 }
 
 /** Used by P_RunTriggerLinedef to check a NiGHTS trigger linedef's conditions
@@ -2253,7 +2253,7 @@ void P_SwitchWeather(INT32 weathernum)
 		thinker_t *think;
 		precipmobj_t *precipmobj;
 
-		for (think = thinkercap.next; think != &thinkercap; think = think->next)
+		for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 		{
 			if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
 				continue; // not a precipmobj thinker
@@ -2269,7 +2269,7 @@ void P_SwitchWeather(INT32 weathernum)
 		precipmobj_t *precipmobj;
 		state_t *st;
 
-		for (think = thinkercap.next; think != &thinkercap; think = think->next)
+		for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 		{
 			if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
 				continue; // not a precipmobj thinker
@@ -3136,7 +3136,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 				scroll_t *scroller;
 				thinker_t *th;
 
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)T_Scroll)
 						continue;
@@ -3972,7 +3972,7 @@ void P_SetupSignExit(player_t *player)
 
 	// didn't find any signposts in the exit sector.
 	// spin all signposts in the level then.
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -4004,7 +4004,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
 	mobj_t *mo;
 	INT32 specialnum = 0;
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -4437,7 +4437,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
 
 			// Find the center of the Eggtrap and release all the pretty animals!
 			// The chimps are my friends.. heeheeheheehehee..... - LouisJM
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -4743,7 +4743,7 @@ DoneSection2:
 
 				// scan the thinkers
 				// to find the first waypoint
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -4822,7 +4822,7 @@ DoneSection2:
 
 				// scan the thinkers
 				// to find the last waypoint
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -4974,7 +4974,7 @@ DoneSection2:
 
 				// scan the thinkers
 				// to find the first waypoint
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -5012,7 +5012,7 @@ DoneSection2:
 				}
 
 				// Find waypoint before this one (waypointlow)
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -5039,7 +5039,7 @@ DoneSection2:
 				}
 
 				// Find waypoint after this one (waypointhigh)
-				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 				{
 					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 						continue;
@@ -5758,7 +5758,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
 
 	// Just initialise both of these to placate the compiler.
 	i = 0;
-	th = thinkercap.next;
+	th = thlist[THINK_MAIN].next;
 
 	for(;;)
 	{
@@ -5768,7 +5768,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
 				th = secthinkers[sec2num].thinkers[i];
 			else break;
 		}
-		else if (th == &thinkercap)
+		else if (th == &thlist[THINK_MAIN])
 			break;
 
 		// Should this FOF have spikeness?
@@ -5858,7 +5858,7 @@ static void P_AddSpikeThinker(sector_t *sec, INT32 referrer)
 
 	// create and initialize new thinker
 	spikes = Z_Calloc(sizeof (*spikes), PU_LEVSPEC, NULL);
-	P_AddThinker(&spikes->thinker);
+	P_AddThinker(THINK_MAIN, &spikes->thinker);
 
 	spikes->thinker.function.acp1 = (actionf_p1)T_SpikeSector;
 
@@ -5880,7 +5880,7 @@ static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline)
 
 	// create and initialize new thinker
 	floater = Z_Calloc(sizeof (*floater), PU_LEVSPEC, NULL);
-	P_AddThinker(&floater->thinker);
+	P_AddThinker(THINK_MAIN, &floater->thinker);
 
 	floater->thinker.function.acp1 = (actionf_p1)T_FloatSector;
 
@@ -5904,7 +5904,7 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
 
 	// create an initialize new thinker
 	bridge = Z_Calloc(sizeof (*bridge), PU_LEVSPEC, NULL);
-	P_AddThinker(&bridge->thinker);
+	P_AddThinker(THINK_MAIN, &bridge->thinker);
 
 	bridge->thinker.function.acp1 = (actionf_p1)T_BridgeThinker;
 
@@ -5940,7 +5940,7 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control,
 
 	// create and initialize new displacement thinker
 	displace = Z_Calloc(sizeof (*displace), PU_LEVSPEC, NULL);
-	P_AddThinker(&displace->thinker);
+	P_AddThinker(THINK_MAIN, &displace->thinker);
 
 	displace->thinker.function.acp1 = (actionf_p1)T_PlaneDisplace;
 	displace->affectee = affectee;
@@ -5967,7 +5967,7 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline)
 
 	// create and initialize new elevator thinker
 	block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
-	P_AddThinker(&block->thinker);
+	P_AddThinker(THINK_MAIN, &block->thinker);
 
 	block->thinker.function.acp1 = (actionf_p1)T_MarioBlockChecker;
 	block->sourceline = sourceline;
@@ -5996,7 +5996,7 @@ static void P_AddRaiseThinker(sector_t *sec, line_t *sourceline)
 	levelspecthink_t *raise;
 
 	raise = Z_Calloc(sizeof (*raise), PU_LEVSPEC, NULL);
-	P_AddThinker(&raise->thinker);
+	P_AddThinker(THINK_MAIN, &raise->thinker);
 
 	raise->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
 
@@ -6035,7 +6035,7 @@ static void P_AddOldAirbob(sector_t *sec, line_t *sourceline, boolean noadjust)
 	levelspecthink_t *airbob;
 
 	airbob = Z_Calloc(sizeof (*airbob), PU_LEVSPEC, NULL);
-	P_AddThinker(&airbob->thinker);
+	P_AddThinker(THINK_MAIN, &airbob->thinker);
 
 	airbob->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
 
@@ -6096,7 +6096,7 @@ static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, lin
 
 	// create and initialize new elevator thinker
 	thwomp = Z_Calloc(sizeof (*thwomp), PU_LEVSPEC, NULL);
-	P_AddThinker(&thwomp->thinker);
+	P_AddThinker(THINK_MAIN, &thwomp->thinker);
 
 	thwomp->thinker.function.acp1 = (actionf_p1)T_ThwompSector;
 
@@ -6132,7 +6132,7 @@ static inline void P_AddNoEnemiesThinker(sector_t *sec, line_t *sourceline)
 
 	// create and initialize new thinker
 	nobaddies = Z_Calloc(sizeof (*nobaddies), PU_LEVSPEC, NULL);
-	P_AddThinker(&nobaddies->thinker);
+	P_AddThinker(THINK_MAIN, &nobaddies->thinker);
 
 	nobaddies->thinker.function.acp1 = (actionf_p1)T_NoEnemiesSector;
 
@@ -6154,7 +6154,7 @@ static inline void P_AddEachTimeThinker(sector_t *sec, line_t *sourceline)
 
 	// create and initialize new thinker
 	eachtime = Z_Calloc(sizeof (*eachtime), PU_LEVSPEC, NULL);
-	P_AddThinker(&eachtime->thinker);
+	P_AddThinker(THINK_MAIN, &eachtime->thinker);
 
 	eachtime->thinker.function.acp1 = (actionf_p1)T_EachTimeThinker;
 
@@ -6176,7 +6176,7 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
 
 	// create and initialize new elevator thinker
 	elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
-	P_AddThinker(&elevator->thinker);
+	P_AddThinker(THINK_MAIN, &elevator->thinker);
 
 	elevator->thinker.function.acp1 = (actionf_p1)T_CameraScanner;
 	elevator->type = elevateBounce;
@@ -6272,7 +6272,7 @@ static inline void EV_AddLaserThinker(sector_t *sec, sector_t *sec2, line_t *lin
 
 	flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
 
-	P_AddThinker(&flash->thinker);
+	P_AddThinker(THINK_MAIN, &flash->thinker);
 
 	flash->thinker.function.acp1 = (actionf_p1)T_LaserFlash;
 	flash->ffloor = ffloor;
@@ -6441,7 +6441,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
 	secthinkers = Z_Calloc(numsectors * sizeof(thinkerlist_t), PU_STATIC, NULL);
 
 	// Firstly, find out how many there are in each sector
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 == (actionf_p1)T_SpikeSector)
 			secthinkers[((levelspecthink_t *)th)->sector - sectors].count++;
@@ -6461,7 +6461,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
 		}
 
 	// Finally, populate the lists.
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		size_t secnum = (size_t)-1;
 
@@ -7723,7 +7723,7 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3
 	if ((s->control = control) != -1)
 		s->last_height = sectors[control].floorheight + sectors[control].ceilingheight;
 	s->affectee = affectee;
-	P_AddThinker(&s->thinker);
+	P_AddThinker(THINK_MAIN, &s->thinker);
 }
 
 /** Initializes the scrollers.
@@ -7892,7 +7892,7 @@ static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t o
 	d->exists = true;
 	d->timer = 1;
 
-	P_AddThinker(&d->thinker);
+	P_AddThinker(THINK_MAIN, &d->thinker);
 }
 
 /** Makes a FOF appear/disappear
@@ -8381,7 +8381,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
 				FixedFloor(FixedDiv(abs(d->destvalue - d->alpha), d->speed))/FRACUNIT);
 	}
 
-	P_AddThinker(&d->thinker);
+	P_AddThinker(THINK_MAIN, &d->thinker);
 }
 
 /** Makes a FOF fade
@@ -8451,7 +8451,7 @@ static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, ext
 	}
 
 	sector->fadecolormapdata = d;
-	P_AddThinker(&d->thinker); // add thinker
+	P_AddThinker(THINK_MAIN, &d->thinker); // add thinker
 }
 
 void T_FadeColormap(fadecolormap_t *d)
@@ -8570,7 +8570,7 @@ static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32
 	else
 		f->roverfriction = false;
 
-	P_AddThinker(&f->thinker);
+	P_AddThinker(THINK_MAIN, &f->thinker);
 }
 
 /** Applies friction to all things in a sector.
@@ -8736,7 +8736,7 @@ static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *
 		p->z = p->source->z;
 	}
 	p->affectee = affectee;
-	P_AddThinker(&p->thinker);
+	P_AddThinker(THINK_MAIN, &p->thinker);
 }
 
 
diff --git a/src/p_tick.c b/src/p_tick.c
index 6f7c96ead28bf5a7ca1061345959ba46d874ddd3..f4f73aa3d6fc56f6aeb446d4b8620cb86bad68b0 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -35,8 +35,8 @@ tic_t leveltime;
 // but the first element must be thinker_t.
 //
 
-// Both the head and tail of the thinker list.
-thinker_t thinkercap;
+// The entries will behave like both the head and tail of the lists.
+thinker_t thlist[NUM_THINKERLISTS];
 
 void Command_Numthinkers_f(void)
 {
@@ -102,7 +102,7 @@ void Command_Numthinkers_f(void)
 			return;
 	}
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != action)
 			continue;
@@ -139,7 +139,7 @@ void Command_CountMobjs_f(void)
 
 			count = 0;
 
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -159,7 +159,7 @@ void Command_CountMobjs_f(void)
 	{
 		count = 0;
 
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -178,19 +178,18 @@ void Command_CountMobjs_f(void)
 //
 void P_InitThinkers(void)
 {
-	thinkercap.prev = thinkercap.next = &thinkercap;
+	UINT8 i;
+	for (i = 0; i < NUM_THINKERLISTS; i++)
+		thlist[i].prev = thlist[i].next = &thlist[i];
 }
 
-//
-// P_AddThinker
 // Adds a new thinker at the end of the list.
-//
-void P_AddThinker(thinker_t *thinker)
+void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
 {
-	thinkercap.prev->next = thinker;
-	thinker->next = &thinkercap;
-	thinker->prev = thinkercap.prev;
-	thinkercap.prev = thinker;
+	thlist[n].prev->next = thinker;
+	thinker->next = &thlist[n];
+	thinker->prev = thlist[n].prev;
+	thlist[n].prev = thinker;
 
 	thinker->references = 0;    // killough 11/98: init reference counter to 0
 }
@@ -296,11 +295,17 @@ if ((*mop = targ) != NULL) // Set new target and if non-NULL, increase its count
 //
 static inline void P_RunThinkers(void)
 {
-	for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = currentthinker->next)
+	size_t i;
+	for (i = 0; i < NUM_THINKERLISTS; i++)
 	{
-		if (currentthinker->function.acp1)
-			currentthinker->function.acp1(currentthinker);
+		//CONS_Printf("Running thinker list %d.\n", i);
+		for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next)
+		{
+			if (currentthinker->function.acp1)
+				currentthinker->function.acp1(currentthinker);
+		}
 	}
+
 }
 
 //
diff --git a/src/p_user.c b/src/p_user.c
index ca14c64d4367a04e53b2afe60787885d21e6cd7b..fa5b0f5022b2b126358358473dc4d506a3134da5 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -343,7 +343,7 @@ UINT8 P_FindLowestMare(void)
 
 	// scan the thinkers
 	// to find the egg capsule with the lowest mare
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -392,7 +392,7 @@ boolean P_TransferToNextMare(player_t *player)
 
 	// scan the thinkers
 	// to find the closest axis point
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -443,7 +443,7 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
 
 	// scan the thinkers
 	// to find the closest axis point
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -476,7 +476,7 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
 
 	// scan the thinkers
 	// to find the closest axis point
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -515,7 +515,7 @@ void P_TransferToAxis(player_t *player, INT32 axisnum)
 
 	// scan the thinkers
 	// to find the closest axis point
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -615,7 +615,7 @@ static void P_DeNightserizePlayer(player_t *player)
 	}
 
 	// Check to see if the player should be killed.
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -1567,7 +1567,7 @@ void P_SpawnShieldOrb(player_t *player)
 	}
 
 	// blaze through the thinkers to see if an orb already exists!
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -3057,7 +3057,7 @@ static void P_DoClimbing(player_t *player)
 			angle_t sideangle;
 			fixed_t dx, dy;
 
-			for (think = thinkercap.next; think != &thinkercap; think = think->next)
+			for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 			{
 				if (think->function.acp1 != (actionf_p1)T_Scroll)
 					continue;
@@ -4438,7 +4438,7 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range)
 	if (player->powers[pw_super]) // increase range when super
 		range *= 2;
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -5635,7 +5635,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 		fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags2 & MF2_AMBUSH ? -1 : 1);
 
 		// Find next waypoint
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 				continue;
@@ -5671,7 +5671,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 		// Look for a wrapper point.
 		if (!transfer1)
 		{
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 					continue;
@@ -5699,7 +5699,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
 		}
 		if (!transfer2)
 		{
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 					continue;
@@ -6406,7 +6406,7 @@ static void P_NiGHTSMovement(player_t *player)
 
 		// scan the thinkers
 		// to find the closest axis point
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
@@ -7216,7 +7216,7 @@ static void P_MovePlayer(player_t *player)
 			thinker_t *th;
 			mobj_t *mo2;
 
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 					continue;
@@ -8124,7 +8124,7 @@ static void P_DoZoomTube(player_t *player)
 		CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
 
 		// Find next waypoint
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 				continue;
@@ -8258,7 +8258,7 @@ static void P_DoRopeHang(player_t *player)
 		CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
 
 		// Find next waypoint
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 				continue;
@@ -8283,7 +8283,7 @@ static void P_DoRopeHang(player_t *player)
 			CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, wrapping to start...\n");
 
 			// Wrap around back to first waypoint
-			for (th = thinkercap.next; th != &thinkercap; th = th->next)
+			for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 			{
 				if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
 					continue;
@@ -8349,7 +8349,7 @@ static void P_NukeAllPlayers(player_t *player)
 	mobj_t *mo;
 	thinker_t *think;
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -8397,7 +8397,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
 		}
 	}
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -8448,7 +8448,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
 	const angle_t span = (bullet ? ANG30 : ANGLE_90);
 	fixed_t dist, closestdist = 0;
 
-	for (think = thinkercap.next; think != &thinkercap; think = think->next)
+	for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
 	{
 		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue; // not a mobj thinker
@@ -8587,7 +8587,7 @@ void P_FindEmerald(void)
 
 	// scan the remaining thinkers
 	// to find all emeralds
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;
@@ -10013,7 +10013,7 @@ void P_PlayerThink(player_t *player)
 		fixed_t y = player->mo->y;
 		fixed_t z = player->mo->z;
 
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		{
 			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 				continue;
diff --git a/src/r_data.c b/src/r_data.c
index 838bc160cdbf9942727ed8defe709cac25eece53..dbbc615fcf376f4f84f206c43758feb48e14f916 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -2242,7 +2242,7 @@ void R_PrecacheLevel(void)
 	spritepresent = calloc(numsprites, sizeof (*spritepresent));
 	if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel");
 
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 			spritepresent[((mobj_t *)th)->sprite] = 1;
 
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 9ad04b5ce4c1b17b6728728a9d0d0f00ef59dac8..a946bf516a4af878f24fad2df63ca7c540c51e97 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -2289,7 +2289,7 @@ static void ST_doItemFinderIconsAndSound(void)
 		return;
 
 	// Scan thinkers to find emblem mobj with these ids
-	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
 	{
 		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
 			continue;