--[[ ringkeep v1.1
Author: birbhorse aka EeveeEuphoria
Thanks: to the SRB2 Discord for lending a hand in some of my Coding Conundrums!

This is a script that changes how you play SRB2, where you keep all your rings between levels, and instead of losing all your rings on hit, you lose a % of them.
The goal is to rack up as many rings as you can, with your high score being tracked!
]]

--[[ TO-DO LIST
	- [ ] add custom feature to make it so when player collects 100/200/300 rings the first time, they get an extra life, but never again after that until they hit 0 rings.
	- [ ] have ring counter clock over back to 0 when you reach 9999, but have the high score saved with multiples of 9999, somehow
	- [ ] test this out in match mode, see how it works and if i can adjust it any 
	- [ ] track misc. stats, like how many rings have been lost in total, how many rings in total were collected, etc.
	- [ ] display ring percent losing rate thing as a HUD element 

]]--

local function readhighscore(lenumber)
	local file = io.openlocal("ringkeep/highscore.txt", "r")
	if file
		local numbertime = file:read("*number")
		file:close()
		return numbertime
	else
		local writethis = io.openlocal("ringkeep/highscore.txt", "w")
		writethis:write(1) -- doesn't work if set to 0
		writethis:close()
		return 1
	end
end

local function writehighscore(lenumber, player)
	local file = io.openlocal("ringkeep/highscore.txt", "r")
	if file
		local compare = file:read("*number")
		if compare and compare < lenumber
			file:close()
			local file = io.openlocal("ringkeep/highscore.txt", "w")
			file:write(lenumber)
			file:close()
			CONS_Printf(player, "\x85\Congrats!\x80 New ringkeep high score! It's \x82" .. lenumber .. "\x80!")
		else
			file:close()
		end
	else
		local file = io.openlocal("ringkeep/highscore.txt", "w")
		file:write(lenumber)
		file:close()
		CONS_Printf(player, "\x85\Congrats!\x80 New ringkeep high score! It's \x82" .. lenumber .. "\x80!")
	end
end


addHook("PlayerThink", function(player) if player.bot > 0 return end
	local function CalculateRingsSpilled(player)
		if (player.losstime/TICRATE) < 5
			--print("1/9, " .. player.losstime)
			return ((player.PreviousRings*FRACUNIT) - (FixedMul(player.PreviousRings*FRACUNIT, FRACUNIT/9)))/FRACUNIT
		else
			if (player.losstime/TICRATE) < 15
				--print("1/4, " .. player.losstime)
				return ((player.PreviousRings*FRACUNIT) - (FixedMul(player.PreviousRings*FRACUNIT, FRACUNIT/4)))/FRACUNIT
			elseif (player.losstime/TICRATE) < 30
				--print("1/3, " .. player.losstime)
				return ((player.PreviousRings*FRACUNIT) - (FixedMul(player.PreviousRings*FRACUNIT, FRACUNIT/3)))/FRACUNIT
			else -- 6/10
				return ((player.PreviousRings*FRACUNIT) - (FixedMul(player.PreviousRings*FRACUNIT, (6*FRACUNIT)/10)))/FRACUNIT
			end
		end
	end

	local function RingsSpilledPercent(player)
		if (player.losstime/TICRATE) < 5
			return "1/9"
		elseif (player.losstime/TICRATE) < 15
			return "1/4"
		elseif (player.losstime/TICRATE) < 30
			return "1/3"
		else
			return "6/10"
		end
	end
	
	local function EncouragementPrint()
		local gayer = readhighscore()
		if gayer == 1
			CONS_Printf(player, "Welcome to \x84ringkeep\x80! Collect as many rings as you can, your rings will be kept in-between levels, and your highest score will be saved!")
		elseif gayer > player.rings
			CONS_Printf(player, "\x84ringkeep\x80 high score to aim for: \x82" .. gayer)
		end
			
	end

	if not player.PrintThing -- this only exists because if we print the moment the player spawns, they don't actually get to see it unless they upon console. stjr plz fix
		player.ringkeeptimer = $ + 1 
		if player.ringkeeptimer == 2*TICRATE
			EncouragementPrint()
			player.PrintThing = true
		end
	end

	if P_PlayerInPain(player) and player.RingPainTime
		player.rings = CalculateRingsSpilled(player)
		--print("rings before hit: " .. player.PreviousRings)
		--print("rings set to: " .. CalculateRingsSpilled(player))
		player.RingsLost = player.PreviousRings - CalculateRingsSpilled(player)
		--print("rings lost: " .. player.RingsLost)
		--print("rings percentage lost: " .. RingsSpilledPercent(player))
		P_PlayerRingBurst(player, player.RingsLost)
		player.RingsLost = 1
		player.RingPainTime = false
	end

	-- give back rings to a player who just died instantly
	if player.playerstate == PST_DEAD and not player.rkIJustDied
		player.rkIJustDied = true
	end
	
	if player.rkIJustDied and player.playerstate == PST_LIVE -- can't use reborn, since for whatever reason it runs *before* the player actually respawns 
		if mapheaderinfo[gamemap].bonustype == 1 and player.PreviousRings < 10
			return
		end
		player.rings = player.PreviousRings/2
		player.rkIJustDied = false
	end
	
	
	-- save rings at end of stage, and check for highest score
	if ((player.pflags & PF_FINISHED) or (mapheaderinfo[gamemap].bonustype == 1 and player.exiting > 0)) and not player.RingsAlreadySaved and not G_IsSpecialStage(gamemap)
		player.RingsAfterLevel = player.rings
		writehighscore(player.RingsAfterLevel, player)
		player.RingsAlreadySaved = true
		EncouragementPrint()
		player.rings = 0
	end

	-- save rings to a constant variable, keep this at very bottom
		player.PreviousRings = player.rings
end)

addHook("PlayerSpawn", function(player)
	player.ringkeeptimer = 0 
	
	if not player.PreviousRings 
		player.PreviousRings = 0
	end
	
	if player.RingsAlreadySaved and not G_IsSpecialStage(gamemap) and not (mapheaderinfo[gamemap].bonustype == 1 and player.RingsAfterLevel < 10)
		player.RingsAlreadySaved = false
		player.PrintThing = false
		player.rings = player.RingsAfterLevel
	end

end)

addHook("MobjDamage", function(mobj, inflictor, source, damage, damagetype) -- makes it so the player doesn't drop rings when being hit
	local player = mobj.player
	if not player.powers[pw_shield] and player.rings > 1
		P_PlayRinglossSound(mobj, player)
		player.RingPainTime = true
		P_DoPlayerPain(player, source, inflictor)
		return true
	else
		return false
	end
end, MT_PLAYER)