--------------------------------------------------------
-- Sonic Robo Blast 2 v2.2.4
-- Custom Gametype - Last Man Standing
-- By Lucario - The Aura Pokemon
--------------------------------------------------------

-- Version check
if (CODEBASE < 220) or ((CODEBASE == 220) and (SUBVERSION < 4))
	error("Required SRB2 v2.2.4 in orden to use this addon. Please update your game.", 0)
	return
end

-- Version
local version = "1.1"

-- Already defined
if lms
	assert((lms.version == version), string.format("Multiple Last Man Standing versions loaded! (Actual %d, tried to load %d).", lms.version, version))
	print("Last Man Standing is already loaded.")
	S_StartSound(nil, sfx_adderr)
	return
end

/* DEFINITION START */
rawset(_G, "lms", {})
lms.version = version

-- Variables
local BLUETEAMTEXT = "\x84" .. "Blue Team" .. "\x80"
local REDTEAMTEXT = "\x85" .. "Red Team" .. "\x80"
local BLUETEXT = "\x84" .. "Blue" .. "\x80"
local REDTEXT = "\x85" .. "Red" .. "\x80"

-- Console variables
lms.cv_countdown = CV_RegisterVar({name = "lms_countdown", defaultvalue = "30", flags = CV_NETVAR, possiblevalue = {MIN = 5, MAX = 90}})
lms.cv_timelimit = CV_RegisterVar({name = "lms_timelimit", defaultvalue = "3", flags = CV_NETVAR, possiblevalue = {MIN = 0, MAX = 30}})
lms.cv_intermission = CV_RegisterVar({name = "lms_intermission", defaultvalue = "10", flags = CV_NETVAR, possiblevalue = {MIN = 10, MAX = 60}})
lms.cv_minplayers = CV_RegisterVar({name = "lms_minplayers", defaultvalue = "2", flags = CV_NETVAR, possiblevalue = {MIN = 1, MAX = 32}})
lms.cv_suddendeath = CV_RegisterVar({name = "lms_suddendeath", defaultvalue = "Yes", flags = CV_NETVAR, possiblevalue = CV_YesNo})
lms.cv_debug = CV_RegisterVar({name = "lms_debug", defaultvalue = "Off", flags = CV_NETVAR|CV_NOSHOWHELP, possiblevalue = CV_OnOff})

/* GAMETYPE START */
-- Gametype
G_AddGametype({
	name = "Last Man Standing",
	identifier = "lms",
	typeoflevel = TOL_MATCH,
	rules = GTR_DEATHMATCHSTARTS|GTR_FIRSTPERSON|GTR_RINGSLINGER|GTR_SPECTATORS|GTR_NOSPECTATORSPAWN,
	intermissiontype = int_match,
	headercolor = 44,
	description = "One life, no power-ups and no abilities. Be the Last Man Standing."
})

G_AddGametype({
	name = "Last Team Standing",
	identifier = "teamlms",
	typeoflevel = TOL_MATCH,
	rules = GTR_DEATHMATCHSTARTS|GTR_FIRSTPERSON|GTR_RINGSLINGER|GTR_SPECTATORS|GTR_NOSPECTATORSPAWN|GTR_TEAMS,
	intermissiontype = int_match,
	headerleftcolor = 156,
	headerrightcolor = 44,
	description = "One life, no power-ups, no abilities and with your mates. Be the Last Team Standing."
})
/* GAMETYPE EMD */
/* DEFINITION END */

/* FUNCTIONS START */
-- Colored player name
local function lmsPlayerName(player)
	return "\x80" .. P_SkincolorToText(player.skincolor) .. player.name .. "\x80"
end

-- Red Team count
local function lmsRedTeamCount()
	if (gametype ~= GT_TEAMLMS) return 0 end

	local count = 0
	for player in players.iterate
		if (player.lms_eliminated ~= nil)
			if not player.spectator
				if (player.ctfteam == 1)
					if not player.lms_eliminated
						count = $ + 1
					end
				end
			end
		end
	end
	return count
end

-- Blue Team count
local function lmsBlueTeamCount()
	if (gametype ~= GT_TEAMLMS) return 0 end

	local count = 0
	for player in players.iterate
		if (player.lms_eliminated ~= nil)
			if not player.spectator
				if (player.ctfteam == 2)
					if not player.lms_eliminated
						count = $ + 1
					end
				end
			end
		end
	end
	return count
end

-- Player count
local function lmsPlayerCount()
	if (gametype ~= GT_LMS) return 0 end

	local count = 0
	for player in players.iterate
		if (player.lms_eliminated ~= nil)
			if not player.spectator
				if not player.lms_eliminated
					count = $ + 1
				end
			end
		end
	end
	return count
end

-- Spectator count
local function lmsSpectatorCount()
	if (gametype ~= GT_LMS) and (gametype ~= GT_TEAMLMS) return 0 end
	
	local count = 0
	for player in players.iterate
		if (player.lms_eliminated ~= nil)
			if player.spectator and not (player.quittime > 0)
				if not player.lms_eliminated
					count = $ + 1
				end
			end
		end
	end
	return count
end

-- Red Team enough
local function lmsRedTeamEnough()
	if (gametype ~= GT_TEAMLMS) return false end

	if (lmsRedTeamCount() >= (lms.cv_minplayers.value / 2))
		return true
	end
	return false
end

-- Blue Team enough
local function lmsBlueTeamEnough()
	if (gametype ~= GT_TEAMLMS) return false end

	if (lmsBlueTeamCount() >= (lms.cv_minplayers.value / 2))
		return true
	end
	return false
end

-- Player enough
local function lmsPlayerEnough()
	if (gametype ~= GT_LMS) return false end

	if (lmsPlayerCount() >= lms.cv_minplayers.value)
		return true
	end
	return false
end

-- Blue Team unbalanced
local function lmsBlueTeamUnbalanced()
	if (gametype ~= GT_TEAMLMS) return false end

	if (CV_FindVar("autobalance").value == 0) return false end
	if (lmsBlueTeamCount() >= (lms.cv_minplayers.value / 2)) and (lmsBlueTeamCount() > (lmsRedTeamCount() + (CV_FindVar("autobalance").value + 1)))
		return true
	end
	return false
end

-- Red Team unbalanced
local function lmsRedTeamUnbalanced()
	if (gametype ~= GT_TEAMLMS) return false end

	if (CV_FindVar("autobalance").value == 0) return false end
	if (lmsRedTeamCount() >= (lms.cv_minplayers.value / 2)) and (lmsRedTeamCount() > (lmsBlueTeamCount() + (CV_FindVar("autobalance").value + 1)))
		return true
	end
	return false
end

-- Teleport player
local function lmsTeleportPlayer(player, mobj)
	player.playerstate = PST_REBORN
	P_TeleportMove(player.mo, mobj.x << FRACBITS, mobj.y << FRACBITS, mobj.z << FRACBITS)
	player.mo.angle = FixedAngle(mobj.angle << FRACBITS)
	player.mo.momx, player.mo.momy, player.mo.momz = 0, 0, 0
end

-- Respawn player
local function lmsRespawnPlayer(player)
	local playerspawns = {}
	local startnum = 0
	for spawns in mapthings.iterate
		if (spawns.type == startnum)
			table.insert(playerspawns, spawns)
		end
	end
	
	if (#playerspawns > 0)
		local destination = playerspawns[P_RandomRange(1, #playerspawns)]
		if (destination ~= nil)
			lmsTeleportPlayer(player, destination)
		else
			CONS_Printf(player, "Something went wrong, teleport failure!")
		end
	else
		CONS_Printf(player, "Not found spawns, teleport failure!")
	end
	player.powers[pw_flashing] = 2
end
/* FUNCTIONS END */

/* HOOKS START*/
/* NETPLAY START */
-- Team change
local DELAY = 0 -- This is for "cannot join", "cannot change team" and "cannot became spectator" message for get spammed
addHook("TeamSwitch", function (player, team, fromspectators, autobalance, scramble)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	if server.lms_started and (autobalance or scramble) return false end
	
	if not server.lms_started and not lms.cv_debug.value
		if (gametype == GT_TEAMLMS)
			if ((team == 2) and lmsBlueTeamUnbalanced()) or ((team == 1) and lmsRedTeamUnbalanced())
				if not DELAY
					chatprintf(player, "\x82" .. "* You can't change teams due team unbalancing.", true)
				end
				DELAY = 2
				return false
			end
		end
	elseif server.lms_started and not lms.cv_debug.value
		if not DELAY
			if fromspectators
				chatprintf(player, "\x82" .. "* You can't join until round ends.", true)
			else
				if (team ~= 0)
					chatprintf(player, "\x82" .. "* You can't change teams until round ends.", true)
				else
					chatprintf(player, "\x82" .. "* You can't became spectator until round ends.", true)
				end
			end
		end
		DELAY = 2
		return false
	end
	return
end)
addHook("ThinkFrame", do if DELAY DELAY = $ - 1 end end)

-- No spectator view player
addHook("ViewpointSwitch", function (player, viewplayer, force)
	if (gametype ~= GT_LMS) and (gametype ~= GT_TEAMLMS) return end
	if lms.cv_debug.value return end
	return false
end)

-- Hurt message
addHook("HurtMsg", function (player, inflictor, source)
	return true
end)

-- Player Message
addHook("PlayerMsg", function (source, type, target, message)
	if (gametype ~= GT_LMS) and (gametype ~= GT_TEAMLMS) return end
	if lms.cv_debug.value return end
	if not server.lms_started or server.lms_finished return end
	if (type == 3) return end
	
	local prefix = ((source == server) and "\x82" .. "~") or (IsPlayerAdmin(source) and "\x82" .. "@") or ""
	if (type == 0) or (type == 1)
		if not source.spectator
			if (gametype == GT_TEAMLMS)
				if not source.lms_teamchat
					chatprintf(source, "\x82" .. "* Remember that your messages are only visible to your teammates.", true)
					source.lms_teamchat = true
				end
				for player in players.iterate
					if (player.ctfteam == source.ctfteam)
						chatprintf(player, prefix .. ((source.ctfteam == 1) and "\x85" or "\x84") .. "[TEAM] " .. source.name .. "\x80" .. ": " .. message, true)
					end
				end
			else
				chatprintf(source, "\x82" .. "* Chatting is disabled!", true)
			end
		elseif source.spectator
			if not source.lms_specchat
				chatprintf(source, "\x82" .. "* Remember that your messages are only visible to others spectators.", true)
				source.lms_specchat = true
			end
			for player in players.iterate
				if (player.spectator == source.spectator)
					chatprintf(player, prefix .. "\x86" .. source.name .. "\x80" .. ": " .. message, true)
				end
			end
		end
	elseif (type == 2)
		chatprintf(source, "\x82" .. "* Private chatting is not allowed!", true)
	end
	return true
end)
/* NETPLAY END */

/* PLAYER ABILITIES START */
-- Avoid character abilities
local function lmsNoAbilities(player)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	if lms.cv_debug.value return end
	return true
end
addHook("AbilitySpecial", lmsNoAbilities)
addHook("JumpSpinSpecial", lmsNoAbilities)
addHook("SpinSpecial", lmsNoAbilities)
/* PLAYER ABILITIES END */

/* MOBJ START */
-- Deleting things
addHook("MapThingSpawn", function (mobj)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	if (mobj.type == MT_RAILRING) or (mobj.type == MT_RAILPICKUP) or (mobj.flags & MF_MONITOR)
		P_RemoveMobj(mobj)
	end
end)

-- Can't touch this before round starts
local lmsNoTouch = {
	MT_RING, MT_FLINGRING, MT_CORK, MT_LHRT, MT_REDRING, MT_BOUNCERING, MT_INFINITYRING, MT_AUTOMATICRING,
	MT_EXPLOSIONRING, MT_SCATTERRING, MT_GRENADERING, MT_RAILRING, MT_BOUNCEPICKUP, MT_AUTOPICKUP, MT_EXPLODEPICKUP,
	MT_SCATTERPICKUP, MT_GRENADEPICKUP, MT_RAILPICKUP, MT_THROWNBOUNCE, MT_THROWNINFINITY, MT_THROWNAUTOMATIC,
	MT_THROWNSCATTER, MT_THROWNEXPLOSION, MT_THROWNGRENADE,
}

-- Colliding objects
addHook("TouchSpecial", function (special, toucher)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	if (toucher and toucher.valid and toucher.player)
		if not (server.lms_started and not server.lms_finished and (not server.lms_usetime or (server.lms_usetime and not (server.lms_timelimit < 1))))
			for index = 1, #lmsNoTouch
				if (special.type == lmsNoTouch[index])
					return true
				end
			end
		end
	end
	return
end)

-- Player Death
addHook("MobjDeath", function (mobj, inflictor, source, amount)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	if server.lms_ended return end
	
	if mobj and mobj.valid and mobj.player
		if (not server.lms_started or server.lms_finished)
			if mobj.player.mo and not mobj.player.spectator
				lmsRespawnPlayer(mobj.player)
			end
			return true
		elseif (server.lms_started and not server.lms_finished) and not lms.cv_debug.value
			if not mobj.player.spectator
				if not mobj.player.lms_eliminated		
					mobj.player.lms_eliminated = true
					chatprint(lmsPlayerName(mobj.player) .. "\x80" .. " was eliminated.")
				end
			end
		end
	end
	return
end, MT_PLAYER)

-- Player Spawn
addHook("PlayerSpawn", function(player)
	if (gametype ~= GT_LMS) and (gametype ~= GT_TEAMLMS) return end

	if server.lms_started and not server.lms_finished
		if (player.jointime < 2)
			player.spectator = true
			player.lms_eliminated = false
			player.lms_specchat = false
			player.lms_teamchat = false
		elseif player.lms_eliminated and not lms.cv_debug.value
			player.spectator = true
			player.lms_eliminated = true
			player.lms_specchat = false
			player.lms_teamchat = true
		end
	end
end)

-- Player Think
addHook("PlayerThink", function(player)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS)
		if player.lms_skinmodded
			if player.mo and not player.spectator
				player.lms_skinmodded = false
				player.charability = skins[player.mo.skin].ability
				player.charability2 = skins[player.mo.skin].ability2
				player.charflags = skins[player.mo.skin].flags
			end
		end
		return
	end
	
	-- Avoid keepbody
	if (player.quittime > 0)
		if not player.spectator
			player.spectator = true
		end
	end

	-- Reset
	if (player.lms_eliminated == nil)
		player.lms_eliminated = false
		player.lms_time = 0
		player.lms_idletime = 0
		player.lms_specchat = false
		player.lms_skinmodded = false
	end

	-- Special
	if server.lms_started and not server.lms_finished and not (player.playerstate == PST_DEAD) and not player.lms_eliminated
		if (player.powers[pw_flashing] > ((TICRATE / 2) + (TICRATE / 4))) and not (player.powers[pw_flashing] == flashingtics)
			player.powers[pw_flashing] = (TICRATE / 2) + (TICRATE / 4)
		end
		player.powers[pw_noautobrake] = TICRATE
		
		if (player.speed < (4 * FRACUNIT))
			player.lms_idletime = $ + 1
			if (player.lms_idletime >= (5 * TICRATE)) and ((player.lms_idletime % TICRATE) == 0)
				S_StartSound(player.mo, sfx_gbeep)
				for a = 1, 32
					local effects = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_SPARK)
					effects.momx = player.mo.momx
					effects.momy = player.mo.momy
					effects.momz = player.mo.momz
					P_Thrust(effects, ANGLE_11hh * a, 64 * FRACUNIT)
				end
			end
		else
			player.lms_idletime = 0
		end
	end
	
	-- No abilities
	if player.mo and not player.spectator
		if (player.charability ~= CA_NONE) player.charability = CA_NONE end
		if (player.charability2 ~= CA2_NONE) player.charability2 = CA2_NONE end
		if (player.charflags & SF_DASHMODE) player.dashmode = 0 end
		if not (player.charflags & SF_NOJUMPDAMAGE) player.charflags = $ | SF_NOJUMPDAMAGE end
		if not (player.charflags & SF_NOJUMPSPIN) player.charflags = $ | SF_NOJUMPSPIN end
		player.lms_skinmodded = true
	end
end)

-- local in_range = (thing.z > (tmthing.z - tmthing.height)) and not (thing.z > (tmthing.z + tmthing.height))
-- local in_rangeZ = (tmthing.z < (thing.z + thing.height)) and ((tmthing.z + tmthing.height) > thing.z)
/* MOBJ END */

local lmsInvisible = {
	MT_RING, MT_CORK, MT_LHRT, MT_REDRING, MT_BOUNCERING, MT_INFINITYRING, MT_AUTOMATICRING,
	MT_EXPLOSIONRING, MT_SCATTERRING, MT_GRENADERING, MT_RAILRING, MT_BOUNCEPICKUP, MT_AUTOPICKUP, MT_EXPLODEPICKUP,
	MT_SCATTERPICKUP, MT_GRENADEPICKUP, MT_RAILPICKUP, MT_THROWNBOUNCE, MT_THROWNINFINITY, MT_THROWNAUTOMATIC,
	MT_THROWNSCATTER, MT_THROWNEXPLOSION, MT_THROWNGRENADE,
}

/* MAIN START */
-- Setup
addHook("MapChange", do
	hud.enable("score")
	hud.enable("time")
	hud.enable("rings")
	hud.enable("rankings")
	hud.enable("intermissiontally")
	hud.enable("lives")
	hud.enable("teamscores")
	hud.enable("textspectator")
	
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	
	-- Server
	server.lms_countdown = lms.cv_countdown.value * TICRATE
	server.lms_timelimit = lms.cv_timelimit.value * (60 * TICRATE)
	server.lms_intermission = lms.cv_intermission.value * TICRATE
	server.lms_winnername = "Nobody"
	server.lms_winnernamecolor = "\x80"
	server.lms_started = false
	server.lms_finished = false
	server.lms_ended = false
	server.lms_usetime = (lms.cv_timelimit.value > 0) and true or false
	server.lms_suddendeath = lms.cv_suddendeath.value
	
	-- Players
	for player in players.iterate		
		player.lms_eliminated = false
		player.lms_time = 0
		player.lms_idletime = 0
		player.lms_specchat = false
		player.lms_skinmodded = false
	end
end)

-- Main Thinker
addHook("ThinkFrame", do
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	
	-- Disable vanilla hud
	hud.disable("score")
	hud.disable("time")
	hud.disable("rings")
	hud.disable("intermissiontally")
	hud.disable("lives")
	hud.disable("teamscores")
	hud.disable("textspectator")
	hud.disable("weaponrings")
	hud.disable("rankings")
	
	if not server.lms_started and not server.lms_finished -- Waiting
		for player in players.iterate
			if player.mo and not player.spectator
				player.powers[pw_flashing] = 2
			end
		end
		
		if (server.lms_countdown ~= nil)
			if ((gametype == GT_TEAMLMS) and ((lmsRedTeamEnough() and lmsBlueTeamEnough()) and not (lmsRedTeamUnbalanced() and lmsBlueTeamUnbalanced()))) or ((gametype == GT_LMS) and lmsPlayerEnough())
				server.lms_countdown = $ - 1
				if (server.lms_countdown < 1)
					server.lms_started = true
					server.lms_timelimit = lms.cv_timelimit.value * (60 * TICRATE)
					server.lms_usetime = (lms.cv_timelimit.value > 0) and true or false
					server.lms_suddendeath = lms.cv_suddendeath.value
					for player in players.iterate
						if player.mo and not player.spectator
							lmsRespawnPlayer(player)
						end
					end
					chatprint("\x82" .. "* Normal chatting is disabled until round ends.", true)
				end
			else
				if server.lms_countdown ~= (lms.cv_countdown.value * TICRATE)
					server.lms_countdown = (lms.cv_countdown.value * TICRATE)
				end
			end
		end
	elseif server.lms_started and not server.lms_finished -- Underway
		hud.enable("weaponrings")
	
		-- End condition
		if (((gametype == GT_TEAMLMS) and (((lmsBlueTeamCount() < 1) or (lmsRedTeamCount() < 1)))) or ((gametype == GT_LMS) and (lmsPlayerCount() <= 1))) and not lms.cv_debug.value
			if (gametype == GT_TEAMLMS)
				if (lmsRedTeamCount() < 1)
					server.lms_winnernamecolor = "\x84"
					server.lms_winnername = "Blue Team"
				elseif (lmsBlueTeamCount() < 1)
					server.lms_winnernamecolor = "\x85"
					server.lms_winnername = "Red Team"
				end
			elseif (gametype == GT_LMS)
				for player in players.iterate
					if player.mo and not player.spectator
						if not player.lms_eliminated
							server.lms_winnernamecolor = P_SkincolorToText(player.skincolor)
							server.lms_winnername = player.name
						end
					end
				end
			end
			server.lms_finished = true
			server.lms_intermission = (lms.cv_intermission.value * TICRATE)
			chatprint("\x82" .. "* Normal chatting is enabled.", true)
			chatprint(server.lms_winnernamecolor .. server.lms_winnername  .. "\x80" .. " wins.", true)
		end
	
		-- Timelimit and sudden-death
		if server.lms_usetime
			server.lms_timelimit = $ - 1
			if (server.lms_timelimit < 1)
				if (server.lms_timelimit == 0)
					if server.lms_suddendeath
						for player in players.iterate
							if player.mo and not player.spectator
								lmsRespawnPlayer(player)
							end
						end
						chatprint("\x82" .. "* Extra 30 seconds before round ends.", true)
					else
						server.lms_finished = true
						server.lms_intermission = (lms.cv_intermission.value * TICRATE)
						chatprint("\x82" .. "* Normal chatting is enabled.", true)
						chatprint(server.lms_winnernamecolor .. server.lms_winnername  .. "\x80" .. " wins.", true)
					end
				end
				
				if server.lms_suddendeath
					-- Infinite ammo
					for player in players.iterate
						if player.mo and not player.spectator
							if not player.lms_eliminated
								player.rings = 0
								player.ringweapons = 0
								player.powers[pw_infinityring] = 999
							end
						end
					end
					
					-- Kill players
					if (abs(server.lms_timelimit) == (30 * TICRATE))
						for player in players.iterate
							if player.mo and not player.spectator
								if not player.lms_eliminated
									P_KillMobj(player.mo, nil, nil)
								end
							end
						end
					end
				end
			end
		end
		
		-- Player alive time
		for player in players.iterate
			if (player.lms_time == nil) player.lms_time = 0 end
			if player.mo and not player.spectator
				if not player.lms_eliminated
					if (player.lms_time ~= nil)
						player.lms_time = $ + 1
					end
				end
			end
		end
	elseif server.lms_finished -- Finish
		server.lms_intermission = $ - 1
		if (server.lms_intermission < 1)
			G_ExitLevel()
			
			if not server.lms_ended -- Final
				server.lms_started = false
				server.lms_finished = false
				server.lms_ended = true
			end
		end
		
		for player in players.iterate
			if player.mo and not player.spectator
				player.powers[pw_flashing] = 2
			end
		end
	end
end)
/* MAIN END */
/* HOOKS END */

/* HUD START */
-- Zeroes
local function hudPadZeroes(num)
	if (num < 10) return "0" .. tostring(num) end
	return tostring(num)
end

-- Timer
local function hudTicsToTimer(num)
	return G_TicsToMinutes(num, true) .. ":" ..  hudPadZeroes(G_TicsToSeconds(num)) .. "." .. hudPadZeroes(G_TicsToCentiseconds(num))
end

-- Time HUD replica
local function lmsHUDTime(v, offsetx, offsety, tics, flashing)
	local time = ((tics < 0) and 0) or tics
	local flash = ((flashing and "STTRTIME") or "STTTIME")
	local style = CV_FindVar("timerres")
	local timesprite = v.cachePatch(flash)
	local timecolon = v.cachePatch("STTCOLON")
	local timeperiot = v.cachePatch("STTPERIO")
	
	v.draw(hudinfo[HUD_TIME].x + offsetx, hudinfo[HUD_TIME].y + offsety, timesprite, hudinfo[HUD_TIME].f|V_HUDTRANS|V_PERPLAYER)
	if (style.value < 3)
		v.drawNum(hudinfo[HUD_MINUTES].x + offsetx, hudinfo[HUD_MINUTES].y + offsety, G_TicsToMinutes(time, true), hudinfo[HUD_MINUTES].f|V_HUDTRANS|V_PERPLAYER)
		v.draw(hudinfo[HUD_TIMECOLON].x + offsetx, hudinfo[HUD_TIMECOLON].y + offsety, timecolon, hudinfo[HUD_TIMECOLON].f|V_HUDTRANS|V_PERPLAYER)
		v.drawPaddedNum(hudinfo[HUD_SECONDS].x + offsetx, hudinfo[HUD_SECONDS].y + offsety, G_TicsToSeconds(time), 2, hudinfo[HUD_SECONDS].f|V_HUDTRANS|V_PERPLAYER)
		
		if (style.value > 0)
			v.draw(hudinfo[HUD_TIMETICCOLON].x + offsetx, hudinfo[HUD_TIMETICCOLON].y + offsety, timeperiot, hudinfo[HUD_TIMETICCOLON].f|V_HUDTRANS|V_PERPLAYER)
			v.drawPaddedNum(hudinfo[HUD_TICS].x + offsetx, hudinfo[HUD_TICS].y + offsety, G_TicsToCentiseconds(time), 2, hudinfo[HUD_TICS].f|V_HUDTRANS|V_PERPLAYER)
		end
	else
		v.drawNum(hudinfo[HUD_SECONDS].x + offsetx, hudinfo[HUD_SECONDS].y + offsety, time, hudinfo[HUD_SECONDS].f|V_HUDTRANS|V_PERPLAYER)
	end
end

-- Rings HUD replica
local function lmsHUDRings(v, offsetx, offsety, amount, flashing)
	local rings = ((amount < 0) and 0) or amount
	local flash = ((flashing and "STTRRING") or "STTRINGS")
	local ringssprite = v.cachePatch(flash)
	local style = CV_FindVar("timerres")
	local position = (style.value == 2) and HUD_RINGSNUMTICS or HUD_RINGSNUM
	
	v.draw(hudinfo[HUD_RINGS].x + offsetx, hudinfo[HUD_RINGS].y + offsety, ringssprite, hudinfo[HUD_RINGS].f|V_HUDTRANS|V_PERPLAYER)
	v.drawNum(hudinfo[position].x + offsetx, hudinfo[position].y + offsety, rings, hudinfo[position].f|V_HUDTRANS|V_PERPLAYER)
end

-- Character icon HUD
local function lmsHUDCharacter(v, player)
	local color = v.getColormap(player.skin, player.skincolor)
	local colortext = P_SkincolorToText(player.skincolor)
	local trans = V_HUDTRANS
	local iconback = v.cachePatch("STLIVEBK")
	local skin = CV_FindVar("skin")
	local icon = v.getSprite2Patch(skins[skin.string].name, SPR2_XTRA, false, A)
	
	if not (player.mo and not player.spectator)
		color = v.getColormap(nil, SKINCOLOR_WHITE)
		colortext = "\x86"
		trans = V_HUDTRANSHALF
	end
	
	if (not splitscreen)
		v.drawScaled(hudinfo[HUD_LIVES].x * FRACUNIT, hudinfo[HUD_LIVES].y * FRACUNIT, FRACUNIT / 2, iconback, hudinfo[HUD_LIVES].f|V_HUDTRANS|V_PERPLAYER, color)
		v.drawScaled(hudinfo[HUD_LIVES].x * FRACUNIT, hudinfo[HUD_LIVES].y * FRACUNIT, FRACUNIT / 2, icon, hudinfo[HUD_LIVES].f|trans|V_PERPLAYER, color)
	end
	v.drawString(hudinfo[HUD_LIVES].x + 20, hudinfo[HUD_LIVES].y + 5, colortext .. player.name, hudinfo[HUD_LIVES].f|V_ALLOWLOWERCASE|V_HUDTRANS|V_PERPLAYER, "thin")
end

-- Main HUD
hud.add(function (v, player, camera)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	
	local offset = 0
	
	-- Time
	local time_flasher = ((leveltime % 10) >= 5)
	local time_tics = (not server.lms_started and server.lms_countdown) or ((server.lms_started and (player.lms_time ~= nil) and not server.lms_usetime) and player.lms_time) or ((server.lms_started and server.lms_usetime and not server.lms_suddendeath and not (server.lms_timelimit < 1)) and max(server.lms_timelimit, 0)) or ((server.lms_started and server.lms_usetime and (server.lms_timelimit < 1)) and max((30 * TICRATE) - abs(server.lms_timelimit), 0)) or 0 --((59940 * TICRATE) + (59 * TICRATE) + 34)
	local time_noplayers = (not server.lms_started and (((gametype == GT_LMS) and not lmsPlayerEnough()) or ((gametype == GT_TEAMLMS) and not (lmsBlueTeamEnough() and lmsRedTeamEnough())))) and true
	local time_starting = ((not server.lms_started and (server.lms_countdown <= (10 * TICRATE)) and time_flasher) and (((gametype == GT_LMS) and lmsPlayerEnough()) or ((gametype == GT_TEAMLMS) and (lmsBlueTeamEnough() and lmsRedTeamEnough())))) and true
	local time_timelimit = ((server.lms_started and server.lms_usetime and (server.lms_timelimit < (10 * TICRATE))) and time_flasher) or ((server.lms_started and server.lms_usetime and (server.lms_timelimit < 1)) and true) and true
	local time_flash = time_noplayers or time_starting or time_timelimit or false
	lmsHUDTime(v, 0, -16, time_tics, time_flash)
	offset = $ + 16
	
	-- Rings
	if server.lms_started and not server.lms_finished and (not server.lms_usetime or (server.lms_usetime and not (server.lms_timelimit < 1)))
		local rings_flasher = ((leveltime % 10) >= 5)
		local rings_flash = ((player.spectator and true) or (not server.lms_started and true) or ((player.rings < 1) and rings_flasher and true)) or false
		lmsHUDRings(v, 0, -16, (not player.spectator) and player.rings or 0, rings_flash)
		offset = $ + 16
	end
	
	-- Character HUD
	lmsHUDCharacter(v, player)
	
	-- Version
	v.drawString(160, 1, "Last Man Standing v" .. version, V_ALLOWLOWERCASE|V_SNAPTOTOP|V_HUDTRANS|V_PERPLAYER, "thin-center")
	
	-- Debug
	if lms.cv_debug.value
		v.drawString(160, 8, "\x82" .. "Debug Mode", V_ALLOWLOWERCASE|V_SNAPTOTOP|V_HUDTRANS|V_PERPLAYER, "center")
	end
	
	-- Secondary time
	if server.lms_started and server.lms_usetime
		local time = ((player.lms_time == nil) and ("\x86" .. "-:--.--")) or hudTicsToTimer(player.lms_time)
		v.drawString(16, 166, "Time alive: " .. time, V_ALLOWLOWERCASE|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|V_PERPLAYER, "thin")
	end
	
	-- Move around
	if server.lms_started and not server.lms_finished and not (player.playerstate == PST_DEAD)
		if (player.lms_idletime ~= nil)
			if (player.lms_idletime > (5 * TICRATE))
				local color = ((player.lms_idletime % TICRATE) < 2) and V_REDMAP or ((leveltime % 10) >= 5) and V_ORANGEMAP or V_YELLOWMAP
				v.drawString(160, 100, "Move around", color|V_ALLOWLOWERCASE|V_HUDTRANS|V_PERPLAYER, "center")
			end
		end
	end
	
	-- Timelimit
	if server.lms_suddendeath and server.lms_usetime
		if (server.lms_timelimit > 0)
			if (server.lms_timelimit < (10 * TICRATE))
				v.drawString(160, 156, G_TicsToSeconds(server.lms_timelimit) .. " seconds before Sudden-Death", V_REDMAP|V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_HUDTRANS|V_PERPLAYER, "thin-center")
			end
		else
			v.drawString(160, 156, "Sudden-Death", V_REDMAP|V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_HUDTRANS|V_PERPLAYER, "thin-center")
		end
	end
	
	-- Server settings
	if not server.lms_started and not server.lms_finished
		v.drawString(16, 70, "ROUND SETTINGS", V_YELLOWMAP|V_ALLOWLOWERCASE|V_SNAPTOLEFT, "thin")
		v.drawString(16, 80, "Timelimit: " .. "\x82" .. ((lms.cv_timelimit.value and hudTicsToTimer(lms.cv_timelimit.value * 60 * TICRATE)) or "Disabled"), V_ALLOWLOWERCASE|V_SNAPTOLEFT, "thin")
		v.drawString(16, 90, "Sudden-Death: " .. "\x82" .. ((lms.cv_suddendeath.value and "Enabled") or "Disabled"), V_ALLOWLOWERCASE|V_SNAPTOLEFT, "thin")
	end
	
	-- Team state
	if (gametype == GT_TEAMLMS) and displayplayer and displayplayer.valid and not displayplayer.spectator
		local display_teams = (displayplayer.ctfteam == 2) and BLUETEAMTEXT or REDTEAMTEXT
		offset = $ + 8
		v.drawString(16, offset, display_teams, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
	end
	
	-- State
	if not server.lms_started and not server.lms_finished
		if (gametype == GT_TEAMLMS)
			local players_teams = ((not lmsRedTeamEnough() or not lmsBlueTeamEnough()) and "\x87" .. "Not enough players") or (not (lmsRedTeamUnbalanced() and lmsBlueTeamUnbalanced()) and(lmsRedTeamEnough() and lmsBlueTeamEnough()) and "\x82" .. "Starting...") or ((lmsRedTeamUnbalanced() or lmsBlueTeamUnbalanced()) and "\x86" .. "Unbalanced teams!")
			v.drawString(16, 8 + offset, players_teams, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
			
			if (not lmsRedTeamEnough() or not lmsBlueTeamEnough())
				local blueteam_notenough = (not lmsBlueTeamEnough() and "\x82" .. "Need " .. (lms.cv_minplayers.value / 2) .. " players" .. "\x80" .. " (" .. ((lms.cv_minplayers.value / 2) - lmsBlueTeamCount()) .. " players more)")
				local blueteam_ready = ((not lmsBlueTeamUnbalanced()) and "\x83" .. "Ready" .. "\x80" .. " (" .. lmsBlueTeamCount() .. " players)")
				local blueteam_unbalanced = ((lmsBlueTeamUnbalanced()) and "\x86" .. "Unbalanced" .. "\x80" .. " (" .. lmsBlueTeamCount() .. " players)")
				v.drawString(16, 16 + offset, BLUETEXT .. ": " .. (blueteam_notenough or blueteam_ready or blueteam_unbalanced), V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
				
				local redteam_notenough = (not lmsRedTeamEnough() and "\x82" .. "Need " .. (lms.cv_minplayers.value / 2) .. " players" .. "\x80" .. " (" .. ((lms.cv_minplayers.value / 2) - lmsRedTeamCount()) .. " players more)")
				local redteam_ready = ((not lmsRedTeamUnbalanced()) and "\x83" .. "Ready" .. "\x80" .. " (" .. lmsRedTeamCount() .. " players)")
				local redteam_unbalanced = ((lmsRedTeamUnbalanced()) and "\x86" .. "Unbalanced" .. "\x80" .. " (" .. lmsRedTeamCount() .. " players)")
				v.drawString(16, 24 + offset, REDTEXT .. ": " .. (redteam_notenough or redteam_ready or redteam_unbalanced), V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
			end
		else
			local players_single = (not lmsPlayerEnough() and "Not enough players") or (lmsPlayerEnough() and "Starting...")
			v.drawString(16, 8 + offset, players_single, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
			
			if (not lmsPlayerEnough())
				local count_single = "\x82" .. "Need " .. lms.cv_minplayers.value .. " players" .. "\x80" .. " (" .. (lms.cv_minplayers.value - lmsPlayerCount()) .. " players more)"
				v.drawString(16, 16 + offset, count_single, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
			end
		end
	elseif server.lms_started and not server.lms_finished
		local status_single = (displayplayer.lms_eliminated and "\x85" .. "Eliminated") or (displayplayer.spectator and "\x86" .. "Spectator") or "\x83" .. "Still alive"
		v.drawString(16, 8 + offset, status_single, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
		
		if (gametype == GT_TEAMLMS)			
			local alive_blueteam = lmsBlueTeamCount() .. " players alive"
			v.drawString(16, 16 + offset, BLUETEXT .. ": " .. alive_blueteam, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
			
			local alive_redteam = lmsRedTeamCount() .. " players alive"
			v.drawString(16, 24 + offset, REDTEXT .. ": " .. alive_redteam, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
		else			
			local alive_single = lmsPlayerCount() .. " players alive"
			v.drawString(16, 16 + offset, alive_single, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
		end
	elseif server.lms_started and server.lms_finished
		local winner_text = server.lms_winnernamecolor .. server.lms_winnername .. "\x80" .. " wins"
		v.drawString(16, 8 + offset, winner_text, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
		
		local intermission_text = "Intermission in " .. G_TicsToSeconds(server.lms_intermission) .. " seconds"
		v.drawString(16, 16 + offset, intermission_text, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER, "thin")
	end
end)

local spec_offset = 0 -- spectator offsets
local function lmsHUDSpectators(v)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
	
	if (lmsSpectatorCount() > 0)
		local spec_text = "Spectators:" .. "  "
		local spec_length = 0
		
		local spectable = {}
		for specplayer in players.iterate
			if not (specplayer.jointime < 2)
				if (specplayer.spectator and not specplayer.lms_eliminated)
					table.insert(spectable, specplayer)
				end
			end
		end
		
		-- Render players
		if (#spectable > 0)
			for key, specplayer in pairs(spectable)
				spec_text = $ + P_SkincolorToText(specplayer.skincolor) .. specplayer.name .. (((key == #spectable) and "") or "  ")
				spec_length = v.stringWidth(spec_text, 0)
			end
			--print(v.width() / v.dupx())
			spec_offset = $ + 1
			if (spec_offset >= ((v.width() / v.dupx()) + spec_length))
				spec_offset = 0
			end
			
			v.drawString((v.width() / v.dupx()) - spec_offset, 184, spec_text, V_ALLOWLOWERCASE, "thin-center")
		end
	end
end

-- Sort players
local function lmsSortPlayers(a, b)
	return (a.lms_time or 0) > (b.lms_time or 0)
end

-- Rankings
hud.add(function(v)
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end

	-- Timelimit
	if server.lms_started and server.lms_usetime
		v.drawString(8, 1, "Timelimit: " .. ((server.lms_timelimit > 0) and hudTicsToTimer(server.lms_timelimit) or "0:00:00"), V_ALLOWLOWERCASE|V_SNAPTOLEFT, "thin")
	end

	-- Players
	local playertable = {}
	for player in players.iterate
		if not (player.jointime < 2)
			if (not player.spectator) or (player.spectator and player.lms_eliminated)
				table.insert(playertable, player)
			end
		end
	end
	table.sort(playertable, lmsSortPlayers)
	
	
	-- Dividers
	v.drawFill(0, 18, 500, 1, 1|V_SNAPTOLEFT)
	if (#playertable > 16) v.drawFill(162, 19, 1, 161, 1) end
	
	-- Position
	local ypos = 21
	local namepos = 16
	local numberpos = 16 - 2
	local statuspos = ((#playertable > 16) and (namepos + 100)) or namepos + 220
	local timepos = ((#playertable > 16) and (namepos + 142)) or namepos + 288
	local iconflags = V_SNAPTOLEFT
	local nameflags = V_ALLOWLOWERCASE|V_SNAPTOLEFT
	local statflags = V_ALLOWLOWERCASE
	local namestyle = "thin"
	local numberstyle = "thin-right"
	local statstyle = "thin-right"
	local timestyle = "thin-right"
	
	-- Headers
	v.drawString(numberpos, 10, "#", V_ALLOWLOWERCASE|V_SNAPTOLEFT|V_YELLOWMAP, numberstyle)
	v.drawString(namepos, 10, "Player", V_ALLOWLOWERCASE|V_SNAPTOLEFT|V_YELLOWMAP, namestyle)
	v.drawString(statuspos, 10, "Status", V_ALLOWLOWERCASE|V_YELLOWMAP, statstyle)
	v.drawString(timepos, 10, "Time", V_ALLOWLOWERCASE|V_YELLOWMAP, timestyle)
	
	if (#playertable > 16)
		local namepos2 = 16 + 164
		local numberpos2 = namepos2 - 2
		local statuspos2 = namepos2 + 88
		local timepos2 = namepos2 + 130
		v.drawString(numberpos2, 10, "#", V_ALLOWLOWERCASE|V_YELLOWMAP, numberstyle)
		v.drawString(namepos2, 10, "Player", V_ALLOWLOWERCASE|V_YELLOWMAP, namestyle)
		v.drawString(statuspos2, 10, "Status", V_ALLOWLOWERCASE|V_SNAPTORIGHT|V_YELLOWMAP, statstyle)
		v.drawString(timepos2, 10, "Time", V_ALLOWLOWERCASE|V_SNAPTORIGHT|V_YELLOWMAP, timestyle)
	end
	
	-- Render players
	if (#playertable > 0)
		local realrank = 1
		for key, player in pairs(playertable)
			if (key == 17)
				ypos = 21
				namepos = 16 + 164
				statuspos = namepos + 88
				timepos = namepos + 130
				iconflags = 0
				nameflags = V_ALLOWLOWERCASE
				statflags = V_ALLOWLOWERCASE|V_SNAPTORIGHT
			end
			
			local positionrank = realrank or 1
			local rank = positionrank
			local rankcolour = ((((rank == 1) and "\x82") or ((rank == 2) and "\x86") or ((rank == 3) and "\x8D") or ((rank == 4) and "\x89")) or "\x80")
			v.drawString(namepos - 2, ypos + 1, rankcolour .. rank, nameflags, "thin-right")
			
			if (player.lms_time ~= nil) and (player.lms_eliminated ~= nil)
				if (playertable[key + 1])
					if (playertable[key + 1].lms_time ~= nil) and (playertable[key + 1].lms_eliminated ~= nil)
						if (player.lms_time > playertable[key + 1].lms_time)
							realrank = $ + 1
						elseif (playertable[key + 1].lms_eliminated)
							realrank = $ + 1
						end
					end
				end
			end
			
			if player.mo and not player.spectator
				if not player.lms_eliminated
					local icon = v.getSprite2Patch(skins[player.mo.skin].name, SPR2_XTRA, false, A)
					v.drawScaled(namepos * FRACUNIT, ypos * FRACUNIT, FRACUNIT / 4, icon, iconflags, v.getColormap(player.skin, player.skincolor))
				end
			end
			v.drawString(namepos + 12, ypos + 1, lmsPlayerName(player), nameflags, namestyle)
			
			local stat = ((not server.lms_started) and ("\x82" .. "Waiting")) or ((server.lms_started and player.lms_eliminated) and ("\x85" .. "Dead")) or ((server.lms_started and not player.lms_eliminated) and ("\x83" .. "Alive"))
			v.drawString(statuspos, ypos + 1, stat, statflags, statstyle)
			
			local time = ((player.lms_time == nil) and ("\x86" .. "-:--.--")) or hudTicsToTimer(player.lms_time)
			v.drawString(timepos, ypos + 1, time, statflags, timestyle)
			
			ypos = $ + 10
		end
	end
	
	-- Bottom divider
	v.drawFill(0, 180, 500, 1, 1|V_SNAPTOLEFT)
	
	-- Version
	v.drawString(160, 1, "Last Man Standing v" .. version, V_ALLOWLOWERCASE|V_HUDTRANS, "thin-center")
	
	-- Spectators
	lmsHUDSpectators(v)
	
	-- Winner
	if (not server.lms_started and not server.lms_finished)
		if (gametype == GT_TEAMLMS)
			local players_teams = ((not lmsRedTeamEnough() or not lmsBlueTeamEnough()) and "\x87" .. "Not enough players") or (not (lmsRedTeamUnbalanced() and lmsBlueTeamUnbalanced()) and(lmsRedTeamEnough() and lmsBlueTeamEnough()) and "\x82" .. "Starting...") or ((lmsRedTeamUnbalanced() or lmsBlueTeamUnbalanced()) and "\x86" .. "Unbalanced teams!")
			v.drawString(16, 192, players_teams, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT, "thin")
		else
			local players_single = (not lmsPlayerEnough() and "Not enough players") or (lmsPlayerEnough() and "Starting...")
			v.drawString(16, 192, players_single, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT, "thin")
		end
	elseif (server.lms_started and not server.lms_finished)
		local status_single = (displayplayer.lms_eliminated and "\x85" .. "Eliminated") or (displayplayer.spectator and "\x86" .. "Spectator") or "\x83" .. "Still alive"
		v.drawString(16, 192, status_single, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT, "thin")
	elseif (server.lms_started and server.lms_finished)
		local winner_name = server.lms_winnername
		local winner_color = server.lms_winnernamecolor
		local winner_final = winner_color .. winner_name
		local winner_text = winner_final .. "\x80" .. " wins."
		v.drawString(16, 192, winner_text, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOLEFT, "thin")
	end
end, "scores")

-- Intermission
hud.add(function(v)	
	if (gametype ~= GT_LMS and gametype ~= GT_TEAMLMS) return end
		
	-- Players
	local playertable = {}
	for player in players.iterate
		if not (player.jointime < 2)
			if (not player.spectator) or (player.spectator and player.lms_eliminated)
				table.insert(playertable, player)
			end
		end
	end
	table.sort(playertable, lmsSortPlayers)
	
	-- Dividers
	v.drawFill(0, 18, 500, 1, 1|V_SNAPTOLEFT)
	if (#playertable > 16) v.drawFill(162, 19, 1, 161, 1) end
	
	-- Position
	local ypos = 21
	local namepos = 16
	local numberpos = 16 - 2
	local timepos = ((#playertable > 16) and (namepos + 142)) or namepos + 288
	local iconflags = V_SNAPTOLEFT
	local nameflags = V_ALLOWLOWERCASE|V_SNAPTOLEFT
	local statflags = V_ALLOWLOWERCASE
	local numberstyle = "thin-right"
	local namestyle = "thin"
	local timestyle = "thin-right"
	
	-- Headers
	v.drawString(numberpos, 10, "#", V_ALLOWLOWERCASE|V_SNAPTOLEFT|V_YELLOWMAP, numberstyle)
	v.drawString(namepos, 10, "Player", V_ALLOWLOWERCASE|V_SNAPTOLEFT|V_YELLOWMAP, namestyle)
	v.drawString(timepos, 10, "Time", V_ALLOWLOWERCASE|V_YELLOWMAP, timestyle)
	
	if (#playertable > 16)
		local namepos2 = 16 + 164
		local numberpos2 = namepos2 - 2
		local statuspos2 = namepos2 + 88
		local timepos2 = namepos2 + 130
		v.drawString(numberpos2, 10, "#", V_ALLOWLOWERCASE|V_YELLOWMAP, numberstyle)
		v.drawString(namepos2, 10, "Player", V_ALLOWLOWERCASE|V_YELLOWMAP, namestyle)
		v.drawString(timepos2, 10, "Time", V_ALLOWLOWERCASE|V_SNAPTORIGHT|V_YELLOWMAP, timestyle)
	end
	
	-- Render players
	if (#playertable > 0)
		local realrank = 1
		for key, player in pairs(playertable)
			if (key == 17)
				ypos = 21
				namepos = 16 + 168
				statuspos = namepos + 84
				timepos = namepos + 126
				iconflags = 0
				nameflags = V_ALLOWLOWERCASE
				statflags = V_ALLOWLOWERCASE|V_SNAPTORIGHT
			end
			
			local positionrank = realrank or 1
			local rank = positionrank
			local rankcolour = ((((positionrank == 1) and "\x82") or ((positionrank == 2) and "\x86") or ((positionrank == 3) and "\x8D") or ((positionrank == 4) and "\x89")) or "\x80")
			v.drawString(namepos - 2, ypos + 1, rankcolour .. rank, nameflags, "thin-right")
			
			if (player.lms_time ~= nil) and (player.lms_eliminated ~= nil)
				if (playertable[key + 1])
					if (playertable[key + 1].lms_time ~= nil) and (playertable[key + 1].lms_eliminated ~= nil)
						if (player.lms_time > playertable[key + 1].lms_time)
							realrank = $ + 1
						elseif (playertable[key + 1].lms_eliminated)
							realrank = $ + 1
						end
					end
				end
			end
			
			v.drawString(namepos, ypos + 1, lmsPlayerName(player), nameflags, namestyle)
			
			local time = ((player.lms_time == nil) and ("\x86" .. "-:--.--")) or hudTicsToTimer(player.lms_time)
			v.drawString(timepos, ypos + 1, time, statflags, timestyle)
			
			ypos = $ + 10
		end
	end
	
	-- Bottom divider
	v.drawFill(0, 180, 500, 1, 1|V_SNAPTOLEFT)
	
	-- Version
	v.drawString(160, 1, "Last Man Standing v" .. version, V_ALLOWLOWERCASE|V_HUDTRANS, "thin-center")
	
	-- Spectators
	lmsHUDSpectators(v)
	
	-- Winner
	local winner_name = server.lms_winnername
	local winner_color = server.lms_winnernamecolor
	local winner_final = winner_color .. winner_name
	local winner_text = winner_final .. "\x80" .. " wins."
	v.drawString(16, 192, winner_text, V_ALLOWLOWERCASE|V_SNAPTOLEFT, "thin")
end, "intermission")
/* HUD END */