diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 919d35b53fafbd5b2e73dd41b0b8719ceffdf7d8..68deb8b3441a1040a148f0cca9991955ca08e731 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -1313,8 +1313,9 @@ static void SendNameAndColor(void)
 	cv_skin.value = R_SkinAvailable(cv_skin.string);
 	if ((cv_skin.value < 0) || !R_SkinUsable(consoleplayer, cv_skin.value))
 	{
-		CV_StealthSet(&cv_skin, DEFAULTSKIN);
-		cv_skin.value = 0;
+		INT32 defaultSkinNum = GetPlayerDefaultSkin(consoleplayer);
+		CV_StealthSet(&cv_skin, skins[defaultSkinNum].name);
+		cv_skin.value = defaultSkinNum;
 	}
 
 	// Finally write out the complete packet and send it off.
@@ -1475,7 +1476,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 	if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer]))
 	{
 		boolean kick = false;
-		INT32 s;
+		UINT32 unlockShift = 0;
+		UINT32 i;
 
 		// team colors
 		if (G_GametypeHasTeams())
@@ -1491,12 +1493,29 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 			kick = true;
 
 		// availabilities
-		for (s = 0; s < MAXSKINS; s++)
+		for (i = 0; i < MAXUNLOCKABLES; i++)
 		{
-			if (!skins[s].availability && (p->availabilities & (1 << s)))
+			if (unlockables[i].type != SECRET_SKIN)
+			{
+				continue;
+			}
+
+			unlockShift++;
+		}
+
+		// If they set an invalid bit to true, then likely a modified client
+		if (unlockShift < 32) // 32 is the max the data type allows
+		{
+			UINT32 illegalMask = UINT32_MAX;
+
+			for (i = 0; i < unlockShift; i++)
+			{
+				illegalMask &= ~(1 << i);
+			}
+			
+			if ((p->availabilities & illegalMask) != 0)
 			{
 				kick = true;
-				break;
 			}
 		}
 
diff --git a/src/deh_soc.c b/src/deh_soc.c
index c384d71b72c7cff8a4af398ecc46a8a90e8e3003..3a611f3ba18daaacd3c9f5154505176f3a1ad4cd 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -127,6 +127,33 @@ static float searchfvalue(const char *s)
 #endif
 
 // These are for clearing all of various things
+void clear_emblems(void)
+{
+	INT32 i;
+
+	for (i = 0; i < MAXEMBLEMS; ++i)
+	{
+		Z_Free(emblemlocations[i].stringVar);
+		emblemlocations[i].stringVar = NULL;
+	}
+
+	memset(&emblemlocations, 0, sizeof(emblemlocations));
+	numemblems = 0;
+}
+
+void clear_unlockables(void)
+{
+	INT32 i;
+
+	for (i = 0; i < MAXUNLOCKABLES; ++i)
+	{
+		Z_Free(unlockables[i].stringVar);
+		unlockables[i].stringVar = NULL;
+	}
+
+	memset(&unlockables, 0, sizeof(unlockables));
+}
+
 void clear_conditionsets(void)
 {
 	UINT8 i;
@@ -2978,7 +3005,12 @@ void reademblemdata(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "COLOR"))
 				emblemlocations[num-1].color = get_number(word2);
 			else if (fastcmp(word, "VAR"))
+			{
+				Z_Free(emblemlocations[num-1].stringVar);
+				emblemlocations[num-1].stringVar = Z_StrDup(word2);
+
 				emblemlocations[num-1].var = get_number(word2);
+			}
 			else
 				deh_warning("Emblem %d: unknown word '%s'", num, word);
 		}
@@ -3180,11 +3212,16 @@ void readunlockable(MYFILE *f, INT32 num)
 						unlockables[num].type = SECRET_WARP;
 					else if (fastcmp(word2, "SOUNDTEST"))
 						unlockables[num].type = SECRET_SOUNDTEST;
+					else if (fastcmp(word2, "SKIN"))
+						unlockables[num].type = SECRET_SKIN;
 					else
 						unlockables[num].type = (INT16)i;
 				}
 				else if (fastcmp(word, "VAR"))
 				{
+					Z_Free(unlockables[num].stringVar);
+					unlockables[num].stringVar = Z_StrDup(word2);
+
 					// Support using the actual map name,
 					// i.e., Level AB, Level FZ, etc.
 
diff --git a/src/deh_soc.h b/src/deh_soc.h
index fa043b0965fffa4be85a953a06cfd3f4f96d160c..28e3c9512336b91700a648f35f0fe3e922356d69 100644
--- a/src/deh_soc.h
+++ b/src/deh_soc.h
@@ -81,6 +81,8 @@ void readskincolor(MYFILE *f, INT32 num);
 void readthing(MYFILE *f, INT32 num);
 void readfreeslots(MYFILE *f);
 void readPlayer(MYFILE *f, INT32 num);
+void clear_emblems(void);
+void clear_unlockables(void);
 void clear_levels(void);
 void clear_conditionsets(void);
 #endif
diff --git a/src/dehacked.c b/src/dehacked.c
index 91715dfa4ce10505e25a1b8d93f5ed6ffecc946e..da8c81c351f845a98b59e3cd494e8f29c2a6b7d1 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -547,13 +547,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
 					}
 
 					if (clearall || fastcmp(word2, "UNLOCKABLES"))
-						memset(&unlockables, 0, sizeof(unlockables));
+						clear_unlockables();
 
 					if (clearall || fastcmp(word2, "EMBLEMS"))
-					{
-						memset(&emblemlocations, 0, sizeof(emblemlocations));
-						numemblems = 0;
-					}
+						clear_emblems();
 
 					if (clearall || fastcmp(word2, "EXTRAEMBLEMS"))
 					{
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index 3370f8f728996059a73e46a9db7ccf4d2b0fcc2c..e66a379e9d13549610607b2aad173b29c184494c 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -53,7 +53,6 @@ enum skin {
 	skin_contspeed,
 	skin_contangle,
 	skin_soundsid,
-	skin_availability,
 	skin_sprites
 };
 static const char *const skin_opt[] = {
@@ -91,7 +90,6 @@ static const char *const skin_opt[] = {
 	"contspeed",
 	"contangle",
 	"soundsid",
-	"availability",
 	"sprites",
 	NULL};
 
@@ -209,9 +207,6 @@ static int skin_get(lua_State *L)
 	case skin_soundsid:
 		LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID);
 		break;
-	case skin_availability:
-		lua_pushinteger(L, skin->availability);
-		break;
 	case skin_sprites:
 		LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
 		break;
diff --git a/src/m_cond.c b/src/m_cond.c
index a54238ab2b5f47790047a8fffb9d305177f03934..85d732a48d3d7dea1a8c4289a8acaf24ce859e64 100644
--- a/src/m_cond.c
+++ b/src/m_cond.c
@@ -496,6 +496,64 @@ UINT8 M_GotHighEnoughRings(INT32 trings)
 	return false;
 }
 
+// Gets the skin number for a SECRET_SKIN unlockable.
+INT32 M_UnlockableSkinNum(unlockable_t *unlock)
+{
+	if (unlock->type != SECRET_SKIN)
+	{
+		// This isn't a skin unlockable...
+		return -1;
+	}
+
+	if (unlock->stringVar && strcmp(unlock->stringVar, ""))
+	{
+		// Get the skin from the string.
+		INT32 skinnum = R_SkinAvailable(unlock->stringVar);
+		if (skinnum != -1)
+		{
+			return skinnum;
+		}
+	}
+
+	if (unlock->variable >= 0 && unlock->variable < numskins)
+	{
+		// Use the number directly.
+		return unlock->variable;
+	}
+
+	// Invalid skin unlockable.
+	return -1;
+}
+
+// Gets the skin number for a ET_SKIN emblem.
+INT32 M_EmblemSkinNum(emblem_t *emblem)
+{
+	if (emblem->type != ET_SKIN)
+	{
+		// This isn't a skin emblem...
+		return -1;
+	}
+
+	if (emblem->stringVar && strcmp(emblem->stringVar, ""))
+	{
+		// Get the skin from the string.
+		INT32 skinnum = R_SkinAvailable(emblem->stringVar);
+		if (skinnum != -1)
+		{
+			return skinnum;
+		}
+	}
+
+	if (emblem->var >= 0 && emblem->var < numskins)
+	{
+		// Use the number directly.
+		return emblem->var;
+	}
+
+	// Invalid skin emblem.
+	return -1;
+}
+
 // ----------------
 // Misc Emblem shit
 // ----------------
diff --git a/src/m_cond.h b/src/m_cond.h
index 690b6fb2641f503f40271eba2e1765e6833cddfa..b2c6d65e6046b030a44721568ae429baece6909a 100644
--- a/src/m_cond.h
+++ b/src/m_cond.h
@@ -92,6 +92,7 @@ typedef struct
 	UINT8 sprite;    ///< emblem sprite to use, 0 - 25
 	UINT16 color;    ///< skincolor to use
 	INT32 var;       ///< If needed, specifies information on the target amount to achieve (or target skin)
+	char *stringVar; ///< String version
 	char hint[110];  ///< Hint for emblem hints menu
 	UINT8 collected; ///< Do you have this emblem?
 } emblem_t;
@@ -116,6 +117,7 @@ typedef struct
 	UINT8 showconditionset;
 	INT16 type;
 	INT16 variable;
+	char *stringVar;
 	UINT8 nocecho;
 	UINT8 nochecklist;
 	UINT8 unlocked;
@@ -132,6 +134,7 @@ typedef struct
 #define SECRET_WARP			 2 // Selectable warp
 #define SECRET_SOUNDTEST	 3 // Sound Test
 #define SECRET_CREDITS		 4 // Enables Credits
+#define SECRET_SKIN			 5 // Unlocks a skin
 
 // If you have more secrets than these variables allow in your game,
 // you seriously need to get a life.
@@ -185,4 +188,7 @@ UINT8 M_GotHighEnoughScore(INT32 tscore);
 UINT8 M_GotLowEnoughTime(INT32 tictime);
 UINT8 M_GotHighEnoughRings(INT32 trings);
 
+INT32 M_UnlockableSkinNum(unlockable_t *unlock);
+INT32 M_EmblemSkinNum(emblem_t *emblem);
+
 #define M_Achieved(a) ((a) >= MAXCONDITIONSETS || conditionSets[a].achieved)
diff --git a/src/m_menu.c b/src/m_menu.c
index 407225526bed7a8678e06760e55ea777206498bd..c9f80b69dc217529f2e43ee533029e0ca8d3c0e8 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -8963,7 +8963,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
 
 static UINT8 M_SetupChoosePlayerDirect(INT32 choice)
 {
-	INT32 skinnum;
+	INT32 skinnum, botskinnum;
 	UINT8 i;
 	UINT8 firstvalid = 255, lastvalid = 255;
 	boolean allowed = false;
@@ -8995,6 +8995,13 @@ static UINT8 M_SetupChoosePlayerDirect(INT32 choice)
 				skinnum = description[i].skinnum[0];
 				if ((skinnum != -1) && (R_SkinUsable(-1, skinnum)))
 				{
+					botskinnum = description[i].skinnum[1];
+					if ((botskinnum != -1) && (!R_SkinUsable(-1, botskinnum)))
+					{
+						// Bot skin isn't unlocked
+						continue;
+					}
+
 					// Handling order.
 					if (firstvalid == 255)
 						firstvalid = i;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index ca88b783188dc9b7f84987110e8d37aa371d9ba8..3b13fe295aa0a2cbd63bdd332efed9b40d4e8257 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -25,6 +25,7 @@
 #include "i_video.h"
 #include "z_zone.h"
 #include "lua_hook.h"
+#include "m_cond.h" // SECRET_SKIN
 
 #ifdef HW3SOUND
 #include "hardware/hw3sound.h"
@@ -5101,6 +5102,33 @@ void A_SignSpin(mobj_t *actor)
 	}
 }
 
+static boolean SignSkinCheck(player_t *player, INT32 num)
+{
+	INT32 i;
+
+	if (player != NULL)
+	{
+		// Use player's availabilities
+		return R_SkinUsable(player - players, num);
+	}
+
+	// Player invalid, only show characters that are unlocked from the start.
+	for (i = 0; i < MAXUNLOCKABLES; i++)
+	{
+		if (unlockables[i].type == SECRET_SKIN)
+		{
+			INT32 lockedSkin = M_UnlockableSkinNum(&unlockables[i]);
+
+			if (lockedSkin == num)
+			{
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
 // Function: A_SignPlayer
 //
 // Description: Changes the state of a level end sign to reflect the player that hit it.
@@ -5161,23 +5189,21 @@ void A_SignPlayer(mobj_t *actor)
 		// I turned this function into a fucking mess. I'm so sorry. -Lach
 		if (locvar1 == -2) // random skin
 		{
-#define skincheck(num) (player ? !R_SkinUsable(player-players, num) : skins[num].availability > 0)
 			player_t *player = actor->target ? actor->target->player : NULL;
 			UINT8 skinnum;
 			UINT8 skincount = 0;
 			for (skinnum = 0; skinnum < numskins; skinnum++)
-				if (!skincheck(skinnum))
+				if (SignSkinCheck(player, skinnum))
 					skincount++;
 			skinnum = P_RandomKey(skincount);
 			for (skincount = 0; skincount < numskins; skincount++)
 			{
 				if (skincount > skinnum)
 					break;
-				if (skincheck(skincount))
+				if (!SignSkinCheck(player, skincount))
 					skinnum++;
 			}
 			skin = &skins[skinnum];
-#undef skincheck
 		}
 		else // specific skin
 			skin = &skins[locvar1];
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 964015d4654cb0d3f512d87a597d0d737135ce1a..917228d2bc2bf08ca40b29d71a1920b4bf9c7306 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -11962,6 +11962,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
 	INT32 j;
 	emblem_t* emblem = M_GetLevelEmblems(gamemap);
 	skincolornum_t emcolor;
+	boolean validEmblem = true;
 
 	while (emblem)
 	{
@@ -11986,8 +11987,19 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
 	emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting
 	mobj->color = (UINT16)emcolor;
 
-	if (emblemlocations[j].collected
-		|| (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin))
+	validEmblem = !emblemlocations[j].collected;
+
+	if (emblemlocations[j].type == ET_SKIN)
+	{
+		INT32 skinnum = M_EmblemSkinNum(&emblemlocations[j]);
+
+		if (players[0].skin != skinnum)
+		{
+			validEmblem = false;
+		}
+	}
+
+	if (validEmblem == false)
 	{
 		P_UnsetThingPosition(mobj);
 		mobj->flags |= MF_NOCLIP;
diff --git a/src/p_setup.c b/src/p_setup.c
index 16c0802486daccf7eda78d63c8e9d58f68ccc88b..4164c397276d57d95c1ec25d46b75e6a788a2056 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -4576,8 +4576,8 @@ boolean P_AddWadFile(const char *wadfilename)
 	//
 	// look for skins
 	//
-	R_AddSkins(wadnum); // faB: wadfile index in wadfiles[]
-	R_PatchSkins(wadnum); // toast: PATCH PATCH
+	R_AddSkins(wadnum, false); // faB: wadfile index in wadfiles[]
+	R_PatchSkins(wadnum, false); // toast: PATCH PATCH
 	ST_ReloadSkinFaceGraphics();
 
 	//
diff --git a/src/r_skins.c b/src/r_skins.c
index 73d983a00c12443667379851fbbdf5b4e42df0c3..b7eb24345d469682cc70f4e251a6101c4688e60a 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -148,8 +148,6 @@ static void Sk_SetDefaultValue(skin_t *skin)
 	skin->contspeed = 17;
 	skin->contangle = 0;
 
-	skin->availability = 0;
-
 	for (i = 0; i < sfx_skinsoundslot0; i++)
 		if (S_sfx[i].skinsound != -1)
 			skin->soundsid[S_sfx[i].skinsound] = i;
@@ -176,14 +174,34 @@ void R_InitSkins(void)
 
 UINT32 R_GetSkinAvailabilities(void)
 {
-	INT32 s;
 	UINT32 response = 0;
+	UINT32 unlockShift = 0;
+	INT32 i;
 
-	for (s = 0; s < MAXSKINS; s++)
+	for (i = 0; i < MAXUNLOCKABLES; i++)
 	{
-		if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked)
-			response |= (1 << s);
+		if (unlockables[i].type != SECRET_SKIN)
+		{
+			continue;
+		}
+
+		if (unlockShift >= 32)
+		{
+			// This crash is impossible to trigger as is,
+			// but it could happen if MAXUNLOCKABLES is ever made higher than 32,
+			// and someone makes a mod that has 33+ unlockable characters. :V
+			I_Error("Too many unlockable characters\n");
+			return 0;
+		}
+
+		if (unlockables[i].unlocked)
+		{
+			response |= (1 << unlockShift);
+		}
+
+		unlockShift++;
 	}
+
 	return response;
 }
 
@@ -191,14 +209,78 @@ UINT32 R_GetSkinAvailabilities(void)
 // warning don't use with an invalid skinnum other than -1 which always returns true
 boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
 {
-	return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
-		|| (!skins[skinnum].availability)
-		|| (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
-		|| (modeattacking) // If you have someone else's run you might as well take a look
-		|| (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1.
-		|| (netgame && (cv_forceskin.value == skinnum)) // Force 2.
-		|| (metalrecording && skinnum == 5) // Force 3.
-		);
+	INT32 unlockID = -1;
+	UINT32 unlockShift = 0;
+	INT32 i;
+
+	if (skinnum == -1)
+	{
+		// Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
+		return true;
+	}
+
+	if (modeattacking)
+	{
+		// If you have someone else's run you might as well take a look
+		return true;
+	}
+
+	if (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum))
+	{
+		// Force 1.
+		return true;
+	}
+
+	if (netgame && (cv_forceskin.value == skinnum))
+	{
+		// Force 2.
+		return true;
+	}
+	
+	if (metalrecording && skinnum == 5)
+	{
+		// Force 3.
+		return true;
+	}
+
+	// We will now check if this skin is supposed to be locked or not.
+
+	for (i = 0; i < MAXUNLOCKABLES; i++)
+	{
+		INT32 unlockSkin = -1;
+
+		if (unlockables[i].type != SECRET_SKIN)
+		{
+			continue;
+		}
+
+		unlockSkin = M_UnlockableSkinNum(&unlockables[i]);
+
+		if (unlockSkin == skinnum)
+		{
+			unlockID = i;
+			break;
+		}
+
+		unlockShift++;
+	}
+
+	if (unlockID == -1)
+	{
+		// This skin isn't locked at all, we're good.
+		return true;
+	}
+
+	if ((netgame || multiplayer) && playernum != -1)
+	{
+		// We want to check per-player unlockables.
+		return (players[playernum].availabilities & (1 << unlockShift));
+	}
+	else
+	{
+		// We want to check our global unlockables.
+		return (unlockables[unlockID].unlocked);
+	}
 }
 
 // returns true if the skin name is found (loaded from pwad)
@@ -295,6 +377,24 @@ static void SetSkin(player_t *player, INT32 skinnum)
 	}
 }
 
+// Gets the player to the first usuable skin in the game.
+// (If your mod locked them all, then you kinda stupid)
+INT32 GetPlayerDefaultSkin(INT32 playernum)
+{
+	INT32 i;
+
+	for (i = 0; i < numskins; i++)
+	{
+		if (R_SkinUsable(playernum, i))
+		{
+			return i;
+		}
+	}
+
+	I_Error("All characters are locked!");
+	return 0;
+}
+
 // network code calls this when a 'skin change' is received
 void SetPlayerSkin(INT32 playernum, const char *skinname)
 {
@@ -309,10 +409,10 @@ void SetPlayerSkin(INT32 playernum, const char *skinname)
 
 	if (P_IsLocalPlayer(player))
 		CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname);
-	else if(server || IsPlayerAdmin(consoleplayer))
+	else if (server || IsPlayerAdmin(consoleplayer))
 		CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname);
 
-	SetSkin(player, 0);
+	SetSkin(player, GetPlayerDefaultSkin(playernum));
 }
 
 // Same as SetPlayerSkin, but uses the skin #.
@@ -329,10 +429,10 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 
 	if (P_IsLocalPlayer(player))
 		CONS_Alert(CONS_WARNING, M_GetText("Requested skin %d not found\n"), skinnum);
-	else if(server || IsPlayerAdmin(consoleplayer))
+	else if (server || IsPlayerAdmin(consoleplayer))
 		CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum);
 
-	SetSkin(player, 0); // not found put the sonic skin
+	SetSkin(player, GetPlayerDefaultSkin(playernum));
 }
 
 //
@@ -566,7 +666,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
 //
 // Find skin sprites, sounds & optional status bar face, & add them
 //
-void R_AddSkins(UINT16 wadnum)
+void R_AddSkins(UINT16 wadnum, boolean mainfile)
 {
 	UINT16 lump, lastlump = 0;
 	char *buf;
@@ -681,12 +781,6 @@ void R_AddSkins(UINT16 wadnum)
 				if (!realname)
 					STRBUFCPY(skin->realname, skin->hudname);
 			}
-			else if (!stricmp(stoken, "availability"))
-			{
-				skin->availability = atoi(value);
-				if (skin->availability >= MAXUNLOCKABLES)
-					skin->availability = 0;
-			}
 			else if (!R_ProcessPatchableFields(skin, stoken, value))
 				CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
 
@@ -701,7 +795,7 @@ next_token:
 
 		R_FlushTranslationColormapCache();
 
-		if (!skin->availability) // Safe to print...
+		if (mainfile == false)
 			CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name);
 #ifdef SKINVALUES
 		skin_cons_t[numskins].value = numskins;
@@ -721,7 +815,7 @@ next_token:
 //
 // Patch skin sprites
 //
-void R_PatchSkins(UINT16 wadnum)
+void R_PatchSkins(UINT16 wadnum, boolean mainfile)
 {
 	UINT16 lump, lastlump = 0;
 	char *buf;
@@ -834,7 +928,7 @@ next_token:
 
 		R_FlushTranslationColormapCache();
 
-		if (!skin->availability) // Safe to print...
+		if (mainfile == false)
 			CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name);
 	}
 	return;
diff --git a/src/r_skins.h b/src/r_skins.h
index 3f67bfdabbf04e2277fc20ecd6707c61e4054479..a38997f4dd623aad8dc7cdf21aff1283f8c8aa93 100644
--- a/src/r_skins.h
+++ b/src/r_skins.h
@@ -80,8 +80,6 @@ typedef struct
 	// contains super versions too
 	spritedef_t sprites[NUMPLAYERSPRITES*2];
 	spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
-
-	UINT8 availability; // lock?
 } skin_t;
 
 /// Externs
@@ -91,13 +89,14 @@ extern skin_t skins[MAXSKINS];
 /// Function prototypes
 void R_InitSkins(void);
 
+INT32 GetPlayerDefaultSkin(INT32 playernum);
 void SetPlayerSkin(INT32 playernum,const char *skinname);
 void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002
 boolean R_SkinUsable(INT32 playernum, INT32 skinnum);
 UINT32 R_GetSkinAvailabilities(void);
 INT32 R_SkinAvailable(const char *name);
-void R_PatchSkins(UINT16 wadnum);
-void R_AddSkins(UINT16 wadnum);
+void R_AddSkins(UINT16 wadnum, boolean mainfile);
+void R_PatchSkins(UINT16 wadnum, boolean mainfile);
 
 UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
 
diff --git a/src/r_things.c b/src/r_things.c
index 5c0e5fda95b2052e376f16279abae72ba29581f1..3b61e48625bfa8987c6dc3d2894faaa56bdd4942 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -547,8 +547,8 @@ void R_InitSprites(void)
 	R_InitSkins();
 	for (i = 0; i < numwadfiles; i++)
 	{
-		R_AddSkins((UINT16)i);
-		R_PatchSkins((UINT16)i);
+		R_AddSkins((UINT16)i, true);
+		R_PatchSkins((UINT16)i, true);
 		R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps);
 	}
 	ST_ReloadSkinFaceGraphics();