diff --git a/src/deh_tables.c b/src/deh_tables.c
index 689d8746b86429c594894216969e98b3b39f89ee..85ecac3a08d7ff9a1e96d02d4a7d677279e4eaef 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -4415,6 +4415,7 @@ const char *const MOBJEFLAG_LIST[] = {
 	"TRACERANGLE", // Compute and trigger on mobj angle relative to tracer
 	"FORCESUPER", // Forces an object to use super sprites with SPR_PLAY.
 	"FORCENOSUPER", // Forces an object to NOT use super sprites with SPR_PLAY.
+	"TEAMITEM", // Object is a team item
 	"TEAMFLAG", // Object is a team flag
 	NULL
 };
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 318a9e974618f534650a269a279a8036a9161894..859702b4c2d207870ea1e66d0adf34601aa13fe1 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -823,9 +823,8 @@ static boolean P_LookForShield(mobj_t *actor)
 		if (!player->mo || player->mo->health <= 0)
 			continue; // dead
 
-		//When in CTF, don't pull rings that you cannot pick up.
-		if ((actor->type == MT_REDTEAMRING && player->ctfteam != G_GetTeam(TEAM_RED)) ||
-			(actor->type == MT_BLUETEAMRING && player->ctfteam != G_GetTeam(TEAM_BLUE)))
+		// Don't pull rings that you cannot pick up.
+		if ((actor->eflags & MFE_TEAMITEM) && player->ctfteam != actor->extravalue1)
 			continue;
 
 		if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
diff --git a/src/p_inter.c b/src/p_inter.c
index 84da2a437d2fbc05780a905176804ff2d16a5edb..58dc198ebf1a1e422a4959aa901325ed510277b2 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -414,6 +414,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 	if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special))
 		return;
 
+	// Don't collide with items meant for opposing teams
+	if (special->eflags & MFE_TEAMITEM && player->ctfteam != special->extravalue1)
+		return;
+
 	// 0 = none, 1 = elemental pierce, 2 = bubble bounce
 	elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)
 	? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
@@ -626,21 +630,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 // ***************************************** //
 // Rings, coins, spheres, weapon panels, etc //
 // ***************************************** //
-		case MT_REDTEAMRING:
-			if (player->ctfteam != G_GetTeam(TEAM_RED))
-				return;
-			P_CollectRing(player, special);
-			break;
-		case MT_BLUETEAMRING:
-			if (player->ctfteam != G_GetTeam(TEAM_BLUE))
-				return;
-			P_CollectRing(player, special);
-			break;
 		case MT_RING:
 		case MT_FLINGRING:
 		case MT_COIN:
 		case MT_FLINGCOIN:
 		case MT_NIGHTSSTAR:
+		case MT_REDTEAMRING:
+		case MT_BLUETEAMRING:
 			P_CollectRing(player, special);
 			break;
 		case MT_BLUESPHERE:
@@ -3662,14 +3658,19 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 	if (target->flags2 & MF2_SKULLFLY)
 		target->momx = target->momy = target->momz = 0;
 
-	if (!force)
+	// Don't damage items meant for opposing teams
+	if (target->eflags & MFE_TEAMITEM && !force)
 	{
-		// Special case for team ring boxes
-		if (target->type == MT_RING_REDBOX && !(source->player->ctfteam == TEAM_RED))
-			return false;
-
-		if (target->type == MT_RING_BLUEBOX && !(source->player->ctfteam == TEAM_BLUE))
+		if (source && source->player)
+		{
+			if (source->player->ctfteam != target->extravalue1)
+				return false;
+		}
+		else
+		{
+			// If the originator of the attack is not a player, then the item cannot be damaged.
 			return false;
+		}
 	}
 
 	if (target->flags & (MF_ENEMY|MF_BOSS))
diff --git a/src/p_map.c b/src/p_map.c
index 528af655ba3c83fb52cf572c26a17f6175338d2e..6c5236e110701e4bc1b4724260bb1021178022c5 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->eflags & MFE_TEAMITEM) && tmthing->player->ctfteam != thing->extravalue1)
 		&& (!(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 4376f96c6e1554f31d6ece1f9d1d63069039a03c..c996031cde3c7f5f2e17317559e0c70eb090a70c 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -10559,6 +10559,8 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
 
 		case MT_REDTEAMRING:
 		case MT_BLUETEAMRING:
+		case MT_REDFLAG:
+		case MT_BLUEFLAG:
 
 		case MT_BOUNCERING:
 		case MT_AUTOMATICRING:
@@ -10619,9 +10621,7 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
 			return FRACUNIT;
 
 		default:
-			if (thing->eflags & MFE_TEAMFLAG)
-				return 2*FRACUNIT/3;
-			else if (thing->flags & (MF_ENEMY|MF_BOSS))
+			if (thing->flags & (MF_ENEMY|MF_BOSS))
 				return FRACUNIT;
 			else
 				return 0;
@@ -10917,10 +10917,18 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			 mobj->lastlook = mobj->extravalue2 = -1;
 			break;
 		case MT_REDTEAMRING:
-			mobj->color = G_GetTeamWeaponColor(G_GetTeam(TEAM_RED));
+		case MT_RING_REDBOX:
+			mobj->extravalue1 = G_GetTeam(TEAM_RED);
+			mobj->eflags |= MFE_TEAMITEM;
+			if (mobj->type == MT_REDTEAMRING)
+				mobj->color = G_GetTeamWeaponColor(mobj->extravalue1);
 			break;
 		case MT_BLUETEAMRING:
-			mobj->color = G_GetTeamWeaponColor(G_GetTeam(TEAM_BLUE));
+		case MT_RING_BLUEBOX:
+			mobj->extravalue1 = G_GetTeam(TEAM_BLUE);
+			mobj->eflags |= MFE_TEAMITEM;
+			if (mobj->type == MT_BLUETEAMRING)
+				mobj->color = G_GetTeamWeaponColor(mobj->extravalue1);
 			break;
 		case MT_RING:
 		case MT_COIN:
@@ -13283,6 +13291,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 		break;
 	}
 
+	// Team flags don't have MFE_TEAMITEM, because other players must be able to collide with them.
+	// If team flags had MFE_TEAMITEM, then players belonging to opposing teams would not be able to
+	// capture the flags.
 	if (mthing->type == THING_TYPE_CTF_TEAM_FLAG)
 		mobj->eflags |= MFE_TEAMFLAG;
 
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 11d03fdaed2b291da37b92045787def12b2e60d2..716d460c7b820f6b0a14ea1d4633f9f636efb611 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -225,8 +225,7 @@ typedef enum
 	// The mobj stands in a sector with water, and touches the surface
 	// this bit is set once and for all at the start of mobjthinker
 	MFE_TOUCHWATER			= 1<<2,
-	// The mobj stands in a sector with water, and his waist is BELOW the water surface
-	// (for player, allows swimming up/down)
+	// The mobj stands in a sector with water, and its waist is BELOW the water surface
 	MFE_UNDERWATER			= 1<<3,
 	// used for ramp sectors
 	MFE_JUSTSTEPPEDDOWN		= 1<<4,
@@ -251,10 +250,10 @@ typedef enum
 	MFE_FORCENOSUPER		= 1<<13,
 	// Makes an object use super sprites where they wouldn't have otherwise and vice-versa
 	MFE_REVERSESUPER		= MFE_FORCESUPER|MFE_FORCENOSUPER,
+	// Object is a team item - only players belonging to the same team as the item can collide with them
+	MFE_TEAMITEM            = 1<<14,
 	// Object is a team flag
-	MFE_TEAMFLAG            = 1<<14,
-
-	// free: 1<<15
+	MFE_TEAMFLAG            = 1<<15
 } mobjeflag_t;
 
 //