// ------------------------------------------
// Lua_SecondColor
// Secondary customizable color!
// ------------------------------------------
local g_secondcolorchars = {
	["elfilin"] = g_elfilinoverlaycolors,
}

// Sprite to overlay sprite table
local g_overlaysprites = {
	// N/A
}

// -----------------------------------------------------------------------------
// Starting here, nothing else needs to be modified for your character to work
// -----------------------------------------------------------------------------
// Overlay object!
// Uses a global variable to store the object number, so there's only one object no matter how many sc characters you have.
// Different versions of second color will use different objects (and therefore globals)
// to ensure characters with different versions are still compatable with eachother.
if(overlayobj_v2 == nil)
	freeslot("MT_SECONDCOLOROVERLAY_V2")
	rawset(_G, "overlayobj_v2", MT_SECONDCOLOROVERLAY_V2)
	mobjinfo[overlayobj_v2].doomednum = -1
	mobjinfo[overlayobj_v2].spawnstate = S_PLAY_STND
	mobjinfo[overlayobj_v2].spawnhealth = 1
	mobjinfo[overlayobj_v2].seestate = S_PLAY_WALK
	mobjinfo[overlayobj_v2].seesound = sfx_none
	mobjinfo[overlayobj_v2].reactiontime = 0
	mobjinfo[overlayobj_v2].attacksound = sfx_thok
	mobjinfo[overlayobj_v2].painstate = S_PLAY_PAIN
	mobjinfo[overlayobj_v2].painchance = MT_THOK
	mobjinfo[overlayobj_v2].painsound = sfx_none
	mobjinfo[overlayobj_v2].meleestate = S_NULL
	mobjinfo[overlayobj_v2].missilestate = S_NULL
	mobjinfo[overlayobj_v2].deathstate = S_PLAY_PAIN
	mobjinfo[overlayobj_v2].xdeathstate = S_NULL
	mobjinfo[overlayobj_v2].deathsound = sfx_none
	mobjinfo[overlayobj_v2].speed = 1
	mobjinfo[overlayobj_v2].radius = 16*FRACUNIT
	mobjinfo[overlayobj_v2].height = 48*FRACUNIT
	mobjinfo[overlayobj_v2].dispoffset = 0
	mobjinfo[overlayobj_v2].mass = 1000
	mobjinfo[overlayobj_v2].damage = MT_THOK
	mobjinfo[overlayobj_v2].activesound = sfx_none
	mobjinfo[overlayobj_v2].flags = MF_NOGRAVITY|MF_NOCLIPTHING
	mobjinfo[overlayobj_v2].raisestate = MT_THOK
	
	// Remove the overlay when we no longer need it!
	addHook("MobjThinker", function(scoverlay)
		scoverlay.tics = $1 + 1
		if(scoverlay.timer)
			scoverlay.timer = $1 - 1
		else
			P_RemoveMobj(scoverlay)
		end
	end, overlayobj_v2)
end

// Set state without calling the state's action
local function SetStateSafe(mobj, state, player)
	local defaultaction = states[state].action
	states[state].action = nil
	mobj.state = state
	states[state].action = defaultaction
end

// Get second color for skincolor
local function GetSecondColor(skin, color)
	if(g_secondcolorchars[skin][color] != nil)
		return g_secondcolorchars[skin][color]
	elseif(color >= 0 and color < MAXSKINCOLORS and color != SKINCOLOR_NONE)
		return ColorOpposite(color)
	end
	return color
end

// Extra objects in Mario blocks break things... So don't make overlays there!
local function CheckInMarioBlock(mobj)
	if not(mobj.subsector and mobj.subsector.valid)
		return false
	end
	local sector = mobj.subsector.sector
	local i = 0
	while(sector.lines[i] and sector.lines[i].valid)
		if(sector.lines[i].special == 250)	// Special 250 = Mario block
			return true
		end
		i = $1 + 1
	end
	return false
end

// Merge tables
local function MergeTable(dst, src)
	for k,v in pairs(src)
		dst[k] = v
	end
end

// -------------------------------------------
// Overlay function
// -------------------------------------------
local function DoSecondColorOverlay(mobj, slopestick, addtotarget)
	if(CheckInMarioBlock(mobj))
		if(mobj.scoverlay and mobj.scoverlay.valid)
			P_RemoveMobj(mobj.scoverlay)
			mobj.scoverlay = nil
		end
		return
	end
	
	// Ensure overlay
	if not(mobj.scoverlay and mobj.scoverlay.valid)
		mobj.scoverlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, overlayobj_v2)
	end
	mobj.scoverlay.timer = 1
	
	// Pick mobj to match with
	local matchmobj
	if(addtotarget)
		if(mobj.target and mobj.target.valid)
			matchmobj = mobj.target
		end
	else
		matchmobj = mobj
	end
	if not(matchmobj and matchmobj.valid)
		return
	end
	mobj.scoverlay.tracer = matchmobj
	
	// Pick matching color
	local matchcolor
	if(mobj.colorized)
		matchcolor = mobj.color
	elseif(mobj.player and mobj.player.valid and mobj.player.scoverlaycol)
		matchcolor = mobj.player.overlaycol
	else
		matchcolor = GetSecondColor(mobj.skin, mobj.color)
	end
	
	// Deduce height offset
	local offsetheight = 0
	if(addtotarget)
		if(states[mobj.state].var2)
			offsetheight = states[mobj.state].var2*FRACUNIT*P_MobjFlip(matchmobj)
		else
			offsetheight = states[mobjinfo[matchmobj.type].seestate].var2*FRACUNIT*P_MobjFlip(matchmobj)
		end
	end
	
	// Deduce flags
	local matchfflags = FF_TRANSMASK
	local matchflags2 = MF2_DONTDRAW|MF2_OBJECTFLIP
	local matcheflags = MFE_VERTICALFLIP
	if(leveltime or mobj.type != MT_PLAYER)
		matchflags2 = $1|MF2_SHADOW		// Fixes weird bug... Don't apply MF2_SHADOW in this case!
	end
	
	// Match overlay to target object!
	P_MoveOrigin(mobj.scoverlay, mobj.x, mobj.y, matchmobj.z + offsetheight)
	mobj.scoverlay.skin = mobj.skin
	SetStateSafe(mobj.scoverlay, mobj.state, mobj.player)
	mobj.scoverlay.frame = mobj.frame
	mobj.scoverlay.tics = mobj.tics
	mobj.scoverlay.anim_duration = mobj.anim_duration
	if(g_overlaysprites[mobj.sprite])
		mobj.scoverlay.sprite = g_overlaysprites[mobj.sprite]
	end
	mobj.scoverlay.sprite = mobj.sprite
	mobj.scoverlay.sprite2 = mobj.sprite2|FF_SPR2SUPER
	mobj.scoverlay.momx = matchmobj.momx
	mobj.scoverlay.momy = matchmobj.momy
	mobj.scoverlay.momz = matchmobj.momz
	if(matchmobj.player and matchmobj.player.valid)
		mobj.scoverlay.angle = matchmobj.player.drawangle
	else
		mobj.scoverlay.angle = matchmobj.angle
	end
	mobj.scoverlay.scale = matchmobj.scale
	mobj.scoverlay.radius = matchmobj.radius
	mobj.scoverlay.height = matchmobj.height
	mobj.scoverlay.rollangle = matchmobj.rollangle
	mobj.scoverlay.spritexoffset = matchmobj.spritexoffset
	mobj.scoverlay.spriteyoffset = matchmobj.spriteyoffset
	mobj.scoverlay.spritexscale = matchmobj.spritexscale
	mobj.scoverlay.spriteyscale = matchmobj.spriteyscale
	mobj.scoverlay.color = matchcolor
	mobj.scoverlay.colorized = mobj.colorized
	mobj.scoverlay.flags2 = ($1 & ~matchflags2) | (mobj.flags2 & matchflags2)
	mobj.scoverlay.eflags = ($1 & ~matcheflags) | (mobj.eflags & matcheflags)
	if not(slopestick)
		mobj.scoverlay.flags = $1|MF_NOCLIP|MF_NOCLIPHEIGHT
	end
	
	// Don't draw if we aren't actually supposed to match
	if not(mobj.sprite == SPR_PLAY or g_overlaysprites[mobj.sprite])
		mobj.scoverlay.flags2 = $1|MF2_DONTDRAW
	end
end

// -------------------------------------------
// Adding overlays to objects!
// -------------------------------------------
// Players
addHook("PreThinkFrame", function()
	for player in players.iterate
		if(player.mo and player.mo.valid and player.mo.prevspr2)
			player.mo.sprite2 = player.mo.prevspr2
			player.mo.prevspr2 = nil
		end
	end
end)
addHook("PostThinkFrame", function()
	for player in players.iterate
		if(player.mo and player.mo.valid and g_secondcolorchars[player.mo.skin])
			DoSecondColorOverlay(player.mo, true, false)
			player.mo.prevspr2 = player.mo.sprite2
			player.mo.sprite2 = $1 & !FF_SPR2SUPER	// Just in case
		end
	end
end)
addHook("MapLoad", function()
	for player in players.iterate
		if(player.mo and player.mo.valid and g_secondcolorchars[player.mo.skin])
			DoSecondColorOverlay(player.mo, true, false)
			player.mo.prevspr2 = player.mo.sprite2
			player.mo.sprite2 = $1 & !FF_SPR2SUPER	// Just in case
		end
	end
end)
addHook("PlayerSpawn", function(player)
	if(player.mo and player.mo.valid and g_secondcolorchars[player.mo.skin])
		DoSecondColorOverlay(player.mo, true, false)
		player.mo.prevspr2 = player.mo.sprite2
		player.mo.sprite2 = $1 & !FF_SPR2SUPER	// Just in case
	end
end)

// Ghosts
addHook("MobjThinker", function(ghost)
	if(ghost and ghost.valid and g_secondcolorchars[ghost.skin])
		DoSecondColorOverlay(ghost, false, false)
		ghost.sprite2 = $1 & !FF_SPR2SUPER	// Just in case
	end
end, MT_GHOST)
addHook("MobjFuse", function(ghost)
	if(ghost and ghost.valid and g_secondcolorchars[ghost.skin])
		and(ghost.scoverlay and ghost.scoverlay.valid)
		P_RemoveMobj(ghost.scoverlay)	// Make sure to remove it properly so it doesn't linger 1 frame after
	end
end, MT_GHOST)

// Signposts (and 1-up monitors for normal SRB2)
local g_queuedforoverlay = {}
local g_numqueued = 0
addHook("MobjThinker", function(overlay)
	if(g_secondcolorchars[overlay.skin])
		and(overlay.target and overlay.target.valid)
		g_queuedforoverlay[g_numqueued] = overlay
		g_numqueued = $1 + 1
		overlay.overlaydone = false
	elseif(overlay.scoverlay)
		P_RemoveMobj(overlay.scoverlay)
		overlay.scoverlay = nil
	end
end, MT_OVERLAY)

addHook("PostThinkFrame", function()
	local i = 0
	while(i < g_numqueued)
		if(g_queuedforoverlay[i] and g_queuedforoverlay[i].valid)
			// Signpost hack
			if(g_queuedforoverlay[i].sprite2 == SPR2_SIGN)
				g_queuedforoverlay[i].frame = B|($1 & !FF_FRAMEMASK)	// Use the right frame
			end
			
			// Do overlay
			if not(g_queuedforoverlay[i].overlaydone)
				DoSecondColorOverlay(g_queuedforoverlay[i], false, true)
			end
			g_queuedforoverlay[i].overlaydone = true
		end
		i = $1 + 1
	end
	g_queuedforoverlay = {}
	g_numqueued = 0
end)

// -------------------------------------------
// Adding overlays to HUD elements!
// -------------------------------------------
// Fake gametyperankings! Yay! Not exposed to Lua :)
// Can be modified by other add-ons. In addition to this, I'll likely add some existing custom gametypes to this here eventually...
if not(g_secondcolorgametyperankings)
	rawset(_G, "g_secondcolorgametyperankings", {})
end
MergeTable(g_secondcolorgametyperankings, {
	[GT_COOP] = GT_COOP,
	[GT_COMPETITION] = GT_COMPETITION,
	[GT_RACE] = GT_RACE,
	[GT_MATCH] = GT_MATCH,
	[GT_TEAMMATCH] = GT_TEAMMATCH,
	[GT_TAG] = GT_TAG,
	[GT_HIDEANDSEEK] = GT_HIDEANDSEEK,
	[GT_CTF] = GT_CTF,
})

// HUD related console vars
local compactscore = CV_FindVar("compactscoreboard")

// -------------------------------------------
// Life icon
// -------------------------------------------
// TODO: Broken on mobile, for some reason...
local function SecondColorHUD(v, player, cam)
	if not(player.mo and player.mo.valid)
		or not(g_secondcolorchars[player.mo.skin])
		or not(g_secondcolorchars[player.mo.skin].usehud)
		or not(hud.enabled("lives"))	// Need something to append!
		or(mapheaderinfo[gamemap].typeoflevel & TOL_NIGHTS)			// NiGHTs HUD
		or(gamemap >= sstage_start and gamemap <= sstage_end)		// Special stages also use NiGHTs HUD
		or(gamemap >= smpstage_start and gamemap <= smpstage_end)	// Including MP, of course
		return
	end
	
	local livesx = hudinfo[HUD_LIVES].x	// NOTE: This is incorrect on mobile!
	local livesy = hudinfo[HUD_LIVES].y	// Why?
	local toflags = hudinfo[HUD_LIVES].f|V_HUDTRANS|V_PERPLAYER
	local overlaypatch = v.getSprite2Patch(player.mo.skin, SPR2_XTRA, true, A)
	local matchcolor
	if(player.mo.colorized)
		matchcolor = player.mo.color
	elseif(player.scoverlaycol)
		matchcolor = player.overlaycol
	else
		matchcolor = GetSecondColor(player.mo.skin, player.mo.color)
	end
	local colormap = v.getColormap(player.mo.skin, matchcolor)
	v.drawScaled(livesx*FRACUNIT, livesy*FRACUNIT, FRACUNIT>>1, overlaypatch, toflags, colormap)
end
hud.add(SecondColorHUD, "game")

// -------------------------------------------
// Teams/Scores icon
// -------------------------------------------
// TODO: Port C functions for remaining teams/scores sizes
local function DoGreyCheck(player)
	if(player.spectator)
		or(player.playerstate == PST_DEAD)
		or(G_IsSpecialStage(gamemap) and player.exiting)
		return true
	end
	return false
end

local function DoSuperCheck(player)
	if(player.powers[pw_super] and player.mo and player.mo.valid and (player.mo.state < S_PLAY_SUPER_TRANS1 or player.mo.state > S_PLAY_SUPER_TRANS6))
		or(player.powers[pw_carry] == CR_NIGHTSMODE and skins[player.skin].flags & SF_SUPER)
		return true
	end
	return false
end

// Function to append second color graphics to extended team rankings
local function SecondColor32TeamRankings(tab, whiteplayer)
/*
	INT32 i,x,y;
	INT32 redplayers = 0, blueplayers = 0;
	const UINT8 *colormap;
	char name[MAXPLAYERNAME+1];
	boolean greycheck, supercheck;

	V_DrawFill(160, 26, 1, 154, 0); //Draw a vertical line to separate the two teams.
	V_DrawFill(1, 26, 318, 1, 0); //And a horizontal line to make a T.
	V_DrawFill(1, 180, 318, 1, 0); //And a horizontal line near the bottom.

	for (i = 0; i < MAXPLAYERS; i++)
	{
		if (players[tab[i].num].spectator)
			continue; //ignore them.

		greycheck = greycheckdef;
		supercheck = supercheckdef;

		if (tab[i].color == skincolor_redteam) //red
		{
			redplayers++;
			x = 14 + (BASEVIDWIDTH/2);
			y = (redplayers * 9) + 20;
		}
		else if (tab[i].color == skincolor_blueteam) //blue
		{
			blueplayers++;
			x = 14;
			y = (blueplayers * 9) + 20;
		}
		else //er?  not on red or blue, so ignore them
			continue;

		greycheck = greycheckdef;
		supercheck = supercheckdef;

		strlcpy(name, tab[i].name, 8);
		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
			V_DrawString(x + 10, y,
			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
			             | (greycheck ? 0 : V_TRANSLUCENT)
			             | V_ALLOWLOWERCASE, name);

		if (gametyperules & GTR_TEAMFLAGS)
		{
			if (players[tab[i].num].gotflag & GF_REDFLAG) // Red
				V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, rflagico, 0);
			else if (players[tab[i].num].gotflag & GF_BLUEFLAG) // Blue
				V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, bflagico, 0);
		}

		// Draw emeralds
		if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1))
		{
			HU_Draw32Emeralds(x+60, y+2, 255);
			//HU_DrawEmeralds(x-12,y+2,255);
		}
		else if (!players[tab[i].num].powers[pw_super]
			|| ((leveltime/7) & 1))
		{
			HU_Draw32Emeralds(x+60, y+2, tab[i].emeralds);
			//HU_DrawEmeralds(x-12,y+2,tab[i].emeralds);
		}

		if (supercheck)
		{
			colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
			V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], colormap);
		}
		else
		{
			colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
			if (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD)
				V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, V_HUDTRANSHALF, faceprefix[players[tab[i].num].skin], colormap);
			else
				V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, faceprefix[players[tab[i].num].skin], colormap);
		}
		V_DrawRightAlignedThinString(x+128, y, ((players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
		if (!splitscreen)
		{
			if (tab[i].num != serverplayer)
				HU_drawPing(x + 135, y+1, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], true, 0);
			//else
				//V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
		}
	}
*/
end

// Function to append second color graphics to team rankings
local function SecondColorTeamRankings(v, tab, whiteplayer)
/*
	INT32 i,x,y;
	INT32 redplayers = 0, blueplayers = 0;
	boolean smol = false;
	const UINT8 *colormap;
	char name[MAXPLAYERNAME+1];
	boolean greycheck, supercheck;

	// before we draw, we must count how many players are in each team. It makes an additional loop, but we need to know if we have to draw a big or a small ranking.
	for (i = 0; i < MAXPLAYERS; i++)
	{
		if (players[tab[i].num].spectator)
			continue; //ignore them.

		if (tab[i].color == skincolor_redteam) //red
		{
			if (redplayers++ > 8)
			{
				smol = true;
				break; // don't make more loops than we need to.
			}
		}
		else if (tab[i].color == skincolor_blueteam) //blue
		{
			if (blueplayers++ > 8)
			{
				smol = true;
				break;
			}
		}
		else //er?  not on red or blue, so ignore them
			continue;

	}

	// I'll be blunt with you, this may add more lines, but I'm not adding weird cases for this, so we're executing a separate function.
	if (smol == true || cv_compactscoreboard.value)
	{
		HU_Draw32TeamTabRankings(tab, whiteplayer);
		return;
	}

	V_DrawFill(160, 26, 1, 154, 0); //Draw a vertical line to separate the two teams.
	V_DrawFill(1, 26, 318, 1, 0); //And a horizontal line to make a T.
	V_DrawFill(1, 180, 318, 1, 0); //And a horizontal line near the bottom.

	i=0, redplayers=0, blueplayers=0;

	for (i = 0; i < MAXPLAYERS; i++)
	{
		if (players[tab[i].num].spectator)
			continue; //ignore them.

		if (tab[i].color == skincolor_redteam) //red
		{
			if (redplayers++ > 8)
				continue;
			x = 32 + (BASEVIDWIDTH/2);
			y = (redplayers * 16) + 16;
		}
		else if (tab[i].color == skincolor_blueteam) //blue
		{
			if (blueplayers++ > 8)
				continue;
			x = 32;
			y = (blueplayers * 16) + 16;
		}
		else //er?  not on red or blue, so ignore them
			continue;

		greycheck = greycheckdef;
		supercheck = supercheckdef;

		strlcpy(name, tab[i].name, 7);
		V_DrawString(x + 20, y,
		             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
		             | (greycheck ? V_TRANSLUCENT : 0)
		             | V_ALLOWLOWERCASE, name);

		if (gametyperules & GTR_TEAMFLAGS)
		{
			if (players[tab[i].num].gotflag & GF_REDFLAG) // Red
				V_DrawSmallScaledPatch(x-28, y-4, 0, rflagico);
			else if (players[tab[i].num].gotflag & GF_BLUEFLAG) // Blue
				V_DrawSmallScaledPatch(x-28, y-4, 0, bflagico);
		}

		// Draw emeralds
		if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1))
			HU_DrawEmeralds(x-12,y+2,255);
		else if (!players[tab[i].num].powers[pw_super]
			|| ((leveltime/7) & 1))
		{
			HU_DrawEmeralds(x-12,y+2,tab[i].emeralds);
		}

		if (supercheck)
		{
			colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
			V_DrawSmallMappedPatch (x, y-4, 0, superprefix[players[tab[i].num].skin], colormap);
		}
		else
		{
			colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
			if (greycheck)
				V_DrawSmallTranslucentMappedPatch (x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin], colormap);
			else
				V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
		}
		V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
		if (!splitscreen)
		{
			if (!(tab[i].num == serverplayer || players[tab[i].num].quittime))
				HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0);
		//else
		//	V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");
		}
	}
}
*/
end

// Function to append second color graphics to general, compact rankings
local function SecondColorRankings(v, x, y, tab, scorelines, whiteplayer)
	local greycheck
	local supercheck

	//this function is designed for 9 or less score lines only
	if(scorelines > 9)
		return
	end

	local i = 0
	while(i < scorelines)
		if(players[tab[i].num].spectator)
			and(g_secondcolorgametyperankings[gametype] != GT_COOP)
			i = $1 + 1
			continue //ignore them.
		end

		local skin = skins[players[tab[i].num].skin].name

		if not(g_secondcolorchars[skin])
			or not(g_secondcolorchars[skin].usehud)
			y = $1 + 16
			i = $1 + 1
			continue
		end

		greycheck = DoGreyCheck(players[tab[i].num])
		supercheck = DoSuperCheck(players[tab[i].num])
		
		local color
		if(players[tab[i].num].mo and players[tab[i].num].mo.valid)
			local matchcolor
			if(players[tab[i].num].mo.colorized)
				matchcolor = players[tab[i].num].mo.color
			elseif(players[tab[i].num].scoverlaycol)
				matchcolor = players[tab[i].num].overlaycol
			else
				GetSecondColor(skin, players[tab[i].num].mo.color)
			end
			color = GetSecondColor(skin, players[tab[i].num].mo.color)
		else
			color = GetSecondColor(skin, tab[i].color)
		end
		local scpatch = v.getSprite2Patch(skin, SPR2_XTRA, true, A)

		if(tab[i].color == 0)
			if(greycheck and not supercheck)
				v.drawScaled(x*FRACUNIT, (y-4)*FRACUNIT, FRACUNIT/2, scpatch, V_80TRANS)
			else
				v.drawScaled(x*FRACUNIT, (y-4)*FRACUNIT, FRACUNIT/2, scpatch, 0)
			end
		else
			local colormap = v.getColormap(skin, color)
			if(greycheck and not supercheck)
				v.drawScaled(x*FRACUNIT, (y-4)*FRACUNIT, FRACUNIT/2, scpatch, V_80TRANS, colormap)
			else
				v.drawScaled(x*FRACUNIT, (y-4)*FRACUNIT, FRACUNIT/2, scpatch, 0, colormap)
			end
		end

		y = $1 + 16
		i = $1 + 1
	end
end

// Function to append second color graphics to do
local function SecondColorDualRankings(v, x, y, tab, scorelines, whiteplayer)
/*
	INT32 i;
	const UINT8 *colormap;
	char name[MAXPLAYERNAME+1];
	boolean greycheck, supercheck;

	V_DrawFill(160, 26, 1, 154, 0); //Draw a vertical line to separate the two sides.
	V_DrawFill(1, 26, 318, 1, 0); //And a horizontal line to make a T.
	V_DrawFill(1, 180, 318, 1, 0); //And a horizontal line near the bottom.

	for (i = 0; i < scorelines; i++)
	{
		if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
			continue; //ignore them.

		greycheck = greycheckdef;
		supercheck = supercheckdef;

		strlcpy(name, tab[i].name, 7);
		if (tab[i].num != serverplayer)
			HU_drawPing(x+ 113, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0);
		//else
		//	V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER");

		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
			V_DrawString(x + 20, y,
			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
			             | (greycheck ? V_TRANSLUCENT : 0)
			             | V_ALLOWLOWERCASE, name);

		if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
			V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives));
		else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
			V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);

		if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
			V_DrawSmallScaledPatch(x - exiticon->width/2 - 1, y-3, 0, exiticon);

		// Draw emeralds
		if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1))
			HU_DrawEmeralds(x-12,y+2,255);
		else if (!players[tab[i].num].powers[pw_super]
			|| ((leveltime/7) & 1))
		{
			HU_DrawEmeralds(x-12,y+2,tab[i].emeralds);
		}

		//V_DrawSmallScaledPatch (x, y-4, 0, livesback);
		if (tab[i].color == 0)
		{
			colormap = colormaps;
			if (supercheck)
				V_DrawSmallScaledPatch (x, y-4, 0, superprefix[players[tab[i].num].skin]);
			else
			{
				if (greycheck)
					V_DrawSmallTranslucentPatch (x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin]);
				else
					V_DrawSmallScaledPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]);
			}
		}
		else
		{
			if (supercheck)
			{
				colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
				V_DrawSmallMappedPatch (x, y-4, 0, superprefix[players[tab[i].num].skin], colormap);
			}
			else
			{
				colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
				if (greycheck)
					V_DrawSmallTranslucentMappedPatch (x, y-4, V_80TRANS, faceprefix[players[tab[i].num].skin], colormap);
				else
					V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap);
			}
		}

		// All data drawn with thin string for space.
		if (gametyperankings[gametype] == GT_RACE)
		{
			if (circuitmap)
			{
				if (players[tab[i].num].exiting)
					V_DrawRightAlignedThinString(x+146, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
				else
					V_DrawRightAlignedThinString(x+146, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
			}
			else
				V_DrawRightAlignedThinString(x+146, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
		}
		else
			V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));

		y += 16;
		if (y > 160)
		{
			y = 32;
			x += BASEVIDWIDTH/2;
		}
	}
*/
end

// Function to append second color graphics to extended rankings
local function SecondColor32Rankings(v, x, y, tab, scorelines, whiteplayer)
/*
	INT32 i;
	const UINT8 *colormap;
	char name[MAXPLAYERNAME+1];
	boolean greycheck, supercheck;

	V_DrawFill(160, 26, 1, 154, 0); //Draw a vertical line to separate the two sides.
	V_DrawFill(1, 26, 318, 1, 0); //And a horizontal line to make a T.
	V_DrawFill(1, 180, 318, 1, 0); //And a horizontal line near the bottom.

	for (i = 0; i < scorelines; i++)
	{
		if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
			continue; //ignore them.

		greycheck = greycheckdef;
		supercheck = supercheckdef;

		strlcpy(name, tab[i].name, 7);
		if (!splitscreen) // don't draw it on splitscreen,
		{
			if (tab[i].num != serverplayer)
				HU_drawPing(x+ 135, y+1, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], true, 0);
			//else
			//	V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST");
		}

		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
			V_DrawString(x + 10, y,
			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
			             | (greycheck ? 0 : V_TRANSLUCENT)
			             | V_ALLOWLOWERCASE, name);

		if (G_GametypeUsesLives()) //show lives
			V_DrawRightAlignedThinString(x-1, y, V_ALLOWLOWERCASE, va("%d", players[tab[i].num].lives));
		else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
			V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, tagico, 0);

		// Draw emeralds
		if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1))
		{
			HU_Draw32Emeralds(x+60, y+2, 255);
			//HU_DrawEmeralds(x-12,y+2,255);
		}
		else if (!players[tab[i].num].powers[pw_super]
			|| ((leveltime/7) & 1))
		{
			HU_Draw32Emeralds(x+60, y+2, tab[i].emeralds);
			//HU_DrawEmeralds(x-12,y+2,tab[i].emeralds);
		}

		//V_DrawSmallScaledPatch (x, y-4, 0, livesback);
		if (tab[i].color == 0)
		{
			colormap = colormaps;
			if (players[tab[i].num].powers[pw_super] && !(players[tab[i].num].charflags & SF_NOSUPERSPRITES))
				V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], 0);
			else
			{
				if (greycheck)
					V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, V_HUDTRANSHALF, faceprefix[players[tab[i].num].skin], 0);
				else
					V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, faceprefix[players[tab[i].num].skin], 0);
			}
		}
		else
		{
			if (supercheck)
			{
				colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
				V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], colormap);
			}
			else
			{
				colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE);
				if (greycheck)
					V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, V_HUDTRANSHALF, faceprefix[players[tab[i].num].skin], colormap);
				else
					V_DrawFixedPatch(x*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, faceprefix[players[tab[i].num].skin], colormap);
			}
		}

		// All data drawn with thin string for space.
		if (gametyperankings[gametype] == GT_RACE)
		{
			if (circuitmap)
			{
				if (players[tab[i].num].exiting)
					V_DrawRightAlignedThinString(x+128, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
				else
					V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
			}
			else
				V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
		}
		else
			V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));

		y += 9;
		if (i == 16)
		{
			y = 32;
			x += BASEVIDWIDTH/2;
		}
	}
*/
end

// Scores HUD hook
local function SecondColorScores(v)
	if not(hud.enabled("rankings"))	// Need something to append!
		or not(multiplayer)
		return
	end
	
	local maxplay = 32	// MAXPLAYERS
	local tab = {}	// [MAXPLAYERS]		Was playersort_t... check what that does!
	local i
	local j
	local completed = {}	// [MAXPLAYERS]
	local whiteplayer
	local scorelines = 0

	// When you play, you quickly see your score because your name is displayed in white.
	// When playing back a demo, you quickly see who's the view.
	if(demoplayback)	// Not exposed to Lua... oh well? We don't really need this information anyway
		whiteplayer = displayplayer
	else
		whiteplayer = consoleplayer
	end
	
	i = 0
	while(i < maxplay)
		tab[i] = {
			count = 0,
			num = 0,
			color = 0,
			emeralds = 0,
			name = nil,
		}
		completed[i] = false
		i = $1 + 1
	end

	i = 0
	while(i < maxplay)
		tab[i].num = -1
		tab[i].name = nil	// Was set to 0, this was originally a pointer. So its nil now.

		if(g_secondcolorgametyperankings[gametype] == GT_RACE and not circuitmap)
			tab[i].count = 0x7FFFFFFF	// INT32_MAX
		end
		
		i = $1 + 1
	end

	j = 0
	while(j < maxplay)
	//	if not(playeringame[j])		// NOT EXPOSED TO LUA!!!!!!
		if not(players[j] and players[j].valid)	// I *think* this is what "playeringame" represents? But I'm not 100% sure...
			j = $1 + 1
			continue
		end

		if(G_PlatformGametype() == false and players[j].spectator)
			j = $1 + 1
			continue
		end

		i = 0
		while(i < maxplay)
		//	if not(playeringame[i])	// NOT EXPOSED TO LUA!!!!!!!!!!!!!!!!!!!!!
			if not(players[i] and players[i].valid)
				i = $1 + 1
				continue
			end

			if(G_PlatformGametype() == false and players[i].spectator)
				i = $1 + 1
				continue
			end

			if(g_secondcolorgametyperankings[gametype] == GT_RACE)
				if(circuitmap)
					if(players[i].laps+1 >= tab[scorelines].count and completed[i] == false)
						tab[scorelines].count = players[i].laps+1
						tab[scorelines].num = i
						tab[scorelines].color = players[i].skincolor
						tab[scorelines].name = players[i].name
					end
				else
					if(players[i].realtime <= tab[scorelines].count and completed[i] == false)
						tab[scorelines].count = players[i].realtime
						tab[scorelines].num = i
						tab[scorelines].color = players[i].skincolor
						tab[scorelines].name = players[i].name
					end
				end
			elseif(g_secondcolorgametyperankings[gametype] == GT_COMPETITION)
				// todo put something more fitting for the gametype here, such as current
				// number of categories led
				if(players[i].score >= tab[scorelines].count and completed[i] == false)
					tab[scorelines].count = players[i].score
					tab[scorelines].num = i
					tab[scorelines].color = players[i].skincolor
					tab[scorelines].name = players[i].name
					tab[scorelines].emeralds = players[i].powers[pw_emeralds]
				end
			else
				if(players[i].score >= tab[scorelines].count and completed[i] == false)
					tab[scorelines].count = players[i].score
					tab[scorelines].num = i
					tab[scorelines].color = players[i].skincolor
					tab[scorelines].name = players[i].name
					tab[scorelines].emeralds = players[i].powers[pw_emeralds]
				end
			end
			
			i = $1 + 1
		end
		
		completed[tab[scorelines].num] = true
		scorelines = $1 + 1
		j = $1 + 1
	end

	//if(scorelines > 20)
	//	scorelines = 20 //dont draw past bottom of screen, show the best only
	//end
	// shush, we'll do it anyway.

	if(G_GametypeHasTeams())
		SecondColorTeamRankings(v, tab, whiteplayer)
	elseif(scorelines <= 9 and not compactscore.value)
		SecondColorRankings(v, 40, 32, tab, scorelines, whiteplayer)
	elseif(scorelines <= 20 and not compactscore.value)
		SecondColorDualRankings(v, 32, 32, tab, scorelines, whiteplayer)
	else
		SecondColor32Rankings(v, 14, 28, tab, scorelines, whiteplayer)
	end
end
hud.add(SecondColorScores, "scores")
