diff --git a/src/d_player.h b/src/d_player.h
index 79f2a3b924ac5781f9312a7f5523cbe9d4deef7e..2e7afed882ccf4b1ca1966b7439785aadf4a993a 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -52,6 +52,8 @@ typedef enum
 	SF_NOSUPERSPRITES   = 1<<16, // Don't use super sprites while super
 	SF_NOSUPERJUMPBOOST = 1<<17, // Disable the jump boost given while super (i.e. Knuckles)
 	SF_CANBUSTWALLS     = 1<<18, // Can naturally bust walls on contact? (i.e. Knuckles)
+	SF_NOSHIELDABILITY  = 1<<19, // Disable shield abilities
+
 	// free up to and including 1<<31
 } skinflags_t;
 
diff --git a/src/deh_tables.c b/src/deh_tables.c
index 2d79ec5638342a0b4e24506ae5d403282b0e88c4..3039bf7dec22dfecc241bd253ef5175d83aee026 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -5022,6 +5022,7 @@ struct int_const_s const INT_CONST[] = {
 	{"SF_NOSUPERSPRITES",SF_NOSUPERSPRITES},
 	{"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST},
 	{"SF_CANBUSTWALLS",SF_CANBUSTWALLS},
+	{"SF_NOSHIELDABILITY",SF_NOSHIELDABILITY},
 
 	// Dashmode constants
 	{"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD},
diff --git a/src/p_user.c b/src/p_user.c
index bc40e0ebe5df9751c88dbe2e7c9b6542cfee08a3..a70dceb8b12ed25fbcc5777544455013f9e0c488 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -5024,7 +5024,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
 	if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN)
 		&& ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted
 	{
-		if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)
+		if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT && !(player->charflags & SF_NOSHIELDABILITY))
 		{
 			if ((lockonshield = P_LookForEnemies(player, false, false)))
 			{
@@ -5047,7 +5047,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
 				}
 			}
 		}
-		if (cmd->buttons & BT_SPIN && !LUAh_ShieldSpecial(player)) // Spin button effects
+		if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SPIN && !LUAh_ShieldSpecial(player))) // Spin button effects
 		{
 			// Force stop
 			if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
@@ -5495,7 +5495,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 						break;
 				}
 		}
-		else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super])
+		else if ((!(player->charflags & SF_NOSHIELDABILITY)) && ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super] && !LUAh_ShieldSpecial(player)))
 			P_DoJumpShield(player);
 	}
 
diff --git a/src/r_skins.c b/src/r_skins.c
index 522d9236a09fede50991504c1a24c56d32814a87..6f150f234ed9908f9c58bd42ecbe65ac5e5a534a 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -514,6 +514,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
 	GETFLAG(NOSUPERSPRITES)
 	GETFLAG(NOSUPERJUMPBOOST)
 	GETFLAG(CANBUSTWALLS)
+	GETFLAG(NOSHIELDABILITY)
 #undef GETFLAG
 
 	else // let's check if it's a sound, otherwise error out