--this table is only used to give player the same table it player does not have
local LASs = {topspeed = 0,
			 speed = 0,
			 angle = 0,
			 color = 0,
			 sprung = 0,
			 wasground = 0,
			 fmomz = 0,
			 hori = 0,
			 vert = 0,
			 flags = 0,
			 spring = 0,
			 airtime = 0} --table cuz yeah

freeslot("MT_22_GREHORIZ","MT_22_GREDIAG","MT_22_GRESPRG",
		 "MT_22_YELHORIZ","MT_22_YELDIAG","MT_22_YELSPRG",
		 "MT_22_REDHORIZ","MT_22_REDDIAG","MT_22_REDSPRG",
		 "MT_22_BLUHORIZ","MT_22_BLUDIAG","MT_22_BLUSPRG")


--give springs their properties asap
addHook("MobjSpawn",function(spring)
	if not mapheaderinfo[gamemap].altsprings then return end
	if not (spring.type == MT_22_GREHORIZ or
			spring.type == MT_22_GREDIAG or
			spring.type == MT_22_GRESPRG or
			spring.type == MT_22_YELHORIZ or
			spring.type == MT_22_YELDIAG or
			spring.type == MT_22_YELSPRG or
			spring.type == MT_22_REDHORIZ or
			spring.type == MT_22_REDDIAG or
			spring.type == MT_22_REDSPRG or
			spring.type == MT_22_BLUHORIZ or
			spring.type == MT_22_BLUDIAG or
			spring.type == MT_22_BLUSPRG) then return end
	
	spring.isspring = true
		
	spring.scale = tonumber(mapheaderinfo[gamemap].springsize) or spring.scale
	spring.radius = FixedMul(spring.radius,spring.scale)
	spring.height = FixedMul(spring.height,spring.scale)
	spring.flags = $ |MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT --REALLY???
	spring.momz = 0 --REALLY????????????????????????????????
	spring.health = 9999

	
	if spring.type == MT_22_GRESPRG or spring.type == MT_22_GREDIAG then spring.info.mass = (tonumber(mapheaderinfo[gamemap].verticalgreypower) or spring.info.mass) spring.color = 2 end
	if spring.type == MT_22_GREDIAG or spring.type == MT_22_GREHORIZ then spring.info.damage = (tonumber(mapheaderinfo[gamemap].horizontalgreypower) or spring.info.damage) spring.color = 2 end

	if spring.type == MT_22_YELSPRG or spring.type == MT_22_YELDIAG then spring.info.mass = (tonumber(mapheaderinfo[gamemap].verticalyellowpower) or spring.info.mass) spring.color = 46 end
	if spring.type == MT_22_YELDIAG or spring.type == MT_22_YELHORIZ then spring.info.damage = (tonumber(mapheaderinfo[gamemap].horizontalyellowpower) or spring.info.damage) spring.color = 46 end

	if spring.type == MT_22_REDSPRG or spring.type == MT_22_REDDIAG then spring.info.mass = (tonumber(mapheaderinfo[gamemap].verticalredpower) or spring.info.mass) spring.color = 25 end
	if spring.type == MT_22_REDDIAG or spring.type == MT_22_REDHORIZ then spring.info.damage = (tonumber(mapheaderinfo[gamemap].horizontalredpower) or spring.info.damage) spring.color = 25 end

	if spring.type == MT_22_BLUSPRG or spring.type == MT_22_BLUDIAG then spring.info.mass = (tonumber(mapheaderinfo[gamemap].verticalbluepower) or spring.info.mass) spring.color = 86 end
	if spring.type == MT_22_BLUDIAG or spring.type == MT_22_BLUHORIZ then spring.info.damage = (tonumber(mapheaderinfo[gamemap].horizontalbluepower) or spring.info.damage) spring.color = 86 end
	

end,MT_NULL)

if alsprings then
	return
end
rawset(_G, "alsprings", true) --load only once because yes

--this is to rawset the object flags (the ones we see in zone builder) THANK YOU LAT

local mtf_flags = {
	"MTF_EXTRA",
	"MTF_OBJECTFLIP",
	"MTF_SPECIAL",
	"MTF_AMBUSH",
}

for i = 1, #mtf_flags
	rawset(_G, mtf_flags[i], 2^(i-1))
end


local function K_SpawnSparkleTrailL(mo) --this is exposed to lua but iwanted less sparkles
	local rad = (mo.radius*2)>>FRACBITS
	local sparkle
	local i

	for i = 0, 1 do -- way less sparkles

		local newx = mo.x - mo.momx*2 + (P_RandomRange(-rad, rad)<<FRACBITS)
		local newy = mo.y - mo.momy*2 + (P_RandomRange(-rad, rad)<<FRACBITS)
		local newz = mo.z - mo.momz*2 + (P_RandomRange(0, mo.height>>FRACBITS)<<FRACBITS)

		sparkle = P_SpawnMobj(newx, newy, newz, MT_SPARKLETRAIL)
		sparkle.eflags = (sparkle.eflags & ~MFE_VERTICALFLIP)|(mo.eflags & MFE_VERTICALFLIP)
		sparkle.flags2 = (sparkle.flags2 & ~MF2_OBJECTFLIP)|(mo.flags2 & MF2_OBJECTFLIP)

		if (sparkle.eflags & MFE_VERTICALFLIP) then
			sparkle.z = $ + mo.height - FixedMul(mo.scale, sparkle.height)
		end
		
		sparkle.destscale = mo.destscale
		sparkle.scale = mo.scale
		sparkle.color = mo.color
	end
	sparkle.state =  S_KARTINVULN_LARGE1
end

local function L_DoSpring(spring, object) --ported from source code, overrides common behavior
	--//INT32 pflags
	local hscale = mapobjectscale + (mapobjectscale - object.scale)
	local vscale = mapobjectscale + (object.scale - mapobjectscale)
	local offx, offy
	local vertispeed = FixedMul(spring.info.mass,FRACUNIT*(100+(20*spring.spawnpoint.extrainfo))/100)
	local horizspeed = FixedMul(spring.info.damage,FRACUNIT*(100+(20*spring.spawnpoint.extrainfo))/100)
	--this is to make sure is zero
	--even if it multiplies, even if is a zero value, i dunno man lol
	if spring.info.mass == 0 then
		vertispeed = 0
	end
	if spring.info.damage == 0 then
		horizspeed = 0
	end
	
	if object.eflags & MFE_SPRUNG then return end // Object was already sprung this tic

	// Spectators don't trigger springs.
	if object.player and object.player.spectator then return end

	--object.standingslope = NULL // Okay, now we can't return - no launching off at silly angles for you.
	-- lol i cant
	
	object.eflags = $ |MFE_SPRUNG --// apply this flag asap!
	spring.flags = $ & ~(MF_SOLID|MF_SPECIAL) --// De-solidify

	if horizspeed and vertispeed then --// Mimic SA
		object.momx, object.momy = 0, 0
		P_TryMove(object, spring.x, spring.y, true)
	end
	

	if spring.eflags & MFE_VERTICALFLIP then
		vertispeed = $ *-1
	end

	if vertispeed > 0 then
		object.z = spring.z + spring.height + 1
	elseif vertispeed < 0 then
		object.z = spring.z - object.height - 1
	else
		// Horizontal springs teleport you in FRONT of them.
		object.momx, object.momy = 0, 0

		// Overestimate the distance to position you at
		offx = P_ReturnThrustX(spring, spring.angle, (spring.radius + object.radius + 1) * 2)
		offy = P_ReturnThrustY(spring, spring.angle, (spring.radius + object.radius + 1) * 2)

		// Make it square by clipping
		if offx > (spring.radius + object.radius + 1) then
			offx = spring.radius + object.radius + 1
		elseif offx < -(spring.radius + object.radius + 1) then
			offx = -(spring.radius + object.radius + 1)
		end

		if offy > (spring.radius + object.radius + 1) then
			offy = spring.radius + object.radius + 1
		elseif offy < -(spring.radius + object.radius + 1) then
			offy = -(spring.radius + object.radius + 1)
		end

		// Set position!
		P_TryMove(object, spring.x + offx, spring.y + offy, true)
	end
	

	if vertispeed then
		-- if you want diagonals to scale vertical speed with player speed
		--because naturally only horizontal speed scales up
		local FinalSpeed =  FixedDiv(vertispeed, vscale)
		local pSpeed = object.player.speed / 3
		if horizspeed and spring.spawnpoint.options & MTF_SPECIAL then
			if pSpeed > FinalSpeed then
				FinalSpeed = pSpeed
				if vertispeed < 0 then
					FinalSpeed = -pSpeed
				end
			end
		end
		object.momz = FixedMul(FinalSpeed,vscale)-- FixedMul(vertispeed,FixedSqrt(FixedMul(vscale, spring.scale)))
	end

	if horizspeed then
		local finalSpeed = FixedDiv(horizspeed, hscale)
		local pSpeed = object.player.speed

		if pSpeed > finalSpeed then
			finalSpeed = pSpeed
		end
		
		--diagonal spring scales up A LOT horizontaly
		--so you can lock to their common speed
		if vertispeed and spring.spawnpoint.options & MTF_EXTRA then
			finalSpeed = FixedDiv(horizspeed, hscale)
		end

		P_InstaThrust(object, spring.angle, FixedMul(finalSpeed,hscale))-- FixedMul(finalSpeed,FixedSqrt(FixedMul(hscale, spring.scale))))
	end
	

	// Re-solidify
	--spring.flags = $ | (spring.info.flags & (MF_SPECIAL|MF_SOLID))
	spring.flags = spring.info.flags
	spring.flags = $ |MF_SPECIAL|MF_SOLID|MF_NOGRAVITY|MF_NOCLIPHEIGHT
	spring.state = spring.info.raisestate
	
	if horizspeed and object.player.cmd.forwardmove == 0 and object.player.cmd.sidemove == 0 then
		object.angle = spring.angle
	end
	
	P_ResetPlayer(object.player)
	
	--tries to avoid player stuck into slopes
	if object.standingslope and not vertispeed then
		local slope = object.standingslope
		if P_MobjFlip(object) < 0 then
			object.z = P_GetZAt(slope,object.x,object.y) - object.height
		else
			object.z = P_GetZAt(slope,object.x,object.y) 
		end
		
	end
	if vertispeed then
		if P_MobjFlip(object) < 0 then
			object.z = $ - FRACUNIT
		else
			object.z = $ + FRACUNIT
		end
	end
	return true
end


local function springcollision(mt, mt2)
	if not mapheaderinfo[gamemap].altsprings then return end
	if not mt.isspring then return end
	if not mt2.player then return end
	if not mt.valid then return end
	if not mt2.valid then return end
	if mt2.eflags & MFE_SPRUNG then mt.health = 9999 return true end
	if not(mt.flags & MF_SOLID) then mt.health = 9999  return true end
	mt.health = 9999
	L_DoSpring(mt, mt2)
	local mapscale = mapobjectscale + (mapobjectscale - mt2.scale)
	local hsped = mt.info.damage
	local vsped = mt.info.mass
	local p = mt2.player
	p.LAS = {topspeed = FixedMul(FixedMul(hsped,FRACUNIT*(100+(20*mt.spawnpoint.extrainfo))/100),FixedMul(mapscale, mt.scale)),
			 speed = FixedMul(FixedMul(hsped,FRACUNIT*(100+(20*mt.spawnpoint.extrainfo))/100) ,FixedMul(mapscale, mt.scale)),
			 angle = mt.angle,
			 color = mt.color,
			 sprung = true,
			 wasground = false,
			 fmomz = 0,
			 hori = hsped,
			 vert = vsped,
			 flags = mt.spawnpoint.options,
			 spring = mt}
	--cancel wall launch and dash ring
	p.dashringtimer = 0 
	p.wall = nil 
	--no pogo spring too
	p.kartstuff[k_pogospring] = 0
	if mt.spawnpoint.options & MTF_AMBUSH and ((hsped and vsped) or (hsped and not vsped)) then --force angle
		--change player angle 
		mt2.angle = mt.angle
	end
	if vsped then 
		--fake speed for effect
		p.LAS.speed = FixedMul(vsped,FixedSqrt(FixedMul(mapscale, FixedMul(mt.scale, FRACUNIT*(100+(20*mt.spawnpoint.extrainfo))/100))))
		--prevent getting stuck on springs
		if not hsped then
			mt2.player.antispringsoftlock = ($ or 0) + FRACUNIT
		else
			mt2.player.antispringsoftlock = ($ or 0) + FRACUNIT/4
		end
	end
	
	if mt.spawnpoint.options & MTF_SPECIAL and vsped and not hsped then --stop player movement
		--vertical only
		mt2.momx,mt2.momy = 0,0
	end
	if mt.spawnpoint.options & MTF_AMBUSH and vsped and not hsped then --change move direction
		--vertical only
		P_InstaThrust(mt2,mt.angle,mt2.player.speed)
		mt2.angle = mt.angle
	end
	return true
end

addHook("TouchSpecial",springcollision,MT_NULL)


addHook("ThinkFrame",do
	if leveltime >= 1 and not mapheaderinfo[gamemap].altsprings then return end

	for p in players.iterate do
		if not p.LAS then p.LAS = LASs end
		if p.antispringsoftlock == nil then p.antispringsoftlock = 0 end
		if p.LAS then
			--nullify effect
			if p.spectator 
			or (not p.mo or p.mo and not p.mo.valid)
			or p.kartstuff[k_squishedtimer] ~= 0 
			or (p.kartstuff[k_spinouttimer] ~= 0 and p.mo.momz > 0)
			or p.kartstuff[k_respawn]
			or p.exiting ~= 0 then
				p.LAS.speed = 0
			end
			if p.kartstuff[k_justbumped]
			and p.LAS.speed > 0 then
				--lose a bit when you bump someone
				p.LAS.speed = $ - FRACUNIT/32
			end
			
			if p.mo and p.mo.valid and p.mo.eflags & MFE_JUSTBOUNCEDWALL
			and p.LAS.speed > 0 then
				p.LAS.angle = R_PointToAngle2(0,0,p.mo.momx,p.mo.momy)
				--lose some speed
				p.LAS.speed = $ - FRACUNIT/32
			end
			if (p.kartstuff[k_offroad] 
			or p.kartstuff[k_spinouttimer])
			and p.LAS.speed > 0 then
				--lose significant speed if you try to cut offroad
				p.LAS.speed = $ - FRACUNIT/16
			end
		end
	end

	--not available for now 
	--[[
	--bumping shenanigans
	--when a player bumps another one
	--ot trasnfer the spring effect and pushes
	--the other player based on hte spring effect power
	--not the best thing i nthe world ut it works :D
	for p1 in players.iterate do
		if p1.kartstuff[k_justbumped] ~= 6 then continue end
		if not p1.mo or p1.mo and not p1.mo.valid then continue end
		for p2 in players.iterate do
			--if p2.kartstuff[k_justbumped] ~= 6 then continue end
			if not p2.mo or p2.mo and not p2.mo.valid then continue end
			--players are too distant so ignore
			if FixedHypot(p1.mo.x-p2.mo.x,
			p1.mo.y-p2.mo.y) >= 350*FRACUNIT then continue end
			if #p1 ~= #p2 and 
			FixedHypot(p1.mo.x-p2.mo.x,
			p1.mo.y-p2.mo.y)
			<= (p1.mo.radius*2)+(p2.mo.radius*2)  then
				--print('bomp')
				if p1.LAS.speed >= p2.LAS.speed then
					if p1.LAS.speed == 0 then return end
					P_Thrust(p2.mo,p1.LAS.angle,p1.LAS.speed*16/100)
					/*
					p2.LAS.speed = p1.LAS.speed
					p2.LAS.angle = p1.LAS.angle
					p2.LAS.topspeed = p1.LAS.topspeed
					p2.LAS.flags = p1.LAS.flags
					p2.LAS.color = p1.LAS.color
					p2.LAS.vert = p1.LAS.vert
					p2.LAS.hori = p1.LAS.hori
					p2.LAS.moveang = p1.LAS.moveang
					p2.LAS.spring = p1.LAS.spring
					p1.LAS.speed = $ - ($*40/100)
					*/
				else
					if p2.LAS.speed == 0 then return end
					P_Thrust(p1.mo,p2.LAS.angle,p2.LAS.speed*16/100)
					/*
					p1.LAS.speed = p2.LAS.speed
					p1.LAS.angle = p2.LAS.angle
					p1.LAS.topspeed = p2.LAS.topspeed
					p1.LAS.flags = p2.LAS.flags
					p1.LAS.color = p2.LAS.color
					p1.LAS.vert = p2.LAS.vert
					p1.LAS.hori = p2.LAS.hori
					p1.LAS.moveang = p2.LAS.moveang
					p1.LAS.spring = p2.LAS.spring
					p2.LAS.speed = $ - ($*40/100)
					*/
				end
			end
		end	
	end
	]]--
end)


addHook("MobjThinker",function(mo)
	if not mapheaderinfo[gamemap].altsprings then return end
	if mo.player.LAS == nil
	or leveltime == 1 then 
		mo.player.LAS = LASs 
		mo.player.antispringsoftlock = 0
	end 
	local p = mo.player
	local ground = P_IsObjectOnGround(mo)
	p.LAS.moveang = R_PointToAngle2(0,0,mo.momx,mo.momy)
	
	--this got moved here because on collision wont work effectively, also
	--the anti spring lock code
	if p.LAS.sprung == true
	and p.LAS.vert and not p.LAS.hori
	and p.LAS.flags & MTF_SPECIAL then
		--stop horizontal speed if desired
		mo.momx,mo.momy = 0,0
	end
	--if you bounce three times you might be stuck
	--then get you off
	--print(p.antispringsoftlock/FRACUNIT)
	if p.antispringsoftlock > 3*FRACUNIT then
		P_InstaThrust(mo,mo.angle,10*FRACUNIT)
		p.antispringsoftlock = 0
	end

	if p.LAS.sprung == true
	and p.LAS.vert and not p.LAS.hori
	and p.LAS.flags & MTF_EXTRA then
		--align horizontaly with vertical springs
		P_TeleportMove(mo,p.LAS.spring.x,p.LAS.spring.y,mo.z)
	end

	
	if ground == true then
		p.antispringsoftlock = 0
		--if you break, make effect last less
		if p.cmd.buttons & BT_BRAKE
		or p.kartstuff[k_offroad]then
			p.LAS.speed = $ - FRACUNIT*42/100
		end
		--cap mvoement then uncap
		if p.LAS.hori and not p.LAS.vert then
			--sparkle trail efffect
			if p.LAS.speed > 0 then
				mo.color = p.LAS.color
				K_SpawnSparkleTrailL(mo)
				mo.color = p.skincolor
			end
			if p.LAS.flags & MTF_SPECIAL then
				--your movement is locked
				if p.LAS.speed > p.LAS.topspeed*50/100 then		
					P_InstaThrust(mo,p.LAS.angle,p.LAS.speed*250/100)
					p.LAS.speed = $ - (p.LAS.topspeed/84)
				elseif p.LAS.speed > 0 then
					--is not anymore, but youll have some momentum left
					P_Thrust(mo,p.LAS.moveang,p.LAS.speed*10/100)
					p.LAS.speed = $ - (p.LAS.topspeed/112)	
				end
			end
			-- push springs	
			if p.LAS.flags & MTF_EXTRA and p.LAS.speed > 0 then
				--these are a strong push towards spring direction
				--youcan benefit from it in many ways
				--or get punished
				P_Thrust(mo,p.LAS.angle,p.LAS.speed*12/100)
				p.LAS.speed = $ - (p.LAS.topspeed/52)
			end
		end
		if p.LAS.vert then
			--opsie
			p.LAS.speed = $ - (p.LAS.topspeed/32)	
		end
		p.LAS.wasground = true
		p.LAS.fmomz = 0
	else
		--sparkle trail effect
		if p.LAS.speed > 0 then
			mo.color = p.LAS.color
			K_SpawnSparkleTrailL(mo)
			mo.color = p.skincolor
		end
		
		--stop vertical speed if hit horizontal spring midair
		--if you even want this ofc
		if p.LAS.sprung == true
		and p.LAS.hori and not p.LAS.vert and p.LAS.flags & MTF_EXTRA then
			p.LAS.fmomz = FRACUNIT*9
			mo.momz = 0
			p.LAS.wasground = false
		end
		if p.LAS.sprung == true
		and p.LAS.hori
		and not p.LAS.vert
		and p.LAS.flags & MTF_SPECIAL  then
			--stronger horizontal spring midair
			P_InstaThrust(mo,p.LAS.angle,p.LAS.speed*2)			
		end
		if p.LAS.speed > 0
		and p.LAS.hori
		and not p.LAS.vert
		and p.LAS.flags & MTF_EXTRA then
			--this gives players decreased gravity
			--if you leave the ground or havent hit at all
			--cover more space midair without needing a powerfll spring to do so
			if p.LAS.wasground == false and P_MobjFlip(mo) > 0 then
				p.LAS.fmomz = $ - FRACUNIT/4
				mo.momz = max($,p.LAS.fmomz)
			end
			if p.LAS.wasground == false and P_MobjFlip(mo) < 0 then
				p.LAS.fmomz = $ + FRACUNIT/4
				mo.momz = min($,p.LAS.fmomz)
			end
			--left the ground
			if p.LAS.wasground == true and P_MobjFlip(mo) > 0 then
				p.LAS.fmomz = $ - FRACUNIT/2
				mo.momz = max($,p.LAS.fmomz)
			end
			if p.LAS.wasground == true and P_MobjFlip(mo) < 0 then
				p.LAS.fmomz = $ + FRACUNIT/2
				mo.momz = min($,p.LAS.fmomz)
			end
		end
		p.LAS.speed = $ - (p.LAS.topspeed/48)
	end
	
	p.LAS.sprung = false		
end,MT_PLAYER)

