diff --git a/src/d_main.c b/src/d_main.c
index 904ab3bf13046f37984752acf4ac34cccc648d8b..9fcf349dbbe26df9dbad1af09557334b4c060953 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1151,6 +1151,10 @@ void D_SRB2Main(void)
 
 	if (M_CheckParm("-password") && M_IsNextParm())
 		D_SetPassword(M_GetNextParm());
+	
+	// player setup menu colors must be initialized before
+	// any wad file is added, as they may contain colors themselves
+	M_InitPlayerSetupColors();
 
 	// add any files specified on the command line with -file wadfile
 	// to the wad list
diff --git a/src/dehacked.c b/src/dehacked.c
index 4d12587ddee5baf0478427a4502b7e5941bd191a..e2627d2417ca47e22f8a4b7b0ec7eb9a4a104f07 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -4629,11 +4629,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
 				{
 					if (i == 0 && word2[0] != '0') // If word2 isn't a number
 						i = get_skincolor(word2); // find a skincolor by name
-					if (i < numskincolors && i > 0)
+					if (i < numskincolors && i >= (INT32)SKINCOLOR_FIRSTFREESLOT)
 						readskincolor(f, i);
 					else
 					{
-						deh_warning("Skincolor %d out of range (1 - %d)", i, numskincolors-1);
+						deh_warning("Skincolor %d out of range (%d - %d)", i, SKINCOLOR_FIRSTFREESLOT, numskincolors-1);
 						ignorelines(f);
 					}
 				}
diff --git a/src/info.c b/src/info.c
index d592da8b88194d733cc4c7a7a1e3534572cfa55f..e8e5bc89b36795a4a9a2956e5eabd4b01fa41a2a 100644
--- a/src/info.c
+++ b/src/info.c
@@ -21773,7 +21773,6 @@ void P_PatchInfoTables(void)
 		skincolors[i].accessible = false;
 		skincolors[i].name[0] = '\0';
 	}
-	numskincolors = SKINCOLOR_FIRSTFREESLOT;
 	for (i = MT_FIRSTFREESLOT; i <= MT_LASTFREESLOT; i++)
 		mobjinfo[i].doomednum = -1;
 }
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index fd9cd319f11dfee528a6034675a764fb59843254..372b746d4f5f471dad77c0bcdfc691d110db9511 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -1516,8 +1516,8 @@ static int lib_setSkinColor(lua_State *L)
 	lua_remove(L, 1); // don't care about skincolors[] userdata.
 	{
 		cnum = (UINT8)luaL_checkinteger(L, 1);
-		if (!cnum || cnum >= numskincolors)
-			return luaL_error(L, "skincolors[] index %d out of range (1 - %d)", cnum, numskincolors-1);
+		if (cnum < SKINCOLOR_FIRSTFREESLOT || cnum >= numskincolors)
+			return luaL_error(L, "skincolors[] index %d out of range (%d - %d)", cnum, SKINCOLOR_FIRSTFREESLOT, numskincolors-1);
 		info = &skincolors[cnum]; // get the skincolor to assign to.
 	}
 	luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
@@ -1615,8 +1615,8 @@ static int skincolor_set(lua_State *L)
 	I_Assert(info != NULL);
 	I_Assert(info >= skincolors);
 
-	if (info-skincolors >= numskincolors)
-		return luaL_error(L, "skincolors[] index %d does not exist", info-skincolors);
+	if (info-skincolors < SKINCOLOR_FIRSTFREESLOT || info-skincolors >= numskincolors)
+		return luaL_error(L, "skincolors[] index %d out of range (%d - %d)", info-skincolors, SKINCOLOR_FIRSTFREESLOT, numskincolors-1);
 
 	if (fastcmp(field,"name")) {
 		const char* n = luaL_checkstring(L, 3);
@@ -1640,13 +1640,9 @@ static int skincolor_set(lua_State *L)
 		info->invshade = (UINT8)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"chatcolor"))
 		info->chatcolor = (UINT16)luaL_checkinteger(L, 3);
-	else if (fastcmp(field,"accessible")) {
-		boolean v = lua_isboolean(L,3) ? lua_toboolean(L, 3) : true;
-		if (info-skincolors < FIRSTSUPERCOLOR && v != info->accessible)
-			return luaL_error(L, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", info-skincolors);
-		else
-			info->accessible = v;
-	} else
+	else if (fastcmp(field,"accessible"))
+		info->accessible = lua_isboolean(L,3);
+	else
 		CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "skincolor_t", field);
 	return 1;
 }
@@ -1678,8 +1674,11 @@ static int colorramp_get(lua_State *L)
 static int colorramp_set(lua_State *L)
 {
 	UINT8 *colorramp = *((UINT8 **)luaL_checkudata(L, 1, META_COLORRAMP));
+	UINT16 cnum = (UINT16)(((uint8_t*)colorramp - (uint8_t*)(skincolors[0].ramp))/sizeof(skincolor_t));
 	UINT32 n = luaL_checkinteger(L, 2);
 	UINT8 i = (UINT8)luaL_checkinteger(L, 3);
+	if (cnum < SKINCOLOR_FIRSTFREESLOT || cnum >= numskincolors)
+		return luaL_error(L, "skincolors[] index %d out of range (%d - %d)", cnum, SKINCOLOR_FIRSTFREESLOT, numskincolors-1);
 	if (n >= COLORRAMPSIZE)
 		return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' index %d out of range (0 - %d)", n, COLORRAMPSIZE-1);
 	if (hud_running)
diff --git a/src/m_menu.c b/src/m_menu.c
index 76ac7e0865c173a9585f64e52d7f3eb13a5bb704..ec3f59b41b16d567bf07522b04588b12ad62728e 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -3860,8 +3860,6 @@ void M_Init(void)
 #ifndef NONET
 	CV_RegisterVar(&cv_serversort);
 #endif
-
-	M_InitPlayerSetupColors();
 }
 
 void M_InitCharacterTables(void)
@@ -11427,7 +11425,7 @@ void M_AddMenuColor(UINT8 color) {
 		return;
 	}
 
-	c = (menucolor_t *)Z_Malloc(sizeof(menucolor_t), PU_STATIC, NULL);
+	c = (menucolor_t *)malloc(sizeof(menucolor_t));
 	c->color = color;
 	if (menucolorhead == NULL) {
 		c->next = c;
@@ -11561,6 +11559,7 @@ UINT8 M_GetColorAfter(UINT8 color) {
 
 void M_InitPlayerSetupColors(void) {
 	UINT8 i;
+	numskincolors = SKINCOLOR_FIRSTFREESLOT;
 	menucolorhead = menucolortail = NULL;
 	for (i=0; i<numskincolors; i++)
 		M_AddMenuColor(i);
@@ -11576,9 +11575,9 @@ void M_FreePlayerSetupColors(void) {
 		if (look != menucolortail) {
 			tmp = look;
 			look = look->next;
-			Z_Free(tmp);
+			free(tmp);
 		} else {
-			Z_Free(look);
+			free(look);
 			return;
 		}
 	}