--[[
	Lua by JugadorXEI
	In order to enable frictionfix, add "Lua.frictionfix = true" to your map header.
	Instead of using the map header,
	it's possible to mark your Floor Friction linedefs with the "[12] No Tails" flag,
	in order to make speed items like sneakers and invincibility keep the sector's friction,
	thus preventing these items from capping speed.
]] 

-- Only execute if the version is higher.
local LOCALVERSION = 4
if frictionfix == nil then
	rawset(_G, "frictionfix", {})
end

if frictionfix.ver == nil or frictionfix.ver < LOCALVERSION then

local FRACBITS = 16
local FRACUNIT = FRACUNIT

local ORIG_FRICTION	= 62914
local LINEDEF_FRICTION = 540

local DISABLEFRICIMMUNITY = ML_NOTAILS

frictionfix.frictionTable = {}
frictionfix.isThereFrictionLinedefs = false

frictionfix.repopulateFrictionTable = function()
	frictionfix.frictionTable = {}
	frictionfix.isThereFrictionLinedefs = false
	
	local isFrictionFixHeaderEnabled = 
		mapheaderinfo[gamemap] ~= nil and
		mapheaderinfo[gamemap].frictionfix ~= nil and
		-- this is so scuffed lmfao
		mapheaderinfo[gamemap].frictionfix:lower() == "true"

	for line in lines.iterate do
		if line.valid and line.special == LINEDEF_FRICTION then
			local isFrictionImmunityDisabled =
				(line.flags & DISABLEFRICIMMUNITY) == DISABLEFRICIMMUNITY

			if isFrictionFixHeaderEnabled or isFrictionImmunityDisabled then
				local strength = line.frontside.textureoffset / FRACUNIT
				-- print("new line: " + line.tag + " - " + strength)
				if strength < 0 then
					table.insert(frictionfix.frictionTable, line.tag, strength)
					frictionfix.isThereFrictionLinedefs = true
				end
			end
		end
	end
end

frictionfix.fricfix = function(mobj)
	if leveltime == 1 	then frictionfix.repopulateFrictionTable() end
	if leveltime < 2 	then return end

	-- don't do anything if the table is empty
	if frictionfix.isThereFrictionLinedefs == false then return end

	-- don't enable if player is not on the ground
	if P_IsObjectOnGround(mobj) == false then return end

	-- print(mobj.friction)
	local player = mobj.player

	-- don't enable if player isn't fast, invincible or big.
	if player.kartstuff[k_sneakertimer] 		== 0	and
		player.kartstuff[k_invincibilitytimer] 	== 0 	and
		player.kartstuff[k_growshrinktimer] 	<= 0  	and
		player.kartstuff[k_hyudorotimer] 		== 0 	then
	return end

	local sector = nil
	local FoF = P_ThingOnSpecial3DFloor(mobj)
	
	sector = mobj.subsector.sector
	-- don't enable if no linedef changes friction
	
	-- if the friction loss comes from an FoF - find it
	-- P_ThingOnSpecial3DFloor doesn't help, since if you're underwater
	-- and stepping on an FoF floor, the water FoF takes precedence.
	if frictionfix.frictionTable[sector.tag] == nil then
		local wasItInFoF = false

		for fof in sector.ffloors() do
			if mobj.z >= fof.bottomheight and frictionfix.frictionTable[fof.sector.tag] ~= nil then
				-- print("found causing sector, tag " + frictionTable[fof.sector.tag])
				sector = fof.sector
				wasItInFoF = true
				break
			end
		end

		if wasItInFoF == false then return end
	end
	
	-- print("Tag: " + sector.tag)
	local strength = frictionfix.frictionTable[sector.tag]

	if strength > 0 then
		strength = $ * 2
	end

	local friction = ORIG_FRICTION - (0x1EB8 * strength) / 0x80

	friction = min($, FRACUNIT)
	friction = max($, 0)

	local movefactor = FixedDiv(ORIG_FRICTION, friction)

	if movefactor < FRACUNIT then
		movefactor = (19 * movefactor) - (18 * FRACUNIT)
	else
		movefactor = FRACUNIT
	end

	movefactor = max($, 32)

	mobj.friction 	= friction
	mobj.movefactor = movefactor
	-- print("Post (" + sector.tag + ") : " + mobj.friction)
end

if frictionfix.ver == nil then

	addHook("MobjThinker", function(mobj)
		frictionfix.fricfix(mobj)
	end, MT_PLAYER)
	addHook("NetVars", function(host)
		frictionfix.isThereFrictionLinedefs = host(frictionfix.isThereFrictionLinedefs)
		if frictionfix.isThereFrictionLinedefs == true then
			frictionfix.frictionTable = host(frictionfix.frictionTable)
		end
	end)

end

-- end
frictionfix.ver = LOCALVERSION -- The script ran, don't run it again
end