diff --git a/src/d_player.h b/src/d_player.h
index 77ad34dab..a7b19439d 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -181,25 +181,35 @@ typedef enum
 typedef enum
 {
 	SH_NONE = 0,
-	// Standard shields
+
+	// Shield flags
+	SH_PROTECTFIRE = 0x400,
+	SH_PROTECTWATER = 0x800,
+	SH_PROTECTELECTRICITY = 0x1000,
+
+	// Indivisible shields
+	SH_PITY = 1,
 	SH_JUMP,
-	SH_ATTRACT,
-	SH_ELEMENTAL,
 	SH_BOMB,
-	// Pity shield: the world's most basic shield ever, given to players who suck at Match
-	SH_PITY,
-	// Sonic 3 shields
-	SH_FLAMEAURA,
-	SH_BUBBLEWRAP,
-	SH_THUNDERCOIN,
-	// The fireflower used to be stackable with other shields. Not anymore.
 	SH_FIREFLOWER,
+
+	// normal shields that use flags
+	SH_ATTRACT = SH_PROTECTELECTRICITY,
+	SH_ELEMENTAL = SH_PROTECTFIRE|SH_PROTECTWATER,
+
+	// Sonic 3 shields
+	SH_FLAMEAURA = SH_PROTECTFIRE,
+	SH_BUBBLEWRAP = SH_PROTECTWATER,
+	SH_THUNDERCOIN = SH_JUMP|SH_PROTECTELECTRICITY,
+
 	// The force shield uses the lower 8 bits to count how many extra hits are left.
 	SH_FORCE = 0x100,
 	SH_FORCEHP = 0xFF, // to be used as a bitmask only
-	// The mushroom CAN stack with other shields.
+
+	// Mostly for use with Mario mode.
 	SH_MUSHROOM = 0x200,
-	SH_STACK = SH_MUSHROOM, //|SH_FIREFLOWER,
+
+	SH_STACK = SH_MUSHROOM, // second-layer shields
 	SH_NOSTACK = ~SH_STACK
 } shieldtype_t; // pw_shield
 
diff --git a/src/dehacked.c b/src/dehacked.c
index bd3f8455f..20dce51d4 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -7174,21 +7174,28 @@ struct {
 	{"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES},
 
 	// Shields
-	// These ones use the lower 8 bits
 	{"SH_NONE",SH_NONE},
+	// Shield flags
+	{"SH_PROTECTFIRE",SH_PROTECTFIRE},
+	{"SH_PROTECTWATER",SH_PROTECTWATER},
+	{"SH_PROTECTELECTRICITY",SH_PROTECTELECTRICITY},
+	// Indivisible shields
+	{"SH_PITY",SH_PITY},
 	{"SH_JUMP",SH_JUMP},
+	{"SH_BOMB",SH_BOMB},
+	{"SH_FIREFLOWER",SH_FIREFLOWER},
+	// normal shields that use flags
 	{"SH_ATTRACT",SH_ATTRACT},
 	{"SH_ELEMENTAL",SH_ELEMENTAL},
-	{"SH_BOMB",SH_BOMB},
+	// Sonic 3 shields
+	{"SH_FLAMEAURA",SH_FLAMEAURA},
 	{"SH_BUBBLEWRAP",SH_BUBBLEWRAP},
 	{"SH_THUNDERCOIN",SH_THUNDERCOIN},
-	{"SH_FLAMEAURA",SH_FLAMEAURA},
-	{"SH_PITY",SH_PITY},
-	{"SH_FIREFLOWER",SH_FIREFLOWER},
-	// These ones are special and use the upper bits
-	{"SH_FORCE",SH_FORCE}, // Lower bits are how many hits left, 0 is the last hit
-	{"SH_MUSHROOM", SH_MUSHROOM}, // Can stack with other shields
-	// Stack masks
+	// The force shield uses the lower 8 bits to count how many extra hits are left.
+	{"SH_FORCE",SH_FORCE},
+	{"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only
+	// Mostly for use with Mario mode.
+	{"SH_MUSHROOM", SH_MUSHROOM},
 	{"SH_STACK",SH_STACK},
 	{"SH_NOSTACK",SH_NOSTACK},
 
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 7ef87ac44..6345a89c4 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -741,7 +741,7 @@ static boolean P_LookForShield(mobj_t *actor)
 			(actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
 			continue;
 
-		if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
+		if ((player->powers[pw_shield] & SH_PROTECTELECTRICITY)
 			&& (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale)))
 		{
 			P_SetTarget(&actor->tracer, player->mo);
@@ -3817,7 +3817,7 @@ void A_AttractChase(mobj_t *actor)
 
 	// Turn flingrings back into regular rings if attracted.
 	if (actor->tracer && actor->tracer->player
-		&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
+		&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRICITY) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
 	{
 		mobj_t *newring;
 		newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
@@ -4022,7 +4022,7 @@ void A_ThrownRing(mobj_t *actor)
 		// A non-homing ring getting attracted by a
 		// magnetic player. If he gets too far away, make
 		// sure to stop the attraction!
-		if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
+		if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRICITY)
 		    && P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x,
 		    actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale)))
 		{
@@ -4030,7 +4030,7 @@ void A_ThrownRing(mobj_t *actor)
 		}
 
 		if (actor->tracer && (actor->tracer->health)
-			&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)// Already found someone to follow.
+			&& (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRICITY))// Already found someone to follow.
 		{
 			const INT32 temp = actor->threshold;
 			actor->threshold = 32000;
@@ -4098,7 +4098,7 @@ void A_ThrownRing(mobj_t *actor)
 		if (!P_CheckSight(actor, player->mo))
 			continue; // out of sight
 
-		if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
+		if ((player->powers[pw_shield] & SH_PROTECTELECTRICITY)
 			&& dist < FixedMul(RING_DIST/4, player->mo->scale))
 			P_SetTarget(&actor->tracer, player->mo);
 		return;
diff --git a/src/p_inter.c b/src/p_inter.c
index 0b2262ab7..c5938c90e 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -1459,7 +1459,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			return;
 
 		case MT_EXTRALARGEBUBBLE:
-			if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
+			if (player->powers[pw_shield] & SH_PROTECTWATER)
 				return;
 			if (maptol & TOL_NIGHTS)
 				return;
@@ -3022,28 +3022,23 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 			if (!(target->player->pflags & (PF_NIGHTSMODE|PF_NIGHTSFALL)) && (maptol & TOL_NIGHTS))
 				return false;
 
-#define shieldtype (player->powers[pw_shield] & SH_NOSTACK)
 			switch (damagetype)
 			{
 				case DMG_WATER:
-					if (shieldtype == SH_BUBBLEWRAP
-					|| shieldtype == SH_ELEMENTAL)
+					if (player->powers[pw_shield] & SH_PROTECTWATER)
 						return false; // Invincible to water damage
 					break;
 				case DMG_FIRE:
-					if (shieldtype == SH_FLAMEAURA
-					|| shieldtype == SH_ELEMENTAL)
+					if (player->powers[pw_shield] & SH_PROTECTFIRE)
 						return false; // Invincible to fire damage
 					break;
 				case DMG_ELECTRIC:
-					if (shieldtype == SH_ATTRACT
-					|| shieldtype == SH_THUNDERCOIN)
+					if (player->powers[pw_shield] & SH_PROTECTELECTRICITY)
 						return false; // Invincible to electric damage
 					break;
 				default:
 					break;
 			}
-#undef shieldtype
 		}
 
 		if (player->pflags & PF_NIGHTSMODE) // NiGHTS damage handling
@@ -3067,7 +3062,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 
 		if (!force && inflictor && inflictor->flags & MF_FIRE)
 		{
-			if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
+			if (player->powers[pw_shield] & SH_PROTECTFIRE)
 				return false; // Invincible to fire objects
 
 			if (G_PlatformGametype() && inflictor && source && source->player)
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 2cd6b7d77..d87e3cc20 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -3619,15 +3619,20 @@ void P_MobjCheckWater(mobj_t *mobj)
 	{
 		if (!((p->powers[pw_super]) || (p->powers[pw_invulnerability])))
 		{
-			if ((p->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)
-			{ // Water removes attract shield.
+			if (p->powers[pw_shield] & SH_PROTECTELECTRICITY)
+			{ // Water removes electric shields...
 				p->powers[pw_shield] = p->powers[pw_shield] & SH_STACK;
 				P_FlashPal(p, PAL_WHITE, 1);
 			}
+			else if ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER))
+			{ // ...and fire-only shields.
+				p->powers[pw_shield] = p->powers[pw_shield] & SH_STACK;
+				P_FlashPal(p, PAL_NUKE, 1);
+			}
 		}
 
 		// Drown timer setting
-		if ((p->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL // Has elemental
+		if ((p->powers[pw_shield] & SH_PROTECTWATER) // Has water protection
 		 || (p->exiting) // Or exiting
 		 || (maptol & TOL_NIGHTS) // Or in NiGHTS mode
 		 || (mariomode)) // Or in Mario mode...
diff --git a/src/p_spec.c b/src/p_spec.c
index ed2ff055c..0119664aa 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3562,7 +3562,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
 				P_PlayerFlagBurst(player, false);
 			break;
 		case 12: // Space Countdown
-			if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL && !player->powers[pw_spacetime])
+			if (!(player->powers[pw_shield] & SH_PROTECTWATER) && !player->powers[pw_spacetime])
 				player->powers[pw_spacetime] = spacetimetics + 1;
 			break;
 		case 13: // Ramp Sector (Increase step-up/down)
diff --git a/src/p_user.c b/src/p_user.c
index df28806b6..8ceef8d6e 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -2229,7 +2229,7 @@ static void P_DoBubbleBreath(player_t *player)
 	fixed_t z = player->mo->z;
 	mobj_t *bubble = NULL;
 
-	if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && !(player->pflags & PF_NIGHTSMODE)) || player->spectator)
+	if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_PROTECTWATER) && !(player->pflags & PF_NIGHTSMODE)) || player->spectator)
 		return;
 
 	if (player->charflags & SF_MACHINE)
@@ -9242,7 +9242,7 @@ void P_PlayerThink(player_t *player)
 	if (player->powers[pw_tailsfly] && player->powers[pw_tailsfly] < UINT16_MAX && player->charability != CA_SWIM && !(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) // tails fly counter
 		player->powers[pw_tailsfly]--;
 
-	if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL))
+	if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER)))
 	{
 		if (player->powers[pw_underwater] <= 12*TICRATE+1)
 			P_RestoreMusic(player); //incase they were about to drown
@@ -9252,7 +9252,7 @@ void P_PlayerThink(player_t *player)
 	else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
 		player->powers[pw_underwater]--;
 
-	if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL))
+	if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER)))
 		player->powers[pw_spacetime] = 0;
 	else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
 		player->powers[pw_spacetime]--;