diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index af2d99a0c015cf05001ccaa31b3c54fffa09ea04..bec2e488ab40b46fdb519e37493b9c0717b8d6b9 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -30,9 +30,6 @@
 #include "lua_hud.h" // hud_running errors
 #include "lua_hook.h" // hook_cmd_running errors
 
-extern CV_PossibleValue_t Color_cons_t[];
-extern UINT8 skincolor_modified[];
-
 boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor);
 state_t *astate;
 
diff --git a/src/m_menu.c b/src/m_menu.c
index ca4486bf623035e878abf81117b88513b7b7fb12..083de2de179a8cd92cd8fb706630edf2769b952b 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -9111,7 +9111,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
 {
 	INT32 skinnum, botskinnum;
 	UINT16 i;
-	UINT16 firstvalid = 65535, lastvalid = 65535;
+	INT32 firstvalid = INT32_MAX, lastvalid = INT32_MAX;
 	boolean allowed = false;
 	(void)choice;
 
@@ -9155,7 +9155,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
 				}
 
 				// Handling order.
-				if (firstvalid == 65535)
+				if (firstvalid == INT32_MAX)
 					firstvalid = i;
 				else
 				{
@@ -9518,7 +9518,7 @@ static void M_ChoosePlayer(INT32 choice)
 	UINT8 skinnum;
 
 	// skip this if forcecharacter or no characters available
-	if (choice == 65535)
+	if (choice == INT32_MAX)
 	{
 		skinnum = botskin = 0;
 		botingame = false;
diff --git a/src/r_draw.c b/src/r_draw.c
index 7b0d88e7d2156a87f46c44554af33cf4ccdcef35..a9dbb93585fb8019ad9ee5f499946fe1b738ab5b 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -122,54 +122,56 @@ float focallengthf, zeroheight;
 UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
 
 // =========================================================================
-//                   TRANSLATION COLORMAP CODE
+//                       TRANSLATION COLORMAP CODE
 // =========================================================================
 
-#define DEFAULT_TT_CACHE_INDEX MAXSKINS
-#define BOSS_TT_CACHE_INDEX (MAXSKINS + 1)
-#define METALSONIC_TT_CACHE_INDEX (MAXSKINS + 2)
-#define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3)
-#define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4)
-#define BLINK_TT_CACHE_INDEX (MAXSKINS + 5)
-#define DASHMODE_TT_CACHE_INDEX (MAXSKINS + 6)
-#define DEFAULT_STARTTRANSCOLOR 96
 #define NUM_PALETTE_ENTRIES 256
+#define DEFAULT_STARTTRANSCOLOR 96
+
+enum
+{
+	DEFAULT_TT_CACHE_INDEX,
+	BOSS_TT_CACHE_INDEX,
+	METALSONIC_TT_CACHE_INDEX,
+	ALLWHITE_TT_CACHE_INDEX,
+	RAINBOW_TT_CACHE_INDEX,
+	BLINK_TT_CACHE_INDEX,
+	DASHMODE_TT_CACHE_INDEX,
+
+	TT_CACHE_SIZE
+};
 
-static UINT8 **translationtablecache[MAXSKINS + 7] = {NULL};
-UINT8 skincolor_modified[MAXSKINCOLORS];
+static UINT8 **translationtablecache[TT_CACHE_SIZE] = {NULL};
+static UINT8 **skintranslationcache[NUM_PALETTE_ENTRIES] = {NULL};
 
-static INT32 SkinToCacheIndex(INT32 skinnum)
+boolean skincolor_modified[MAXSKINCOLORS];
+
+static INT32 TranslationToCacheIndex(INT32 translation)
 {
-	switch (skinnum)
+	switch (translation)
 	{
-		case TC_DEFAULT:    return DEFAULT_TT_CACHE_INDEX;
 		case TC_BOSS:       return BOSS_TT_CACHE_INDEX;
 		case TC_METALSONIC: return METALSONIC_TT_CACHE_INDEX;
 		case TC_ALLWHITE:   return ALLWHITE_TT_CACHE_INDEX;
 		case TC_RAINBOW:    return RAINBOW_TT_CACHE_INDEX;
 		case TC_BLINK:      return BLINK_TT_CACHE_INDEX;
 		case TC_DASHMODE:   return DASHMODE_TT_CACHE_INDEX;
-		     default:       break;
+		default:            return DEFAULT_TT_CACHE_INDEX;
 	}
-
-	return skinnum;
 }
 
-static INT32 CacheIndexToSkin(INT32 ttc)
+static INT32 CacheIndexToTranslation(INT32 index)
 {
-	switch (ttc)
+	switch (index)
 	{
-		case DEFAULT_TT_CACHE_INDEX:    return TC_DEFAULT;
 		case BOSS_TT_CACHE_INDEX:       return TC_BOSS;
 		case METALSONIC_TT_CACHE_INDEX: return TC_METALSONIC;
 		case ALLWHITE_TT_CACHE_INDEX:   return TC_ALLWHITE;
 		case RAINBOW_TT_CACHE_INDEX:    return TC_RAINBOW;
 		case BLINK_TT_CACHE_INDEX:      return TC_BLINK;
 		case DASHMODE_TT_CACHE_INDEX:   return TC_DASHMODE;
-		     default:                   break;
+		default:                        return TC_DEFAULT;
 	}
-
-	return ttc;
 }
 
 CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
@@ -398,18 +400,18 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
 	RGBA_t color;
 	UINT8 brightness;
 	INT32 j;
-	UINT8 colorbrightnesses[16];
+	UINT8 colorbrightnesses[COLORRAMPSIZE];
 	UINT16 brightdif;
 	INT32 temp;
 
 	// first generate the brightness of all the colours of that skincolour
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < COLORRAMPSIZE; i++)
 	{
 		color = V_GetColor(skincolors[skincolor].ramp[i]);
 		SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue);
 	}
 
-	// next, for every colour in the palette, choose the transcolor that has the closest brightness
+	// next, for every colour in the palette, choose the translated colour that has the closest brightness
 	for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
 	{
 		if (i == 0 || i == 31) // pure black and pure white don't change
@@ -420,7 +422,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
 		color = V_GetColor(i);
 		SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue);
 		brightdif = 256;
-		for (j = 0; j < 16; j++)
+		for (j = 0; j < COLORRAMPSIZE; j++)
 		{
 			temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]);
 			if (temp < brightdif)
@@ -436,28 +438,29 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
 
 /**	\brief	Generates a translation colormap.
 
-	\param	dest_colormap	colormap to populate
-	\param	skinnum		skin number, or a translation mode
-	\param	color		translation color
+	\param	dest_colormap   colormap to populate
+	\param	translation     translation mode
+	\param	color           translation color
+	\param  starttranscolor starting point of the translation
 
 	\return	void
 */
-static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color)
+static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 translation, UINT16 color, INT32 starttranscolor)
 {
-	INT32 i, starttranscolor, skinramplength;
+	INT32 i, skinramplength;
 
 	// Handle a couple of simple special cases
-	if (skinnum < TC_DEFAULT)
+	if (translation < TC_DEFAULT)
 	{
-		switch (skinnum)
+		switch (translation)
 		{
 			case TC_ALLWHITE:
 				memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
 				return;
 			case TC_RAINBOW:
 				if (color >= numskincolors)
-					I_Error("Invalid skin color #%hu.", (UINT16)color);
-				if (color != SKINCOLOR_NONE)
+					I_Error("Invalid skin color #%hu", (UINT16)color);
+				else if (color != SKINCOLOR_NONE)
 				{
 					R_RainbowColormap(dest_colormap, color);
 					return;
@@ -465,8 +468,8 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 				break;
 			case TC_BLINK:
 				if (color >= numskincolors)
-					I_Error("Invalid skin color #%hu.", (UINT16)color);
-				if (color != SKINCOLOR_NONE)
+					I_Error("Invalid skin color #%hu", (UINT16)color);
+				else if (color != SKINCOLOR_NONE)
 				{
 					memset(dest_colormap, skincolors[color].ramp[3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
 					return;
@@ -480,26 +483,28 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 			dest_colormap[i] = (UINT8)i;
 
 		// White!
-		if (skinnum == TC_BOSS)
+		if (translation == TC_BOSS)
 		{
 			UINT8 *originalColormap = R_GetTranslationColormap(TC_DEFAULT, (skincolornum_t)color, GTC_CACHE);
-			for (i = 0; i < 16; i++)
+			if (starttranscolor >= NUM_PALETTE_ENTRIES)
+				I_Error("Invalid startcolor #%d", starttranscolor);
+			for (i = 0; i < COLORRAMPSIZE; i++)
 			{
-				dest_colormap[DEFAULT_STARTTRANSCOLOR + i] = originalColormap[DEFAULT_STARTTRANSCOLOR + i];
+				dest_colormap[starttranscolor + i] = originalColormap[starttranscolor + i];
 				dest_colormap[31-i] = i;
 			}
 		}
-		else if (skinnum == TC_METALSONIC)
+		else if (translation == TC_METALSONIC)
 		{
 			for (i = 0; i < 6; i++)
 			{
 				dest_colormap[skincolors[SKINCOLOR_BLUE].ramp[12-i]] = skincolors[SKINCOLOR_BLUE].ramp[i];
 			}
 			dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0;
-			for (i = 0; i < 16; i++)
+			for (i = 0; i < COLORRAMPSIZE; i++)
 				dest_colormap[96+i] = dest_colormap[skincolors[SKINCOLOR_COBALT].ramp[i]];
 		}
-		else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices
+		else if (translation == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices
 		{
 			// greens -> ketchups
 			dest_colormap[96] = dest_colormap[97] = 48;
@@ -543,26 +548,21 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 	}
 
 	if (color >= numskincolors)
-		I_Error("Invalid skin color #%hu.", (UINT16)color);
-
-	if (skinnum < 0 && skinnum > TC_DEFAULT)
-		I_Error("Invalid translation colormap index %d.", skinnum);
-
-	starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum]->starttranscolor : DEFAULT_STARTTRANSCOLOR;
+		I_Error("Invalid skin color #%hu", (UINT16)color);
 
 	if (starttranscolor >= NUM_PALETTE_ENTRIES)
-		I_Error("Invalid startcolor #%d.", starttranscolor);
+		I_Error("Invalid startcolor #%d", starttranscolor);
 
 	// Fill in the entries of the palette that are fixed
 	for (i = 0; i < starttranscolor; i++)
 		dest_colormap[i] = (UINT8)i;
 
-	i = starttranscolor + 16;
+	i = starttranscolor + COLORRAMPSIZE;
 	if (i < NUM_PALETTE_ENTRIES)
 	{
 		for (i = (UINT8)i; i < NUM_PALETTE_ENTRIES; i++)
 			dest_colormap[i] = (UINT8)i;
-		skinramplength = 16;
+		skinramplength = COLORRAMPSIZE;
 	}
 	else
 		skinramplength = i - NUM_PALETTE_ENTRIES; // shouldn't this be NUM_PALETTE_ENTRIES - starttranscolor?
@@ -575,7 +575,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 
 /**	\brief	Retrieves a translation colormap from the cache.
 
-	\param	skinnum	number of skin, TC_DEFAULT or TC_BOSS
+	\param	skinnum	number of skin, or translation modes
 	\param	color	translation color
 	\param	flags	set GTC_CACHE to use the cache
 
@@ -583,25 +583,47 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 */
 UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags)
 {
-	UINT8* ret;
-	INT32 skintableindex = SkinToCacheIndex(skinnum); // Adjust if we want the default colormap
-	INT32 i;
+	UINT8 ***cache = NULL;
+	INT32 index, starttranscolor;
+	UINT8 *ret;
+
+	// Adjust if we want the default colormap
+	if (skinnum >= numskins)
+		I_Error("Invalid skin number %d", skinnum);
+	else if (skinnum >= 0)
+	{
+		cache = skintranslationcache;
+		starttranscolor = index = skins[skinnum]->starttranscolor;
+	}
+	else if (skinnum <= TC_DEFAULT)
+	{
+		cache = translationtablecache;
+		starttranscolor = DEFAULT_STARTTRANSCOLOR;
+		index = TranslationToCacheIndex(skinnum);
+	}
+	else
+		I_Error("Invalid translation %d", skinnum);
 
 	if (flags & GTC_CACHE)
 	{
 		// Allocate table for skin if necessary
-		if (!translationtablecache[skintableindex])
-			translationtablecache[skintableindex] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL);
+		if (!cache[index])
+			cache[index] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL);
 
 		// Get colormap
-		ret = translationtablecache[skintableindex][color];
+		ret = cache[index][color];
 
 		// Rebuild the cache if necessary
 		if (skincolor_modified[color])
 		{
-			for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++)
+			INT32 i;
+
+			for (i = 0; i < TT_CACHE_SIZE; i++)
 				if (translationtablecache[i] && translationtablecache[i][color])
-					R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToSkin(i), color);
+					R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToTranslation(i), color, starttranscolor);
+			for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
+				if (skintranslationcache[i] && skintranslationcache[i][color])
+					R_GenerateTranslationColormap(skintranslationcache[i][color], 0, color, i);
 
 			skincolor_modified[color] = false;
 		}
@@ -612,11 +634,11 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags
 	if (!ret)
 	{
 		ret = Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8);
-		R_GenerateTranslationColormap(ret, skinnum, color);
+		R_GenerateTranslationColormap(ret, skinnum, color, starttranscolor);
 
 		// Cache the colormap if desired
 		if (flags & GTC_CACHE)
-			translationtablecache[skintableindex][color] = ret;
+			cache[index][color] = ret;
 	}
 
 	return ret;
@@ -634,9 +656,12 @@ void R_FlushTranslationColormapCache(void)
 {
 	INT32 i;
 
-	for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++)
+	for (i = 0; i < TT_CACHE_SIZE; i++)
 		if (translationtablecache[i])
 			memset(translationtablecache[i], 0, MAXSKINCOLORS * sizeof(UINT8**));
+	for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
+		if (skintranslationcache[i])
+			memset(skintranslationcache[i], 0, MAXSKINCOLORS * sizeof(UINT8**));
 }
 
 UINT16 R_GetColorByName(const char *name)
diff --git a/src/r_draw.h b/src/r_draw.h
index 2173c7a5a36e5c9b92063657aa833dbb5b457726..6d7e89f35db6cf46544b141e9b59f1bcd22c8d43 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -147,7 +147,7 @@ UINT8 *R_GetBlendTable(int style, INT32 alphalevel);
 boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel);
 
 // Color ramp modification should force a recache
-extern UINT8 skincolor_modified[];
+extern boolean skincolor_modified[];
 
 void R_InitViewBuffer(INT32 width, INT32 height);
 void R_InitViewBorder(void);
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 88affcf0a9a8abe5d88da67f62e495ea3841b6c0..1db91da7a6678ef2bffa244f0265334ffb76dc31 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -128,8 +128,6 @@ static patch_t *gotrflag;
 static patch_t *gotbflag;
 static patch_t *fnshico;
 
-static boolean facefreed[MAXPLAYERS];
-
 hudinfo_t hudinfo[NUMHUDITEMS] =
 {
 	{  16, 176, V_SNAPTOLEFT|V_SNAPTOBOTTOM}, // HUD_LIVES
@@ -361,17 +359,14 @@ void ST_LoadFaceGraphics(INT32 skinnum)
 	}
 	else
 		faceprefix[skinnum] = superprefix[skinnum] = W_CachePatchName("MISSING", PU_HUDGFX); // ditto
-	facefreed[skinnum] = false;
 }
 
 void ST_ReloadSkinFaceGraphics(void)
 {
 	INT32 i;
 
-	if (faceprefix)
-		Z_Free(faceprefix);
-	if (superprefix)
-		Z_Free(superprefix);
+	Z_Free(faceprefix);
+	Z_Free(superprefix);
 
 	if (!numskins)
 		return;
@@ -421,11 +416,6 @@ lumpnum_t st_borderpatchnum;
 
 void ST_Init(void)
 {
-	INT32 i;
-
-	for (i = 0; i < MAXPLAYERS; i++)
-		facefreed[i] = true;
-
 	if (dedicated)
 		return;