diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index ed0b8e528ef1462ada824a9f7764168b18a96b1e..25b156153fda79bcad66427359c11cc157aec016 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -1495,7 +1495,7 @@ static boolean SV_SendServerConfig(INT32 node)
 		if (!playeringame[i])
 			continue;
 		netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin;
-		netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor;
+		netbuffer->u.servercfg.playercolor[i] = (UINT16)players[i].skincolor;
 		netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)LONG(players[i].availabilities);
 	}
 
@@ -3877,7 +3877,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
 			for (j = 0; j < MAXPLAYERS; j++)
 			{
 				if (netbuffer->u.servercfg.playerskins[j] == 0xFF
-				 && netbuffer->u.servercfg.playercolor[j] == 0xFF
+				 && netbuffer->u.servercfg.playercolor[j] == 0xFFFF
 				 && netbuffer->u.servercfg.playeravailabilities[j] == 0xFFFFFFFF)
 					continue; // not in game
 
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 463240a2adc87289f8e00f319c7f90df062bf5f2..f15b5ff91efb5473794194bda8b621e7db689ce4 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -188,7 +188,7 @@ typedef struct
 	SINT8 xtralife;
 	SINT8 pity;
 
-	UINT8 skincolor;
+	UINT16 skincolor;
 	INT32 skin;
 	UINT32 availabilities;
 	// Just in case Lua does something like
@@ -308,7 +308,7 @@ typedef struct
 
 	// 0xFF == not in game; else player skin num
 	UINT8 playerskins[MAXPLAYERS];
-	UINT8 playercolor[MAXPLAYERS];
+	UINT16 playercolor[MAXPLAYERS];
 	UINT32 playeravailabilities[MAXPLAYERS];
 
 	UINT8 gametype;
@@ -414,7 +414,7 @@ typedef struct
 {
 	char name[MAXPLAYERNAME+1];
 	UINT8 skin;
-	UINT8 color;
+	UINT16 color;
 	UINT32 pflags;
 	UINT32 score;
 	UINT8 ctfteam;
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 01c14e937a399922c3a031e3680d03970d630875..84070135a165d1e54a7b884135275ba08a29957b 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -225,7 +225,7 @@ consvar_t cv_allowseenames = {"allowseenames", "Yes", CV_NETVAR, CV_YesNo, NULL,
 consvar_t cv_playername = {"name", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_playername2 = {"name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange, 0, NULL, NULL, 0, 0, NULL};
 // player colors
-UINT8 lastgoodcolor = SKINCOLOR_BLUE, lastgoodcolor2 = SKINCOLOR_BLUE;
+UINT16 lastgoodcolor = SKINCOLOR_BLUE, lastgoodcolor2 = SKINCOLOR_BLUE;
 consvar_t cv_playercolor = {"color", "Blue", CV_CALL|CV_NOINIT, Color_cons_t, Color_OnChange, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_playercolor2 = {"color2", "Orange", CV_CALL|CV_NOINIT, Color_cons_t, Color2_OnChange, 0, NULL, NULL, 0, 0, NULL};
 // player's skin, saved for commodity, when using a favorite skins wad..
@@ -1285,7 +1285,7 @@ static void SendNameAndColor(void)
 				players[consoleplayer].skincolor = cv_playercolor.value % numskincolors;
 
 				if (players[consoleplayer].mo)
-					players[consoleplayer].mo->color = (UINT8)players[consoleplayer].skincolor;
+					players[consoleplayer].mo->color = (UINT16)players[consoleplayer].skincolor;
 			}*/
 		}
 		else
@@ -1323,7 +1323,7 @@ static void SendNameAndColor(void)
 	// Finally write out the complete packet and send it off.
 	WRITESTRINGN(p, cv_playername.zstring, MAXPLAYERNAME);
 	WRITEUINT32(p, (UINT32)players[consoleplayer].availabilities);
-	WRITEUINT8(p, (UINT8)cv_playercolor.value);
+	WRITEUINT16(p, (UINT16)cv_playercolor.value);
 	WRITEUINT8(p, (UINT8)cv_skin.value);
 	SendNetXCmd(XD_NAMEANDCOLOR, buf, p - buf);
 }
@@ -1439,7 +1439,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 {
 	player_t *p = &players[playernum];
 	char name[MAXPLAYERNAME+1];
-	UINT8 color, skin;
+	UINT16 color;
+	UINT8 skin;
 
 #ifdef PARANOIA
 	if (playernum < 0 || playernum > MAXPLAYERS)
@@ -1458,7 +1459,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 
 	READSTRINGN(*cp, name, MAXPLAYERNAME);
 	p->availabilities = READUINT32(*cp);
-	color = READUINT8(*cp);
+	color = READUINT16(*cp);
 	skin = READUINT8(*cp);
 
 	// set name
@@ -1468,7 +1469,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 	// set color
 	p->skincolor = color % numskincolors;
 	if (p->mo)
-		p->mo->color = (UINT8)p->skincolor;
+		p->mo->color = (UINT16)p->skincolor;
 
 	// normal player colors
 	if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer]))
diff --git a/src/d_player.h b/src/d_player.h
index e5c7e72980d644dc926ca8e792f1136a54fd3b16..0f10317084b046d713a5b96a3a2e9392af6fb892 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -366,7 +366,7 @@ typedef struct player_s
 	UINT16 flashpal;
 
 	// Player skin colorshift, 0-15 for which color to draw player.
-	UINT8 skincolor;
+	UINT16 skincolor;
 
 	INT32 skin;
 	UINT32 availabilities;
diff --git a/src/dehacked.c b/src/dehacked.c
index 13e4eb6fee2d8f2f35484dd419560e54ccb10e0f..627a3a11921ad43b945f0ea1519fec4d20750dff 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -452,7 +452,7 @@ static void readPlayer(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR"))
 			{
 				SLOTFOUND
-				description[num].oppositecolor = (UINT8)get_number(word2);
+				description[num].oppositecolor = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME"))
 			{
@@ -462,12 +462,12 @@ static void readPlayer(MYFILE *f, INT32 num)
 			else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR"))
 			{
 				SLOTFOUND
-				description[num].tagtextcolor = (UINT8)get_number(word2);
+				description[num].tagtextcolor = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR"))
 			{
 				SLOTFOUND
-				description[num].tagoutlinecolor = (UINT8)get_number(word2);
+				description[num].tagoutlinecolor = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "STATUS"))
 			{
@@ -821,11 +821,11 @@ static void readskincolor(MYFILE *f, INT32 num)
 			}
 			else if (fastcmp(word, "INVCOLOR"))
 			{
-				skincolors[num].invcolor = (UINT8)get_number(word2);
+				skincolors[num].invcolor = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "INVSHADE"))
 			{
-				skincolors[num].invshade = get_number(word2);
+				skincolors[num].invshade = get_number(word2)%COLORRAMPSIZE;
 			}
 			else if (fastcmp(word, "CHATCOLOR"))
 			{
@@ -4043,19 +4043,19 @@ static void readmaincfg(MYFILE *f)
 			}
 			else if (fastcmp(word, "REDTEAM"))
 			{
-				skincolor_redteam = (UINT8)get_number(word2);
+				skincolor_redteam = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "BLUETEAM"))
 			{
-				skincolor_blueteam = (UINT8)get_number(word2);
+				skincolor_blueteam = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "REDRING"))
 			{
-				skincolor_redring = (UINT8)get_number(word2);
+				skincolor_redring = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "BLUERING"))
 			{
-				skincolor_bluering = (UINT8)get_number(word2);
+				skincolor_bluering = (UINT16)get_number(word2);
 			}
 			else if (fastcmp(word, "INVULNTICS"))
 			{
diff --git a/src/doomdef.h b/src/doomdef.h
index 7f401f23a79eec6b67b1d9451ec6253fd578a93f..120df85262266d87bfe129139bcaba2f20b34879 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -241,12 +241,13 @@ extern char logfilename[1024];
 
 #define COLORRAMPSIZE 16
 #define MAXCOLORNAME 32
+#define NUMCOLORFREESLOTS 1024
 
 typedef struct skincolor_s
 {
 	char name[MAXCOLORNAME+1];  // Skincolor name
 	UINT8 ramp[COLORRAMPSIZE];  // Colormap ramp
-	UINT8 invcolor;             // Signpost color
+	UINT16 invcolor;            // Signpost color
 	UINT8 invshade;             // Signpost color shade
 	UINT16 chatcolor;           // Chat color
 	boolean accessible;         // Accessible by the color command + setup menu
@@ -388,7 +389,7 @@ typedef enum
 	SKINCOLOR_SUPERTAN5,
 
 	SKINCOLOR_FIRSTFREESLOT,
-	SKINCOLOR_LASTFREESLOT = 255,
+	SKINCOLOR_LASTFREESLOT = SKINCOLOR_FIRSTFREESLOT + NUMCOLORFREESLOTS - 1,
 
 	MAXSKINCOLORS,
 
@@ -397,7 +398,6 @@ typedef enum
 
 UINT16 numskincolors;
 
-#define NUMCOLORFREESLOTS (SKINCOLOR_LASTFREESLOT-SKINCOLOR_FIRSTFREESLOT)+1
 extern skincolor_t skincolors[MAXSKINCOLORS];
 
 // State updates, number of tics / second.
diff --git a/src/doomstat.h b/src/doomstat.h
index 57ea3e0496ef4679512ba6c82f029d3396f7bb47..fa346540cf6bb3606c53cc8c90ed048258cbe75d 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -145,7 +145,7 @@ extern INT32 tutorialanalog; // store cv_analog[0] user value
 extern boolean looptitle;
 
 // CTF colors.
-extern UINT8 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering;
+extern UINT16 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering;
 
 extern tic_t countdowntimer;
 extern boolean countdowntimeup;
diff --git a/src/g_demo.c b/src/g_demo.c
index a901e8dea9b135f093940f3aa6d68896ffb592a8..7c949a4c822293e50a1eef11ed1b129f19381a2a 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -68,7 +68,7 @@ static struct {
 	UINT8 flags; // EZT flags
 
 	// EZT_COLOR
-	UINT8 color, lastcolor;
+	UINT16 color, lastcolor;
 
 	// EZT_SCALE
 	fixed_t scale, lastscale;
@@ -82,7 +82,8 @@ static struct {
 // There is no conflict here.
 typedef struct demoghost {
 	UINT8 checksum[16];
-	UINT8 *buffer, *p, color, fadein;
+	UINT8 *buffer, *p, fadein;
+	UINT16 color;
 	UINT16 version;
 	mobj_t oldmo, *mo;
 	struct demoghost *next;
@@ -93,7 +94,7 @@ demoghost *ghosts = NULL;
 // DEMO RECORDING
 //
 
-#define DEMOVERSION 0x000c
+#define DEMOVERSION 0x000d
 #define DEMOHEADER  "\xF0" "SRB2Replay" "\x0F"
 
 #define DF_GHOST        0x01 // This demo contains ghost data too!
@@ -280,13 +281,13 @@ void G_GhostAddColor(ghostcolor_t color)
 {
 	if (!demorecording || !(demoflags & DF_GHOST))
 		return;
-	if (ghostext.lastcolor == (UINT8)color)
+	if (ghostext.lastcolor == (UINT16)color)
 	{
 		ghostext.flags &= ~EZT_COLOR;
 		return;
 	}
 	ghostext.flags |= EZT_COLOR;
-	ghostext.color = (UINT8)color;
+	ghostext.color = (UINT16)color;
 }
 
 void G_GhostAddScale(fixed_t scale)
@@ -425,7 +426,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 		WRITEUINT8(demo_p,ghostext.flags);
 		if (ghostext.flags & EZT_COLOR)
 		{
-			WRITEUINT8(demo_p,ghostext.color);
+			WRITEUINT16(demo_p,ghostext.color);
 			ghostext.lastcolor = ghostext.color;
 		}
 		if (ghostext.flags & EZT_SCALE)
@@ -501,7 +502,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 			WRITEUINT8(demo_p,ghost->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
 		WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK));
-		WRITEUINT8(demo_p,ghost->player->followmobj->color);
+		WRITEUINT16(demo_p,ghost->player->followmobj->color);
 
 		*followtic_p = followtic;
 	}
@@ -566,7 +567,7 @@ void G_ConsGhostTic(void)
 	{ // But wait, there's more!
 		UINT8 xziptic = READUINT8(demo_p);
 		if (xziptic & EZT_COLOR)
-			demo_p++;
+			demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16);
 		if (xziptic & EZT_SCALE)
 			demo_p += sizeof(fixed_t);
 		if (xziptic & EZT_HIT)
@@ -633,7 +634,7 @@ void G_ConsGhostTic(void)
 			demo_p++;
 		demo_p += sizeof(UINT16);
 		demo_p++;
-		demo_p++;
+		demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16);
 	}
 
 	// Re-synchronise
@@ -731,7 +732,7 @@ void G_GhostTicker(void)
 			xziptic = READUINT8(g->p);
 			if (xziptic & EZT_COLOR)
 			{
-				g->color = READUINT8(g->p);
+				g->color = (g->version==0x000c) ? READUINT8(g->p) : READUINT16(g->p);
 				switch(g->color)
 				{
 				default:
@@ -864,7 +865,7 @@ void G_GhostTicker(void)
 			g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4);
 			break;
 		case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer)
-			g->mo->color = (UINT8)(SKINCOLOR_RUBY + (leveltime % (MAXSKINCOLORS - SKINCOLOR_RUBY))); // Passes through all saturated colours
+			g->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours
 			break;
 		default:
 			break;
@@ -918,7 +919,7 @@ void G_GhostTicker(void)
 				follow->sprite = READUINT16(g->p);
 				follow->frame = (READUINT8(g->p)) | (g->mo->frame & FF_TRANSMASK);
 				follow->angle = g->mo->angle;
-				follow->color = READUINT8(g->p);
+				follow->color = (g->version==0x000c) ? READUINT8(g->p) : READUINT16(g->p);
 
 				if (!(followtic & FZT_SPAWNED))
 				{
@@ -1158,7 +1159,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				follow->sprite = READUINT16(metal_p);
 				follow->frame = READUINT32(metal_p); // NOT & FF_FRAMEMASK here, so 32 bits
 				follow->angle = metal->angle;
-				follow->color = READUINT8(metal_p);
+				follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
 
 				if (!(followtic & FZT_SPAWNED))
 				{
@@ -1340,7 +1341,7 @@ void G_WriteMetalTic(mobj_t *metal)
 			WRITEUINT8(demo_p,metal->player->followmobj->sprite2);
 		WRITEUINT16(demo_p,metal->player->followmobj->sprite);
 		WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits
-		WRITEUINT8(demo_p,metal->player->followmobj->color);
+		WRITEUINT16(demo_p,metal->player->followmobj->color);
 
 		*followtic_p = followtic;
 	}
@@ -1394,7 +1395,7 @@ void G_RecordMetal(void)
 void G_BeginRecording(void)
 {
 	UINT8 i;
-	char name[16];
+	char name[MAXCOLORNAME+1];
 	player_t *player = &players[consoleplayer];
 
 	if (demo_p)
@@ -1457,12 +1458,12 @@ void G_BeginRecording(void)
 	demo_p += 16;
 
 	// Color
-	for (i = 0; i < 16 && cv_playercolor.string[i]; i++)
+	for (i = 0; i < MAXCOLORNAME && cv_playercolor.string[i]; i++)
 		name[i] = cv_playercolor.string[i];
-	for (; i < 16; i++)
+	for (; i < MAXCOLORNAME; i++)
 		name[i] = '\0';
-	M_Memcpy(demo_p,name,16);
-	demo_p += 16;
+	M_Memcpy(demo_p,name,MAXCOLORNAME);
+	demo_p += MAXCOLORNAME;
 
 	// Stats
 	WRITEUINT8(demo_p,player->charability);
@@ -1622,7 +1623,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
 	c = READUINT8(p); // SUBVERSION
 	I_Assert(c == SUBVERSION);
 	s = READUINT16(p);
-	I_Assert(s == DEMOVERSION);
+	I_Assert(s >= 0x000c);
 	p += 16; // demo checksum
 	I_Assert(!memcmp(p, "PLAY", 4));
 	p += 4; // PLAY
@@ -1671,6 +1672,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
 	switch(oldversion) // demoversion
 	{
 	case DEMOVERSION: // latest always supported
+	case 0x000c: // all that changed between then and now was longer color name
 		break;
 	// too old, cannot support.
 	default:
@@ -1744,15 +1746,15 @@ void G_DoPlayDemo(char *defdemoname)
 {
 	UINT8 i;
 	lumpnum_t l;
-	char skin[17],color[17],*n,*pdemoname;
-	UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration;
+	char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname;
+	UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration,cnamelen;
 	pflags_t pflags;
 	UINT32 randseed, followitem;
 	fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight;
 	char msg[1024];
 
 	skin[16] = '\0';
-	color[16] = '\0';
+	color[MAXCOLORNAME] = '\0';
 
 	n = defdemoname+strlen(defdemoname);
 	while (*n != '/' && *n != '\\' && n != defdemoname)
@@ -1810,6 +1812,11 @@ void G_DoPlayDemo(char *defdemoname)
 	switch(demoversion)
 	{
 	case DEMOVERSION: // latest always supported
+		cnamelen = MAXCOLORNAME;
+		break;
+	// all that changed between then and now was longer color name
+	case 0x000c:
+		cnamelen = 16;
 		break;
 	// too old, cannot support.
 	default:
@@ -1876,8 +1883,8 @@ void G_DoPlayDemo(char *defdemoname)
 	demo_p += 16;
 
 	// Color
-	M_Memcpy(color,demo_p,16);
-	demo_p += 16;
+	M_Memcpy(color,demo_p,cnamelen);
+	demo_p += cnamelen;
 
 	charability = READUINT8(demo_p);
 	charability2 = READUINT8(demo_p);
@@ -1941,7 +1948,9 @@ void G_DoPlayDemo(char *defdemoname)
 	// Set skin
 	SetPlayerSkin(0, skin);
 
+#ifdef HAVE_BLUA
 	LUAh_MapChange(gamemap);
+#endif
 	displayplayer = consoleplayer = 0;
 	memset(playeringame,0,sizeof(playeringame));
 	playeringame[0] = true;
@@ -1949,8 +1958,9 @@ void G_DoPlayDemo(char *defdemoname)
 	G_InitNew(false, G_BuildMapName(gamemap), true, true, false);
 
 	// Set color
-	for (i = 0; i < MAXSKINCOLORS; i++)
-		if (!stricmp(Color_Names[i],color))
+	players[0].skincolor = skins[players[0].skin].prefcolor;
+	for (i = 0; i < numskincolors; i++)
+		if (!stricmp(skincolors[i].name,color))
 		{
 			players[0].skincolor = i;
 			break;
@@ -1992,7 +2002,8 @@ void G_AddGhost(char *defdemoname)
 {
 	INT32 i;
 	lumpnum_t l;
-	char name[17],skin[17],color[17],*n,*pdemoname,md5[16];
+	char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16];
+	UINT8 cnamelen;
 	demoghost *gh;
 	UINT8 flags;
 	UINT8 *buffer,*p;
@@ -2047,6 +2058,11 @@ void G_AddGhost(char *defdemoname)
 	switch(ghostversion)
 	{
 	case DEMOVERSION: // latest always supported
+		cnamelen = MAXCOLORNAME;
+		break;
+	// all that changed between then and now was longer color name
+	case 0x000c:
+		cnamelen = 16;
 		break;
 	// too old, cannot support.
 	default:
@@ -2109,8 +2125,8 @@ void G_AddGhost(char *defdemoname)
 	p += 16;
 
 	// Color
-	M_Memcpy(color, p,16);
-	p += 16;
+	M_Memcpy(color, p,cnamelen);
+	p += cnamelen;
 
 	// Ghosts do not have a player structure to put this in.
 	p++; // charability
@@ -2198,10 +2214,10 @@ void G_AddGhost(char *defdemoname)
 
 	// Set color
 	gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor;
-	for (i = 0; i < MAXSKINCOLORS; i++)
-		if (!stricmp(Color_Names[i],color))
+	for (i = 0; i < numskincolors; i++)
+		if (!stricmp(skincolors[i].name,color))
 		{
-			gh->mo->color = (UINT8)i;
+			gh->mo->color = (UINT16)i;
 			break;
 		}
 	gh->oldmo.color = gh->mo->color;
@@ -2292,6 +2308,7 @@ void G_DoPlayMetal(void)
 	switch(metalversion)
 	{
 	case DEMOVERSION: // latest always supported
+	case 0x000c: // all that changed between then and now was longer color name
 		break;
 	// too old, cannot support.
 	default:
diff --git a/src/g_game.c b/src/g_game.c
index 5bcf9f580ad2612fa64619499c0e634e8ad630ba..6b434cb3bfa12c7ccf4e389e9811bbb3d618c373 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -54,7 +54,7 @@ UINT8 ultimatemode = false;
 
 boolean botingame;
 UINT8 botskin;
-UINT8 botcolor;
+UINT16 botcolor;
 
 JoyType_t Joystick;
 JoyType_t Joystick2;
@@ -135,10 +135,10 @@ INT32 tutorialanalog = 0; // store cv_analog[0] user value
 
 boolean looptitle = false;
 
-UINT8 skincolor_redteam = SKINCOLOR_RED;
-UINT8 skincolor_blueteam = SKINCOLOR_BLUE;
-UINT8 skincolor_redring = SKINCOLOR_SALMON;
-UINT8 skincolor_bluering = SKINCOLOR_CORNFLOWER;
+UINT16 skincolor_redteam = SKINCOLOR_RED;
+UINT16 skincolor_blueteam = SKINCOLOR_BLUE;
+UINT16 skincolor_redring = SKINCOLOR_SALMON;
+UINT16 skincolor_bluering = SKINCOLOR_CORNFLOWER;
 
 tic_t countdowntimer = 0;
 boolean countdowntimeup = false;
@@ -2381,7 +2381,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
 	INT16 totalring;
 	UINT8 laps;
 	UINT8 mare;
-	UINT8 skincolor;
+	UINT16 skincolor;
 	INT32 skin;
 	UINT32 availabilities;
 	tic_t jointime;
@@ -4475,7 +4475,7 @@ cleanup:
 //
 void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS)
 {
-	UINT8 color = skins[pickedchar].prefcolor;
+	UINT16 color = skins[pickedchar].prefcolor;
 	paused = false;
 
 	if (demoplayback)
diff --git a/src/g_state.h b/src/g_state.h
index 3320ebc47e91e8a78be0ea45a64fd0ba46db19bb..e364c5a35b62c323464783d518bf266b2abe4185 100644
--- a/src/g_state.h
+++ b/src/g_state.h
@@ -57,6 +57,7 @@ extern UINT8 ultimatemode; // was sk_insane
 extern gameaction_t gameaction;
 
 extern boolean botingame;
-extern UINT8 botskin, botcolor;
+extern UINT8 botskin;
+extern UINT16 botcolor;
 
 #endif //__G_STATE__
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 9bf2eb3929bdda7914d9e35aee04468547adea2d..e4ea26d861a8189c0668fcb487b907ad995ecc0f 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -682,7 +682,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 	UINT16 w = gpatch->width, h = gpatch->height;
 	UINT32 size = w*h;
 	RGBA_t *image, *blendimage, *cur, blendcolor;
-	UINT8 translation[16]; // First the color index
+	UINT16 translation[16]; // First the color index
 	UINT8 cutoff[16]; // Brightness cutoff before using the next color
 	UINT8 translen = 0;
 	UINT8 i;
@@ -741,7 +741,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
 			numdupes = 1;
 			translen++;
 
-			translation[translen] = (UINT8)skincolors[color].ramp[i];
+			translation[translen] = (UINT16)skincolors[color].ramp[i];
 		}
 
 		translen++;
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 0f7d20893f58900f8ab8441ca38570299fb89ac2..d460f8cf715c9667d74ed3595050d0d518c2dd41 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -2424,6 +2424,17 @@ static int lib_rGetColorByName(lua_State *L)
 	return 1;
 }
 
+// Lua exclusive function, returns the name of a color from the SKINCOLOR_ constant.
+// SKINCOLOR_GREEN > "Green" for example
+static int lib_rGetNameByColor(lua_State *L)
+{
+	UINT16 colornum = (UINT16)luaL_checkinteger(L, 1);
+	if (!colornum || colornum >= numskincolors)
+		return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, numskincolors-1);
+	lua_pushstring(L, skincolors[colornum].name);
+	return 1;
+}
+
 // S_SOUND
 ////////////
 static int lib_sStartSound(lua_State *L)
@@ -3337,6 +3348,7 @@ static luaL_Reg lib[] = {
 
 	// r_draw
 	{"R_GetColorByName", lib_rGetColorByName},
+	{"R_GetNameByColor", lib_rGetNameByColor},
 
 	// s_sound
 	{"S_StartSound",lib_sStartSound},
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 772265ebef43d3b13367d3f849928cc281954552..4aa70574b3802b62b22cbc4772fb11aa216cdd61 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -878,8 +878,8 @@ static int libd_drawNameTag(lua_State *L)
 	INT32 y;
 	const char *str;
 	INT32 flags;
-	UINT8 basecolor;
-	UINT8 outlinecolor;
+	UINT16 basecolor;
+	UINT16 outlinecolor;
 	UINT8 *basecolormap = NULL;
 	UINT8 *outlinecolormap = NULL;
 
@@ -908,8 +908,8 @@ static int libd_drawScaledNameTag(lua_State *L)
 	const char *str;
 	INT32 flags;
 	fixed_t scale;
-	UINT8 basecolor;
-	UINT8 outlinecolor;
+	UINT16 basecolor;
+	UINT16 outlinecolor;
 	UINT8 *basecolormap = NULL;
 	UINT8 *outlinecolormap = NULL;
 
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index 06b8643d1891231799e80dc5f25997d56ef8dc65..81a215c5363c96655b41782f24bb67d30aad671f 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -1508,10 +1508,10 @@ static int lib_setSkinColor(lua_State *L)
 {
 	UINT32 j;
 	skincolor_t *info;
-	UINT8 cnum; //skincolor num
+	UINT16 cnum; //skincolor num
 	lua_remove(L, 1); // don't care about skincolors[] userdata.
 	{
-		cnum = (UINT8)luaL_checkinteger(L, 1);
+		cnum = (UINT16)luaL_checkinteger(L, 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.
@@ -1551,9 +1551,9 @@ static int lib_setSkinColor(lua_State *L)
 					info->ramp[j] = (*((UINT8 **)luaL_checkudata(L, 3, META_COLORRAMP)))[j];
 			R_FlushTranslationColormapCache();
 		} else if (i == 3 || (str && fastcmp(str,"invcolor")))
-			info->invcolor = (UINT8)luaL_checkinteger(L, 3);
+			info->invcolor = (UINT16)luaL_checkinteger(L, 3);
 		else if (i == 4 || (str && fastcmp(str,"invshade")))
-			info->invshade = (UINT8)luaL_checkinteger(L, 3);
+			info->invshade = (UINT8)luaL_checkinteger(L, 3)%COLORRAMPSIZE;
 		else if (i == 5 || (str && fastcmp(str,"chatcolor")))
 			info->chatcolor = (UINT16)luaL_checkinteger(L, 3);
 		else if (i == 6 || (str && fastcmp(str,"accessible"))) {
@@ -1631,9 +1631,9 @@ static int skincolor_set(lua_State *L)
 				info->ramp[i] = (*((UINT8 **)luaL_checkudata(L, 3, META_COLORRAMP)))[i];
 		R_FlushTranslationColormapCache();
 	} else if (fastcmp(field,"invcolor"))
-		info->invcolor = (UINT8)luaL_checkinteger(L, 3);
+		info->invcolor = (UINT16)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"invshade"))
-		info->invshade = (UINT8)luaL_checkinteger(L, 3);
+		info->invshade = (UINT8)luaL_checkinteger(L, 3)%COLORRAMPSIZE;
 	else if (fastcmp(field,"chatcolor"))
 		info->chatcolor = (UINT16)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"accessible"))
diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c
index 6efec9a5f8fd957ec9e6e7818b67ab9fb6325d8c..76c80c541314a2914ccff349f41928bf4dcd7b9a 100644
--- a/src/lua_mathlib.c
+++ b/src/lua_mathlib.c
@@ -175,7 +175,7 @@ static int lib_all7emeralds(lua_State *L)
 // Returns both color and signpost shade numbers!
 static int lib_coloropposite(lua_State *L)
 {
-	UINT8 colornum = (UINT8)luaL_checkinteger(L, 1);
+	UINT16 colornum = (UINT16)luaL_checkinteger(L, 1);
 	if (!colornum || colornum >= numskincolors)
 		return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, numskincolors-1);
 	lua_pushinteger(L, skincolors[colornum].invcolor); // push color
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index dbd3f4aeb1c9944f709738ead2eabd334532566e..6f2496f2498dff0dc1ce199937dc32866dae13ee 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -574,7 +574,7 @@ static int mobj_set(lua_State *L)
 	}
 	case mobj_color:
 	{
-		UINT8 newcolor = (UINT8)luaL_checkinteger(L,3);
+		UINT16 newcolor = (UINT16)luaL_checkinteger(L,3);
 		if (newcolor >= numskincolors)
 			return luaL_error(L, "mobj.color %d out of range (0 - %d).", newcolor, numskincolors-1);
 		mo->color = newcolor;
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index 6afe5009f21ef309d624fcaac4cf59312b5aa00e..1ce9be525f50146735f3973bb5b36de246c5b383 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -461,7 +461,7 @@ static int player_set(lua_State *L)
 		plr->flashpal = (UINT16)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"skincolor"))
 	{
-		UINT8 newcolor = (UINT8)luaL_checkinteger(L,3);
+		UINT16 newcolor = (UINT16)luaL_checkinteger(L,3);
 		if (newcolor >= numskincolors)
 			return luaL_error(L, "player.skincolor %d out of range (0 - %d).", newcolor, numskincolors-1);
 		plr->skincolor = newcolor;
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 156c5db16bbc7d92a4a89151d1c8b05344ef27f8..3d188644b0226e16464fc5a603fee7c036ab6ab1 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -978,7 +978,7 @@ static mobjflag2_t op_oldflags2 = 0;
 static UINT32 op_oldeflags = 0;
 static fixed_t op_oldmomx = 0, op_oldmomy = 0, op_oldmomz = 0, op_oldheight = 0;
 static statenum_t op_oldstate = 0;
-static UINT8 op_oldcolor = 0;
+static UINT16 op_oldcolor = 0;
 
 //
 // Static calculation / common output help
diff --git a/src/m_cond.h b/src/m_cond.h
index 0c56f7f989c0b336a3e7f2e9b0f9c381465e5655..9bb162ff317a34f40d69cc1ec37230e1d818af27 100644
--- a/src/m_cond.h
+++ b/src/m_cond.h
@@ -90,7 +90,7 @@ typedef struct
 	INT16 tag;       ///< Tag of emblem mapthing
 	INT16 level;     ///< Level on which this emblem can be found.
 	UINT8 sprite;    ///< emblem sprite to use, 0 - 25
-	UINT8 color;     ///< skincolor to use
+	UINT16 color;    ///< skincolor to use
 	INT32 var;       ///< If needed, specifies information on the target amount to achieve (or target skin)
 	char hint[110];  ///< Hint for emblem hints menu
 	UINT8 collected; ///< Do you have this emblem?
@@ -102,7 +102,7 @@ typedef struct
 	UINT8 conditionset;     ///< Condition set that awards this emblem.
 	UINT8 showconditionset; ///< Condition set that shows this emblem.
 	UINT8 sprite;           ///< emblem sprite to use, 0 - 25
-	UINT8 color;            ///< skincolor to use
+	UINT16 color;           ///< skincolor to use
 	UINT8 collected;        ///< Do you have this emblem?
 } extraemblem_t;
 
diff --git a/src/m_menu.c b/src/m_menu.c
index 8b79597683c078236cd972f7b58c1a15850f680f..f9061b2513259639aad55948a90904037a2f825f 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -9055,7 +9055,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
 
 	skin_t *charskin = &skins[0];
 	INT32 skinnum = 0;
-	UINT8 col;
+	UINT16 col;
 	UINT8 *colormap = NULL;
 	INT32 prev = -1, next = -1;
 
@@ -9145,8 +9145,8 @@ static void M_DrawSetupChoosePlayerMenu(void)
 		INT32 ox, oxsh = FixedInt(FixedMul(BASEVIDWIDTH*FRACUNIT, FixedDiv(char_scroll, 128*FRACUNIT))), txsh;
 		patch_t *curpatch = NULL, *prevpatch = NULL, *nextpatch = NULL;
 		const char *curtext = NULL, *prevtext = NULL, *nexttext = NULL;
-		UINT8 curtextcolor = 0, prevtextcolor = 0, nexttextcolor = 0;
-		UINT8 curoutlinecolor = 0, prevoutlinecolor = 0, nextoutlinecolor = 0;
+		UINT16 curtextcolor = 0, prevtextcolor = 0, nexttextcolor = 0;
+		UINT16 curoutlinecolor = 0, prevoutlinecolor = 0, nextoutlinecolor = 0;
 
 		// Name tag
 		curtext = description[char_on].displayname;
@@ -11355,7 +11355,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
 			}
 			else if (itemOn == 2)
 			{
-				UINT8 col = skins[setupm_fakeskin].prefcolor;
+				UINT16 col = skins[setupm_fakeskin].prefcolor;
 				if ((setupm_fakecolor->color != col) && skincolors[col].accessible)
 				{
 					S_StartSound(NULL,sfx_menu1); // Tails
@@ -11514,7 +11514,7 @@ static boolean M_QuitMultiPlayerMenu(void)
 	return true;
 }
 
-void M_AddMenuColor(UINT8 color) {
+void M_AddMenuColor(UINT16 color) {
 	menucolor_t *c;
 
 	if (color >= numskincolors) {
@@ -11538,7 +11538,7 @@ void M_AddMenuColor(UINT8 color) {
 	}
 }
 
-void M_MoveColorBefore(UINT8 color, UINT8 targ) {
+void M_MoveColorBefore(UINT16 color, UINT16 targ) {
 	menucolor_t *look, *c = NULL, *t = NULL;
 
 	if (color == targ)
@@ -11580,7 +11580,7 @@ void M_MoveColorBefore(UINT8 color, UINT8 targ) {
 	t->prev = c;
 }
 
-void M_MoveColorAfter(UINT8 color, UINT8 targ) {
+void M_MoveColorAfter(UINT16 color, UINT16 targ) {
 	menucolor_t *look, *c = NULL, *t = NULL;
 
 	if (color == targ)
@@ -11622,7 +11622,7 @@ void M_MoveColorAfter(UINT8 color, UINT8 targ) {
 	t->next = c;
 }
 
-UINT8 M_GetColorBefore(UINT8 color) {
+UINT16 M_GetColorBefore(UINT16 color) {
 	menucolor_t *look;
 
 	if (color >= numskincolors) {
@@ -11638,7 +11638,7 @@ UINT8 M_GetColorBefore(UINT8 color) {
 	}
 }
 
-UINT8 M_GetColorAfter(UINT8 color) {
+UINT16 M_GetColorAfter(UINT16 color) {
 	menucolor_t *look;
 
 	if (color >= numskincolors) {
diff --git a/src/m_menu.h b/src/m_menu.h
index 3f9f15c33ba499ad8ddaa01d77d14d08266cd068..240c4b2359d1f8592f1f69a978f449603b05e256 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -355,11 +355,11 @@ typedef struct
 	// new character select
 	char displayname[SKINNAMESIZE+1];
 	SINT8 skinnum[2];
-	UINT8 oppositecolor;
+	UINT16 oppositecolor;
 	char nametag[8];
 	patch_t *namepic;
-	UINT8 tagtextcolor;
-	UINT8 tagoutlinecolor;
+	UINT16 tagtextcolor;
+	UINT16 tagoutlinecolor;
 } description_t;
 
 // level select platter
@@ -447,16 +447,16 @@ void Moviemode_option_Onchange(void);
 typedef struct menucolor_s {
 	struct menucolor_s *next;
 	struct menucolor_s *prev;
-	UINT8 color;
+	UINT16 color;
 } menucolor_t;
 
 menucolor_t *menucolorhead, *menucolortail;
 
-void M_AddMenuColor(UINT8 color);
-void M_MoveColorBefore(UINT8 color, UINT8 targ);
-void M_MoveColorAfter(UINT8 color, UINT8 targ);
-UINT8 M_GetColorBefore(UINT8 color);
-UINT8 M_GetColorAfter(UINT8 color);
+void M_AddMenuColor(UINT16 color);
+void M_MoveColorBefore(UINT16 color, UINT16 targ);
+void M_MoveColorAfter(UINT16 color, UINT16 targ);
+UINT16 M_GetColorBefore(UINT16 color);
+UINT16 M_GetColorAfter(UINT16 color);
 void M_InitPlayerSetupColors(void);
 void M_FreePlayerSetupColors(void);
 
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 113999d84db520dd53c85eff97f546f971d21370..18de57b54b92e7046742576f66d921abc9e0788a 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -5106,7 +5106,7 @@ void A_SignPlayer(mobj_t *actor)
 	INT32 locvar2 = var2;
 	skin_t *skin = NULL;
 	mobj_t *ov;
-	UINT8 facecolor, signcolor = (UINT8)locvar2;
+	UINT16 facecolor, signcolor = (UINT16)locvar2;
 	UINT32 signframe = states[actor->info->raisestate].frame;
 
 	if (LUA_CallAction("A_SignPlayer", actor))
@@ -5212,19 +5212,8 @@ void A_SignPlayer(mobj_t *actor)
 	}
 
 	actor->tracer->color = signcolor;
-	/*
-	If you're here from the comment above Color_Opposite,
-	the following line is the one which is dependent on the
-	array being symmetrical. It gets the opposite of the
-	opposite of your desired colour just so it can get the
-	brightness frame for the End Sign. It's not a great
-	design choice, but it's constant time array access and
-	the idea that the colours should be OPPOSITES is kind
-	of in the name. If you have a better idea, feel free
-	to let me know. ~toast 2016/07/20
-	*/
 	if (signcolor && signcolor < numskincolors)
-		signframe += (15 - skincolors[skincolors[signcolor].invcolor].invshade);
+		signframe += (15 - skincolors[signcolor].invshade);
 	actor->tracer->frame = signframe;
 }
 
@@ -8804,10 +8793,10 @@ void A_ChangeColorRelative(mobj_t *actor)
 	{
 		// Have you ever seen anything so hideous?
 		if (actor->target)
-			actor->color = (UINT8)(actor->color + actor->target->color);
+			actor->color = (UINT16)(actor->color + actor->target->color);
 	}
 	else
-		actor->color = (UINT8)(actor->color + locvar2);
+		actor->color = (UINT16)(actor->color + locvar2);
 }
 
 // Function: A_ChangeColorAbsolute
@@ -8831,7 +8820,7 @@ void A_ChangeColorAbsolute(mobj_t *actor)
 			actor->color = actor->target->color;
 	}
 	else
-		actor->color = (UINT8)locvar2;
+		actor->color = (UINT16)locvar2;
 }
 
 // Function: A_Dye
@@ -8850,7 +8839,7 @@ void A_Dye(mobj_t *actor)
 	UINT8 color = (UINT8)locvar2;
 	if (LUA_CallAction("A_Dye", actor))
 		return;
-	if (color >= MAXTRANSLATIONS)
+	if (color >= numskincolors)
 		return;
 
 	if (!color)
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 78d3f49c8013dfd46c58c7a90528635fcd10ed2e..fd13c8f05be07c1e9440b979ab9656c81ec6b4d0 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -9429,7 +9429,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
 	case MT_BOSSFLYPOINT:
 		return false;
 	case MT_NIGHTSCORE:
-		mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE);
+		mobj->color = (UINT16)(leveltime % SKINCOLOR_WHITE);
 		break;
 	case MT_JETFUME1:
 		if (!P_JetFume1Think(mobj))
@@ -11939,7 +11939,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
 
 	mobj->health = j + 1;
 	emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting
-	mobj->color = (UINT8)emcolor;
+	mobj->color = (UINT16)emcolor;
 
 	if (emblemlocations[j].collected
 		|| (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin))
diff --git a/src/p_mobj.h b/src/p_mobj.h
index eda7383df2efdeb03b7846ad2310db01b0a8aad0..dae8c8a86079726aa17ebf45f4283761960d26d0 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -312,7 +312,7 @@ typedef struct mobj_s
 	void *skin; // overrides 'sprite' when non-NULL (for player bodies to 'remember' the skin)
 	// Player and mobj sprites in multiplayer modes are modified
 	//  using an internal color lookup table for re-indexing.
-	UINT8 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation).
+	UINT16 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation).
 
 	// Interaction info, by BLOCKMAP.
 	// Links in blocks (if needed).
diff --git a/src/p_saveg.c b/src/p_saveg.c
index bec64ed35773e3082845084c1993faf16e101740..d6abf423258362f4aa9a277300de58c4f0108c72 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1593,7 +1593,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 	if (diff2 & MD2_SKIN)
 		WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins));
 	if (diff2 & MD2_COLOR)
-		WRITEUINT8(save_p, mobj->color);
+		WRITEUINT16(save_p, mobj->color);
 	if (diff2 & MD2_EXTVAL1)
 		WRITEINT32(save_p, mobj->extravalue1);
 	if (diff2 & MD2_EXTVAL2)
@@ -2600,7 +2600,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 	if (diff2 & MD2_SKIN)
 		mobj->skin = &skins[READUINT8(save_p)];
 	if (diff2 & MD2_COLOR)
-		mobj->color = READUINT8(save_p);
+		mobj->color = READUINT16(save_p);
 	if (diff2 & MD2_EXTVAL1)
 		mobj->extravalue1 = READINT32(save_p);
 	if (diff2 & MD2_EXTVAL2)
diff --git a/src/p_spec.c b/src/p_spec.c
index d45a33c47d5b3bee989d6d6e00d67af1ef15f64e..cee21036ad3d048043980f21cc92356d6bf49406 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3971,7 +3971,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 
 				if (mo)
 				{
-					if (color < 0 || color >= MAXTRANSLATIONS)
+					if (color < 0 || color >= numskincolors)
 						return;
 
 					var1 = 0;
diff --git a/src/p_user.c b/src/p_user.c
index c6e49ef69ec22267baeeca8a8e85e50e3473ba7c..4b2849b1c1d39dddfbfd46be13e893565c786564 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1916,7 +1916,7 @@ void P_SpawnShieldOrb(player_t *player)
 		shieldobj->colorized = true;
 	}
 	else
-		shieldobj->color = (UINT8)shieldobj->info->painchance;
+		shieldobj->color = (UINT16)shieldobj->info->painchance;
 	shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK);
 
 	if (shieldobj->info->seestate)
@@ -2986,7 +2986,7 @@ static void P_CheckInvincibilityTimer(player_t *player)
 		return;
 
 	if (mariomode && !player->powers[pw_super])
-		player->mo->color = (UINT8)(SKINCOLOR_RUBY + (leveltime % (numskincolors - SKINCOLOR_RUBY))); // Passes through all saturated colours
+		player->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (numskincolors - SKINCOLOR_RUBY))); // Passes through all saturated colours
 	else if (leveltime % (TICRATE/7) == 0)
 	{
 		mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_IVSP);
diff --git a/src/r_draw.c b/src/r_draw.c
index 8f5d483150e1b1ff5c0509f1558757914017acde..5351ef37f079b151a0c5c3effd5fe3d006109783 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -184,7 +184,7 @@ void R_InitTranslationTables(void)
 	\param	dest_colormap	colormap to populate
 	\param	skincolor		translation color
 */
-static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor)
+static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor)
 {
 	INT32 i;
 	RGBA_t color;
@@ -226,7 +226,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor)
 
 #undef SETBRIGHTNESS
 
-static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color)
+static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color)
 {
 	INT32 i, starttranscolor, skinramplength;
 
@@ -419,9 +419,9 @@ void R_FlushTranslationColormapCache(void)
 			memset(translationtablecache[i], 0, MAXSKINCOLORS * sizeof(UINT8**));
 }
 
-UINT8 R_GetColorByName(const char *name)
+UINT16 R_GetColorByName(const char *name)
 {
-	UINT16 color = (UINT8)atoi(name);
+	UINT16 color = (UINT16)atoi(name);
 	if (color > 0 && color < numskincolors)
 		return color;
 	for (color = 1; color < numskincolors; color++)
@@ -430,7 +430,7 @@ UINT8 R_GetColorByName(const char *name)
 	return SKINCOLOR_GREEN;
 }
 
-UINT8 R_GetSuperColorByName(const char *name)
+UINT16 R_GetSuperColorByName(const char *name)
 {
 	UINT16 i, color = SKINCOLOR_SUPERGOLD1;
 	char *realname = Z_Malloc(MAXCOLORNAME+1, PU_STATIC, NULL);
diff --git a/src/r_draw.h b/src/r_draw.h
index 6a021fe393f1c82b550af9e3b55a8472af71c7c9..329c4974a6ca722322fb754fd3faf90e6cd92e13 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -114,8 +114,8 @@ extern lumpnum_t viewborderlump[8];
 void R_InitTranslationTables(void);
 UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags);
 void R_FlushTranslationColormapCache(void);
-UINT8 R_GetColorByName(const char *name);
-UINT8 R_GetSuperColorByName(const char *name);
+UINT16 R_GetColorByName(const char *name);
+UINT16 R_GetSuperColorByName(const char *name);
 
 // Custom player skin translation
 void R_InitViewBuffer(INT32 width, INT32 height);
diff --git a/src/r_skins.c b/src/r_skins.c
index caf1fb17299dc0cbad0352df4fa8ec5b71b79ef4..57ce382c4183618a66dde1c45a0874b48d5a7535 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -248,7 +248,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 {
 	player_t *player = &players[playernum];
 	skin_t *skin = &skins[skinnum];
-	UINT8 newcolor = 0;
+	UINT16 newcolor = 0;
 
 	if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists!
 	{
diff --git a/src/r_skins.h b/src/r_skins.h
index 96697b4220038c1bdbe491cbd4943b2b4127113b..45c90bdb4b9e5964547c579abcbdd3d80ed91162 100644
--- a/src/r_skins.h
+++ b/src/r_skins.h
@@ -65,9 +65,9 @@ typedef struct
 
 	// Definable color translation table
 	UINT8 starttranscolor;
-	UINT8 prefcolor;
-	UINT8 supercolor;
-	UINT8 prefoppositecolor; // if 0 use tables instead
+	UINT16 prefcolor;
+	UINT16 supercolor;
+	UINT16 prefoppositecolor; // if 0 use tables instead
 
 	fixed_t highresscale; // scale of highres, default is 0.5
 	UINT8 contspeed; // continue screen animation speed
diff --git a/src/v_video.c b/src/v_video.c
index 1e550fe9d4c488bb0f03456485956f06bfa03da0..5a985555fdd854d593480a145e600254dfd52171 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1040,7 +1040,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
 // V_DrawContinueIcon
 // Draw a mini player!  If we can, that is.  Otherwise we draw a star.
 //
-void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor)
+void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor)
 {
 	if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CONTINUE)
 	{
diff --git a/src/v_video.h b/src/v_video.h
index 664fa8995fa47b9cfc7720f1d67ff17c580b1be3..9f7a9a9e9c29dd8fb23ecfbfb4d1d09d1d7cba8d 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -160,7 +160,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
 void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap);
 void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
 
-void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor);
+void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor);
 
 // Draw a linear block of pixels into the view buffer.
 void V_DrawBlock(INT32 x, INT32 y, INT32 scrn, INT32 width, INT32 height, const UINT8 *src);
diff --git a/src/y_inter.c b/src/y_inter.c
index a2628832fe09074bc77817604e3d72f16f49ea6d..2fe0de60519b7b965387dabd6f42912825d0a4f8 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -99,7 +99,7 @@ typedef union
 		UINT8 continues;
 		patch_t *pcontinues;
 		INT32 *playerchar; // Continue HUD
-		UINT8 *playercolor;
+		UINT16 *playercolor;
 
 		UINT8 gotlife; // Number of extra lives obtained
 	} spec;
@@ -107,7 +107,7 @@ typedef union
 	struct
 	{
 		UINT32 scores[MAXPLAYERS]; // Winner's score
-		UINT8 *color[MAXPLAYERS]; // Winner's color #
+		UINT16 *color[MAXPLAYERS]; // Winner's color #
 		boolean spectator[MAXPLAYERS]; // Spectator list
 		INT32 *character[MAXPLAYERS]; // Winner's character #
 		INT32 num[MAXPLAYERS]; // Winner's player #
@@ -121,7 +121,7 @@ typedef union
 
 	struct
 	{
-		UINT8 *color[MAXPLAYERS]; // Winner's color #
+		UINT16 *color[MAXPLAYERS]; // Winner's color #
 		INT32 *character[MAXPLAYERS]; // Winner's character #
 		INT32 num[MAXPLAYERS]; // Winner's player #
 		char name[MAXPLAYERS][9]; // Winner's name