diff --git a/src/doomstat.h b/src/doomstat.h
index 5d91ebfddef4f93f508ec8efd35a8040cc7265c5..95cb9f6a855da3b56263b824cbc5d3099a643729 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -638,8 +638,7 @@ extern tic_t gametic;
 
 // Player spawn spots.
 extern mapthing_t *playerstarts[MAXPLAYERS]; // Cooperative
-extern mapthing_t *bluectfstarts[MAXPLAYERS]; // CTF
-extern mapthing_t *redctfstarts[MAXPLAYERS]; // CTF
+extern mapthing_t *teamstarts[MAXTEAMS][MAXPLAYERS]; // CTF
 
 #define WAYPOINTSEQUENCESIZE 256
 #define NUMWAYPOINTSEQUENCES 256
diff --git a/src/g_game.c b/src/g_game.c
index 08beccd92d465cfaf6efe95da35f03a106652f1d..a79a2321d5e748ec846abbbf19d7368dce5f4286 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2828,7 +2828,7 @@ void G_SpawnPlayer(INT32 playernum)
 
 	P_SpawnPlayer(playernum);
 	G_MovePlayerToSpawnOrStarpost(playernum);
-	LUA_HookPlayer(&players[playernum], HOOK(PlayerSpawn)); // Lua hook for player spawning :)
+	LUA_HookPlayer(&players[playernum], HOOK(PlayerSpawn));
 }
 
 void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
@@ -2849,57 +2849,55 @@ void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
 		P_ResetCamera(&players[playernum], &camera2);
 }
 
-mapthing_t *G_FindCTFStart(INT32 playernum)
+enum
 {
-	INT32 i,j;
+	PLAYER_START_TYPE_COOP,
+	PLAYER_START_TYPE_MATCH,
+	PLAYER_START_TYPE_TEAM
+};
 
-	if (!numredctfstarts && !numbluectfstarts) //why even bother, eh?
-	{
-		if ((gametyperules & GTR_TEAMFLAGS) && (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)))
-			CONS_Alert(CONS_WARNING, M_GetText("No CTF starts in this map!\n"));
-		return NULL;
-	}
+static boolean G_AreCoopStartsAvailable(void)
+{
+	return numcoopstarts != 0;
+}
 
-	if ((!players[playernum].ctfteam && numredctfstarts && (!numbluectfstarts || P_RandomChance(FRACUNIT/2))) || players[playernum].ctfteam == TEAM_RED) //red
-	{
-		if (!numredctfstarts)
-		{
-			if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-				CONS_Alert(CONS_WARNING, M_GetText("No Red Team starts in this map!\n"));
-			return NULL;
-		}
+static boolean G_AreMatchStartsAvailable(void)
+{
+	return numdmstarts != 0;
+}
 
-		for (j = 0; j < 32; j++)
-		{
-			i = P_RandomKey(numredctfstarts);
-			if (G_CheckSpot(playernum, redctfstarts[i]))
-				return redctfstarts[i];
-		}
+static boolean G_AreTeamStartsAvailable(UINT8 team)
+{
+	if (team >= numteams)
+		return false;
 
-		if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-			CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Red Team starts!\n"));
-		return NULL;
-	}
-	else if (!players[playernum].ctfteam || players[playernum].ctfteam == TEAM_BLUE) //blue
-	{
-		if (!numbluectfstarts)
-		{
-			if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-				CONS_Alert(CONS_WARNING, M_GetText("No Blue Team starts in this map!\n"));
-			return NULL;
-		}
+	return numteamstarts[team] != 0;
+}
 
-		for (j = 0; j < 32; j++)
+static boolean G_AreTeamStartsAvailableForPlayer(INT32 playernum)
+{
+	UINT8 team = players[playernum].ctfteam;
+	if (team != TEAM_NONE && team < numteams)
+		return G_AreTeamStartsAvailable(team);
+	return G_AreMatchStartsAvailable();
+}
+
+mapthing_t *G_FindTeamStart(INT32 playernum)
+{
+	UINT8 team = players[playernum].ctfteam;
+	if (team == TEAM_NONE || team >= numteams)
+		return G_FindMatchStart(playernum);
+
+	if (G_AreTeamStartsAvailable(team))
+	{
+		for (INT32 j = 0; j < MAXPLAYERS; j++)
 		{
-			i = P_RandomKey(numbluectfstarts);
-			if (G_CheckSpot(playernum, bluectfstarts[i]))
-				return bluectfstarts[i];
+			INT32 i = P_RandomKey(numteamstarts[team]);
+			if (G_CheckSpot(playernum, teamstarts[team][i]))
+				return teamstarts[team][i];
 		}
-		if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-			CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Blue Team starts!\n"));
-		return NULL;
 	}
-	//should never be reached but it gets stuff to shut up
+
 	return NULL;
 }
 
@@ -2907,7 +2905,7 @@ mapthing_t *G_FindMatchStart(INT32 playernum)
 {
 	INT32 i, j;
 
-	if (numdmstarts)
+	if (G_AreMatchStartsAvailable())
 	{
 		for (j = 0; j < 64; j++)
 		{
@@ -2915,19 +2913,14 @@ mapthing_t *G_FindMatchStart(INT32 playernum)
 			if (G_CheckSpot(playernum, deathmatchstarts[i]))
 				return deathmatchstarts[i];
 		}
-		if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-			CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n"));
-		return NULL;
 	}
 
-	if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-		CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n"));
 	return NULL;
 }
 
 mapthing_t *G_FindCoopStart(INT32 playernum)
 {
-	if (numcoopstarts)
+	if (G_AreCoopStartsAvailable())
 	{
 		//if there's 6 players in a map with 3 player starts, this spawns them 1/2/3/1/2/3.
 		if (G_CheckSpot(playernum, playerstarts[playernum % numcoopstarts]))
@@ -2938,82 +2931,208 @@ mapthing_t *G_FindCoopStart(INT32 playernum)
 		return playerstarts[0];
 	}
 
-	if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
-		CONS_Alert(CONS_WARNING, M_GetText("No Co-op starts in this map!\n"));
 	return NULL;
 }
 
-// Find a Co-op start, or fallback into other types of starts.
-static inline mapthing_t *G_FindCoopStartOrFallback(INT32 playernum)
+static mapthing_t *G_FindBestStart(INT32 playernum, INT32 type)
 {
-	mapthing_t *spawnpoint = NULL;
-	if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start
-	&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
-		spawnpoint = G_FindCTFStart(playernum); // fallback
+	switch (type)
+	{
+	case PLAYER_START_TYPE_COOP:
+		return G_FindCoopStart(playernum);
+	case PLAYER_START_TYPE_MATCH:
+		return G_FindMatchStart(playernum);
+	case PLAYER_START_TYPE_TEAM:
+		return G_FindTeamStart(playernum);
+	}
+	return NULL;
+}
+
+static mapthing_t *G_FindBestStartInOrder(INT32 playernum, INT32 *order, UINT8 numtries)
+{
+	for (unsigned i = 0; i < numtries; i++)
+	{
+		mapthing_t *spawnpoint = G_FindBestStart(playernum, order[i]);
+		if (spawnpoint)
+			return spawnpoint;
+	}
+
+	return NULL;
+}
+
+// Gets a Co-op start, or returns NULL if none was found.
+// If no Co-op start was found, it looks for a Match start, and then a team start.
+static mapthing_t *G_FindBestCoopStart(INT32 playernum)
+{
+	INT32 order[] = {
+		PLAYER_START_TYPE_COOP,
+		PLAYER_START_TYPE_MATCH,
+		PLAYER_START_TYPE_TEAM
+	};
+	return G_FindBestStartInOrder(playernum, order, sizeof(order) / sizeof(order[0]));
+}
+
+// Gets a Match start, or returns NULL if none was found.
+// If no Match start was found, it looks for a team start, and then a Co-op start.
+static mapthing_t *G_FindBestMatchStart(INT32 playernum)
+{
+	INT32 order[] = {
+		PLAYER_START_TYPE_MATCH,
+		PLAYER_START_TYPE_TEAM,
+		PLAYER_START_TYPE_COOP
+	};
+	return G_FindBestStartInOrder(playernum, order, sizeof(order) / sizeof(order[0]));
+}
+
+// Gets a team start, or returns NULL if none was found.
+// If no team start was found, it looks for a Match start, and then a Co-op start.
+static mapthing_t *G_FindBestTeamStart(INT32 playernum)
+{
+	INT32 order[] = {
+		PLAYER_START_TYPE_TEAM,
+		PLAYER_START_TYPE_MATCH,
+		PLAYER_START_TYPE_COOP
+	};
+	return G_FindBestStartInOrder(playernum, order, sizeof(order) / sizeof(order[0]));
+}
+
+// Gets a Co-op start, or shows a warning to the player if none was found.
+// If no Co-op start was found, it looks for a Match start, and then a team start.
+static mapthing_t *G_GetCoopStartForSpawning(INT32 playernum)
+{
+	player_t *player = &players[playernum];
+	mapthing_t *spawnpoint = G_FindBestCoopStart(playernum);
+
+	if (P_IsLocalPlayer(player))
+	{
+		boolean has_starts = G_AreCoopStartsAvailable();
+		if (spawnpoint && !has_starts)
+			CONS_Alert(CONS_WARNING, M_GetText("No Co-Op starts in this map!\n"));
+		else if (spawnpoint == NULL && has_starts) // This never happens, but in case it does, this will display a warning.
+			CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Co-Op starts!\n"));
+	}
+
 	return spawnpoint;
 }
 
-// Find a Match start, or fallback into other types of starts.
-static inline mapthing_t *G_FindMatchStartOrFallback(INT32 playernum)
+// Gets a Match start, or shows a warning to the player if none was found.
+// If no Match start was found, it looks for a team start, and then a Co-op start.
+static mapthing_t *G_GetMatchStartForSpawning(INT32 playernum)
 {
-	mapthing_t *spawnpoint = NULL;
-	if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start
-	&& !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start
-		spawnpoint = G_FindCoopStart(playernum); // fallback
+	player_t *player = &players[playernum];
+	mapthing_t *spawnpoint = G_FindBestMatchStart(playernum);
+
+	if (P_IsLocalPlayer(player))
+	{
+		boolean has_starts = G_AreMatchStartsAvailable();
+		if (spawnpoint && !has_starts)
+			CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n"));
+		else if (spawnpoint == NULL && has_starts)
+			CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n"));
+	}
+
 	return spawnpoint;
 }
 
-mapthing_t *G_FindMapStart(INT32 playernum)
+// Gets a team start, or shows a warning to the player if none was found.
+// If no team start was found, it looks for a Match start, and then a Co-op start.
+static mapthing_t *G_GetTeamStartForSpawning(INT32 playernum)
 {
-	mapthing_t *spawnpoint;
+	player_t *player = &players[playernum];
+	mapthing_t *spawnpoint = G_FindBestTeamStart(playernum);
+
+	if (P_IsLocalPlayer(player))
+	{
+		boolean has_starts = G_AreTeamStartsAvailableForPlayer(playernum);
+		if (spawnpoint && !has_starts)
+		{
+			if (player->ctfteam)
+				CONS_Alert(CONS_WARNING, M_GetText("No %s starts in this map!\n"), G_GetTeamName(player->ctfteam));
+			else
+				CONS_Alert(CONS_WARNING, M_GetText("No team starts in this map!\n"));
+		}
+		else if (spawnpoint == NULL && has_starts)
+		{
+			if (player->ctfteam)
+				CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any %s starts!\n"), G_GetTeamName(player->ctfteam));
+			else
+				CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any team starts!\n"));
+		}
+	}
+
+	return spawnpoint;
+}
 
+mapthing_t *G_FindMapStart(INT32 playernum)
+{
 	if (!playeringame[playernum])
 		return NULL;
 
+	player_t *player = &players[playernum];
+	mapthing_t *spawnpoint = NULL;
+
 	// -- Spectators --
 	// Order in platform gametypes: Coop->DM->CTF
-	// And, with deathmatch starts: DM->CTF->Coop
-	if (players[playernum].spectator)
+	// Otherwise: DM->CTF->Coop
+	if (player->spectator)
 	{
 		// In platform gametypes, spawn in Co-op starts first
 		// Overriden by GTR_DEATHMATCHSTARTS.
 		if (G_PlatformGametype() && !(gametyperules & GTR_DEATHMATCHSTARTS))
-			spawnpoint = G_FindCoopStartOrFallback(playernum);
+			spawnpoint = G_GetCoopStartForSpawning(playernum);
 		else
-			spawnpoint = G_FindMatchStartOrFallback(playernum);
+			spawnpoint = G_GetMatchStartForSpawning(playernum);
 	}
 
 	// -- CTF --
 	// Order: CTF->DM->Coop
-	else if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam)
+	else if (gametyperules & GTR_TEAMFLAGS)
 	{
-		if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start
-		&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
-			spawnpoint = G_FindCoopStart(playernum); // fallback
+		if (player->ctfteam)
+			spawnpoint = G_GetTeamStartForSpawning(playernum);
+		else
+			spawnpoint = G_GetMatchStartForSpawning(playernum);
 	}
 
-	// -- DM/Tag/CTF-spectator/etc --
+	// -- DM/Tag/etc --
 	// Order: DM->CTF->Coop
-	else if (G_TagGametype() ? (!(players[playernum].pflags & PF_TAGIT)) : (gametyperules & GTR_DEATHMATCHSTARTS))
-		spawnpoint = G_FindMatchStartOrFallback(playernum);
+	else if (gametyperules & GTR_DEATHMATCHSTARTS)
+	{
+		// If the current gametype has teams, but isn't CTF, then this looks for a team start first
+		// If the player is not in a team, then this just gets a match start.
+		if (G_GametypeHasTeams() && player->ctfteam > TEAM_NONE && player->ctfteam < numteams)
+		{
+			spawnpoint = G_FindTeamStart(playernum);
+
+			// If no spawn point was found, but team starts are available, this means there is no good location
+			// for the player to spawn at. In that situation, we display a message telling the player so.
+			if (spawnpoint == NULL && G_AreTeamStartsAvailable(player->ctfteam) && P_IsLocalPlayer(player))
+				CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any %s starts!\n"), G_GetTeamName(player->ctfteam));
+		}
+
+		// If that failed, no warning is shown. Instead, this will look for a match start, which may
+		// then display a warning if no suitable map starts were found.
+		if (spawnpoint == NULL)
+			spawnpoint = G_GetMatchStartForSpawning(playernum);
+	}
 
 	// -- Other game modes --
 	// Order: Coop->DM->CTF
 	else
-		spawnpoint = G_FindCoopStartOrFallback(playernum);
+		spawnpoint = G_GetCoopStartForSpawning(playernum);
 
 	//No spawns found. ANYWHERE.
 	if (!spawnpoint)
 	{
 		if (nummapthings)
 		{
-			if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
+			if (P_IsLocalPlayer(player))
 				CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n"));
 			spawnpoint = &mapthings[0];
 		}
 		else
 		{
-			if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
+			if (P_IsLocalPlayer(player))
 				CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n"));
 		}
 	}
diff --git a/src/g_game.h b/src/g_game.h
index b1d8d1bbbc1370075376cf5a26a3bba18ba08cc3..fe22ef10c0e83264a5d52a22984e7f002b7634e0 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -165,7 +165,7 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc);
 INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep);
 
 // XMOD spawning
-mapthing_t *G_FindCTFStart(INT32 playernum);
+mapthing_t *G_FindTeamStart(INT32 playernum);
 mapthing_t *G_FindMatchStart(INT32 playernum);
 mapthing_t *G_FindCoopStart(INT32 playernum);
 mapthing_t *G_FindMapStart(INT32 playernum);
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 7bd61a439a5a5f56c8b2fdd20ef8378f53450b2a..86cd06deb641717e573f82a65fb3a7efb5b163a1 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -837,7 +837,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
 			fmt2 = "%s<%s%s%s>\x80 %s%s";
 		else // To your team
 		{
-			if (players[playernum].ctfteam != 0)
+			if (players[playernum].ctfteam > TEAM_NONE && players[playernum].ctfteam < numteams)
 			{
 				tempteam = Z_StrDup(va("%s[TEAM]", GetChatColorForSkincolor(G_GetTeamColor(players[playernum].ctfteam))));
 				prefix = tempteam;
diff --git a/src/p_map.c b/src/p_map.c
index ae58aa391aff058483896f166cfe2d62233225cc..f6176fc54ed8e8c229e09e155a14c365943701cc 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -1691,7 +1691,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
 		}
 		// Monitor?
 		else if (thing->flags & MF_MONITOR
-		&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != TEAM_RED) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != TEAM_BLUE))
+		&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != G_GetTeam(TEAM_RED)) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != G_GetTeam(TEAM_BLUE)))
 		&& (!(thing->flags & MF_SOLID) || P_PlayerCanDamage(tmthing->player, thing)))
 		{
 			if (thing->z - thing->scale <= tmthing->z + tmthing->height
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 6300bde4814bb6f2093fb07d9535f24648053857..2db4406cab044cc0dbbd360f9629c1077c41bf17 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -10042,7 +10042,7 @@ static void P_FlagFuseThink(mobj_t *mobj)
 	// Assumedly in splitscreen players will be on opposing teams
 	if (players[consoleplayer].ctfteam == team || splitscreen)
 		S_StartSound(NULL, sfx_hoop1);
-	else if (players[consoleplayer].ctfteam != 0)
+	else if (players[consoleplayer].ctfteam > TEAM_NONE && players[consoleplayer].ctfteam < numteams)
 		S_StartSound(NULL, sfx_hoop3);
 
 	P_SetTarget(&flagmobjs[team], flagmo);
@@ -11933,6 +11933,17 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
 	return P_GetMobjSpawnHeight(mobjtype, x, y, dz, offset, flip, mthing->scale);
 }
 
+static void P_SetTeamStart(UINT8 team, mapthing_t *mthing)
+{
+	if (team != TEAM_NONE && team < numteams && numteamstarts[team] < MAXPLAYERS)
+	{
+		teamstarts[team][numteamstarts[team]] = mthing;
+		numteamstarts[team]++;
+		numteamstarts[0]++;
+		mthing->type = 0;
+	}
+}
+
 static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
 {
 #if MAXPLAYERS > 32
@@ -11957,22 +11968,12 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
 	}
 	else if (mthing->type == 34) // Red CTF starts
 	{
-		if (numredctfstarts < MAXPLAYERS)
-		{
-			redctfstarts[numredctfstarts] = mthing;
-			mthing->type = 0;
-			numredctfstarts++;
-		}
+		P_SetTeamStart(G_GetTeam(TEAM_RED), mthing);
 		return true;
 	}
 	else if (mthing->type == 35) // Blue CTF starts
 	{
-		if (numbluectfstarts < MAXPLAYERS)
-		{
-			bluectfstarts[numbluectfstarts] = mthing;
-			mthing->type = 0;
-			numbluectfstarts++;
-		}
+		P_SetTeamStart(G_GetTeam(TEAM_BLUE), mthing);
 		return true;
 	}
 	else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
@@ -14068,15 +14069,8 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
 //
 void P_ColorTeamMissile(mobj_t *missile, player_t *source)
 {
-	if (G_GametypeHasTeams())
-	{
-		if (source->ctfteam != 0)
-			missile->color = G_GetTeamMissileColor(source->ctfteam);
-	}
-	/*
-	else
-		missile->color = player->mo->color; //copy color
-	*/
+	if (G_GametypeHasTeams() && source->ctfteam > TEAM_NONE && source->ctfteam < numteams)
+		missile->color = G_GetTeamMissileColor(source->ctfteam);
 }
 
 //
diff --git a/src/p_setup.c b/src/p_setup.c
index a69f303b6e9a963e566dcc5f68a1b5e075f4d3e7..1b3f5b4efb01a03cdc910c63ed44ce73f46db7e2 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -144,12 +144,11 @@ mobj_t **blocklinks;
 UINT8 *rejectmatrix;
 
 // Maintain single and multi player starting spots.
-INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
+INT32 numdmstarts, numcoopstarts, numteamstarts[MAXTEAMS];
 
 mapthing_t *deathmatchstarts[MAX_DM_STARTS];
 mapthing_t *playerstarts[MAXPLAYERS];
-mapthing_t *bluectfstarts[MAXPLAYERS];
-mapthing_t *redctfstarts[MAXPLAYERS];
+mapthing_t *teamstarts[MAXTEAMS][MAXPLAYERS];
 
 // Maintain waypoints
 mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE];
@@ -7232,17 +7231,25 @@ static void P_ForceCharacter(const char *forcecharskin)
 
 static void P_ResetSpawnpoints(void)
 {
-	UINT8 i;
+	UINT8 i, j;
 
-	numdmstarts = numredctfstarts = numbluectfstarts = 0;
+	numdmstarts = 0;
 
 	// reset the player starts
 	for (i = 0; i < MAXPLAYERS; i++)
-		playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
+		playerstarts[i] = NULL;
 
 	for (i = 0; i < MAX_DM_STARTS; i++)
 		deathmatchstarts[i] = NULL;
 
+	for (i = 0; i < MAXTEAMS; i++)
+	{
+		numteamstarts[i] = 0;
+
+		for (j = 0; j < MAXPLAYERS; j++)
+			teamstarts[i][j] = NULL;
+	}
+
 	for (i = 0; i < 2; i++)
 		skyboxmo[i] = NULL;
 
diff --git a/src/p_setup.h b/src/p_setup.h
index c6f4f741c01c56fecfc5b0fa0fb267fb1c975b16..6e00a5b5cba59385e3fe4713213292c694401e2b 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -24,7 +24,7 @@ extern unsigned char mapmd5[16];
 // Player spawn spots for deathmatch.
 #define MAX_DM_STARTS 64
 extern mapthing_t *deathmatchstarts[MAX_DM_STARTS];
-extern INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
+extern INT32 numdmstarts, numcoopstarts, numteamstarts[MAXTEAMS];
 
 extern boolean levelloading;
 extern UINT8 levelfadecol;
diff --git a/src/p_spec.c b/src/p_spec.c
index 1606c55add3edd4c5e0bb3753f36392cddac5845..7b58294a0d67fb5e0212866ff590073cdd4cc7fb 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1783,7 +1783,7 @@ void P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller)
 			// Only red/blue team members can activate this.
 			if (!(actor && actor->player))
 				return;
-			if (actor->player->ctfteam != ((triggerline->args[1] == TMT_RED) ? TEAM_RED : TEAM_BLUE))
+			if (actor->player->ctfteam != ((triggerline->args[1] == TMT_RED) ? G_GetTeam(TEAM_RED) : G_GetTeam(TEAM_BLUE)))
 				return;
 			break;
 		case 314:
diff --git a/src/st_stuff.c b/src/st_stuff.c
index aad5b506d7267bbcb524aeb5b662c69f7d6e7408..b067c00826de79af8a14fc03df471d29663cbce6 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -907,7 +907,7 @@ static void ST_drawLivesArea(void)
 		}
 		else if (G_GametypeHasTeams())
 		{
-			if (stplyr->ctfteam != 0)
+			if (stplyr->ctfteam > TEAM_NONE && stplyr->ctfteam < numteams)
 			{
 				v_colmap = skincolors[G_GetTeamColor(stplyr->ctfteam)].chatcolor;
 			}
@@ -994,7 +994,7 @@ static void ST_drawLivesArea(void)
 			}
 			else if (G_GametypeHasTeams())
 			{
-				if (stplyr->ctfteam != 0)
+				if (stplyr->ctfteam > TEAM_NONE && stplyr->ctfteam < numteams)
 				{
 					V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, G_GetTeamName(stplyr->ctfteam));
 				}