local function lightLoad()
	for p in players.iterate do
		p.lightenergy = 0
	end

	for s in sectors.iterate do
		s.lightlevel = 150
	end
end

local function lightThinker()	
	server.lightsectors = $ or {}

	if (leveltime == 8*TICRATE) then
		server.lightTimer = 120*TICRATE
		S_ChangeMusic("LIGHT")
		showMusicCredit()
	end

	local playersLeft = {}
	for p in players.iterate
		if validP(p) and not p.boxdata.out then
			table.insert(playersLeft, p)
		end
	end

	if not (leveltime%350) and (leveltime > 6*TICRATE) then
		server.lightsectors = {}

		local sectorNums = {}
		for s in sectors.iterate do
			s.lightlevel = 150
			table.insert(sectorNums, s)
		end

		local sector
		for i = 1, max(3, #playersLeft/2) do
			sector = sectorNums[P_RandomRange(1, #sectorNums)]
			server.lightsectors[#server.lightsectors+1] = sector
		end
	end

	if not (leveltime%700) and (leveltime > 6*TICRATE) then
		local possiblePlayers = {}

		for p in players.iterate
			if validP(p) then table.insert(possiblePlayers, p.mo) end
		end

		local tmo = possiblePlayers[P_RandomRange(1, #possiblePlayers)]
		local item = P_SpawnMobj(tmo.x+P_RandomRange(-3000, 3000)<<FRACBITS, tmo.y+P_RandomRange(-3000, 3000)<<FRACBITS, tmo.ceilingz-P_RandomRange(0, 150)<<FRACBITS, MT_RANDOMITEM)
		item.flags = $ & ~MF_NOGRAVITY & ~MF_NOCLIPHEIGHT & ~MF_SLIDEME
	end

	if server.lightsectors and #server.lightsectors then
		local sector
		for i = 1, #server.lightsectors do
			sector = server.lightsectors[i]
			if sector and sector.valid then sector.lightlevel = min(255, $+2) end

			for p in players.iterate do
				if validP(p) and p.mo and p.mo.valid and p.mo.subsector.sector and p.mo.subsector.sector == sector then
					if not (leveltime%17) then p.lightenergy = $+1 end
					local spark = P_SpawnMobj(p.mo.x + P_RandomRange(-64, 64)*FRACUNIT, p.mo.y + P_RandomRange(-64, 64)*FRACUNIT, p.mo.z + P_RandomRange(0, 64)*FRACUNIT, MT_SUPERSPARK)
				end
			end
		end
	end
	
	if server.lightTimer
		server.lightTimer = $-1
		
		if server.lightTimer <= 0 then
			for p in players.iterate
				if validP(p) then p.marescore = p.lightenergy end
			end
			
			BX_EndBattle()
		end
	end
end

local function lightPThink(p)
	if p.kartstuff[k_spinouttimer] and not p.paincheck then
		local ghost = P_SpawnGhostMobj(p.mo)
		ghost.destscale = 5*FRACUNIT

		P_InstaThrust(p.mo, p.mo.stunangle or p.mo.angle+ANGLE_180, 100*FRACUNIT)
		p.kartstuff[k_spinouttimer] = 69

		if (p.mo.eflags & MFE_JUSTBOUNCEDWALL) then
			p.mo.stunangle = nil
			p.kartstuff[k_spinouttimer] = 5*TICRATE
			p.paincheck = 10*TICRATE
		end
	end

	if p.paincheck then p.paincheck = $-1 end

	if not (leveltime%10)
		for p in players.iterate do p.marescore = p.lightenergy end
	end
end

local function lightPush(p, inf, src)
	if p.mo and p.mo.valid then
		local ang = p.mo.angle+ANGLE_180
		if inf and inf.valid then
			ang = R_PointToAngle2(inf.x, inf.y, p.mo.x, p.mo.y)
		end

		p.mo.stunangle = ang
		p.kartstuff[k_spinouttimer] = 69 -- nice
		S_StartSound(p.mo, sfx_pstop)
	end

	return false
end

local function lightHUD(v, p, c)
	if server and server.lightTimer and p and p.valid and not p.spectator then
		local t = server.lightTimer
		v.drawString(150, 0, G_TicsToMinutes(t)..":"..G_TicsToSeconds(t).." left", V_SNAPTOTOP|V_SNAPTOLEFT, "center")
		v.drawString(150, 10, (tostring(p.lightenergy) or "0").."% light energy", V_SNAPTOTOP|V_SNAPTOLEFT, "center")
	end
end

local function lightReset()
	server.lightsectors = nil
	server.lightTimer = nil

	for p in players.iterate do
		p.lightenergy = nil
	end
end

Box.Gamemodes[GM_LIGHT] = {
	name = "Light Collector",
	hint = "Collect as much light as possible!",
	noBumpers = true,

	loadFunc = lightLoad,
	thinker = lightThinker,
	playerthinker = lightPThink,
	spinoutfunc = lightPush,
	squishfunc = lightPush,
	explodefunc = lightPush,
	resetfunc = lightReset,
	hudfunc = lightHUD,
}