--Frostii's Physics Shit. bunch'a stuff smashed together in a way that vaguely resembles a vidjya game
--Momentum Mod by CobaltBW
--Everything aside from momentum mod by Frostiikin.
freeslot(
	"S_THOKKO",
	"SPR_THKO",
	"MT_THOKKO",
	"SPR_RNDS",
	"MT_RUNDUST",
	"S_RUNDUST"
)

mobjinfo[MT_THOKKO] = {
	doomednum = -1,
	spawnstate = S_THOKKO,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY
}

states[S_THOKKO] = {
	sprite = SPR_THKO,
	frame = TR_TRANS40|FF_PAPERSPRITE|A
}
mobjinfo[MT_RUNDUST] = {
	doomednum = -1,
	spawnstate = S_RUNDUST,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY
}

states[S_RUNDUST] = {
	sprite = SPR_RNDS,
	frame = TR_TRANS10|A
}


sfxinfo[sfx_kc5b].caption = "Powerful Thok"
/*addHook("AbilitySpecial",  function(p)
    if p.mo and p.mo.valid and p.mo.health and skins[p.mo.skin].ability == CA_THOK and not (p.pflags & PF_THOKKED) --and p.mo.skin=="sonic"
		if p.speed > skins[p.mo.skin].normalspeed
			P_InstaThrust(p.mo, p.mo.angle, p.thokforce)
			P_SetObjectMomZ(p.mo, p.thokupforce)
			S_StartSound(p.mo, sfx_thok)
			if p.thokforce > 69*FRACUNIT
						  --nice--
				local thokko = P_SpawnMobjFromMobj(p.mo, 0, 0, p.mo.scale * 20, MT_THOKKO)
				thokko.angle = p.mo.angle + ANGLE_90
				thokko.fuse = 7
				thokko.scale = 2*FRACUNIT/3
				thokko.destscale = 10*FRACUNIT
				thokko.colorized = true
				thokko.color = p.mo.color
				S_StartSound(p.mo, sfx_kc5b)
				p.thokeffects = true
				else
				p.thokeffects = false
				P_SpawnThokMobj(p)
			end
		else
			P_InstaThrust(p.mo, p.mo.angle, 40*FRACUNIT)
			P_SetObjectMomZ(p.mo, 6*FRACUNIT)
			S_StartSound(p.mo, sfx_thok)
			P_SpawnThokMobj(p)
			p.thokeffects = false
		end
        p.pflags = $ + PF_THOKKED
    end
end)*/
addHook("PlayerThink", function(p)
	--variable setup
		if not mapheaderinfo[gamemap].gfzcanyon then return end 
	if p.thokforce == nil
		p.thokforce = 0*FRACUNIT
		p.thokupforce = 0*FRACUNIT
		p.thokeffects = false
		p.lastspeed = 0
		p.spcanflip = false
		p.spflipping = 0
		p.spflipped = false
		p.frostiifrontflip = false
	end
	/////////////////////////////
	--uncuwl uwu (fuck you code divers you gotta suffer with me)
	--aka uncurl because i want control+f support fucking sue me
	--thanks to switchkaze for helping me make this actually work because this game is a pain in the ass
	p.mo._prevspin = $!=nil and $ or false
	p.mo._spintime = (p.cmd.buttons & BT_USE) and ($ and $+1 or 1) or 0
	if (p.pflags & PF_SPINNING) and p.mo._prevspin and P_IsObjectOnGround(p.mo) and p.mo._spintime == 1
		p.pflags = $1 & ~PF_SPINNING
		p.mo.state = S_PLAY_RUN
	end
	p.mo._prevspin = p.pflags & PF_SPINNING
	///////////////////////////////
	--falling animations over airwalk
	if p.mo.state == S_PLAY_STND or p.mo.state == S_PLAY_WAIT or p.mo.state == S_PLAY_WALK or p.mo.state == S_PLAY_RUN
		if not P_IsObjectOnGround(p.mo)
			if p.mo.momz >= 0
				p.mo.state = S_PLAY_SPRING
			else
				p.mo.state = S_PLAY_FALL
			end
		end
	end
	
	///////////////////////////////
	--recurl momentarily before going into fall frames if you was already in spring frames
	--Characters who don't spindash and don't spinjump who can still perform the frontflip
	if p.mo.skin == "amy"
	or p.mo.skin == "fang"
	or p.mo.skin == "modernsonic"
	or p.mo.skin == "msonic"
	or p.mo.skin == "shadow"
	or p.mo.skin == "inazuma"
	--or p.mo.skin == "blaze"
	or p.mo.skin == "aether"
	or p.mo.skin == "dirk"
	or p.mo.skin == "whirl"
	or p.mo.skin == "sms"
	or p.mo.skin == "silver"
	or p.mo.skin == "skip"
	or p.mo.skin == "bandages"
	or p.mo.skin == "werehog"
	or p.mo.skin == "milne"
	or p.mo.skin == "flamethedragon"
	or p.mo.skin == "flarethelizard"
		p.frostiifrontflip = true
	end
	--here's the fun part, the actual curling
	if not (skins[p.mo.skin].flags & SF_NOJUMPSPIN) or skins[p.mo.skin].ability2 == CA2_SPINDASH or p.frostiifrontflip == true
		if not P_IsObjectOnGround(p.mo)
			if p.mo.state == S_PLAY_SPRING
				p.spcanflip = true
			end
			if p.mo.state == S_PLAY_FALL and p.spcanflip == true
				p.mo.state = S_PLAY_ROLL
			end
			if p.spcanflip == true and p.mo.state == S_PLAY_ROLL and p.spflipping >= 12
				p.mo.state = S_PLAY_FALL
			end
			if p.spcanflip == true and p.mo.state == S_PLAY_ROLL and p.spflipping < 12
				p.spflipping = $ + 1
			end
		else
			p.spcanflip = false
			p.spflipping = 0 
		end
	end
	if p.mo.state == S_PLAY_SPRING
		p.spcanflip = true
		p.spflipping = 0
	end
	///////////////////////////////
	--water running at high speeds
	if p.speed >= 53*FRACUNIT and not (skins[p.mo.skin].flags & SF_RUNONWATER)
		p.charflags = $1|SF_RUNONWATER
	else
		if not (skins[p.mo.skin].flags & SF_RUNONWATER)
			p.charflags = $1 & ~(SF_RUNONWATER)
		end
	end
	--dust when running at high speeds
	if P_IsObjectOnGround(p.mo) and p.mo.state == S_PLAY_RUN and p.speed >= 53*FRACUNIT
		local rundust = P_SpawnMobjFromMobj(p.mo, 0, 0, p.mo.scale * 2, MT_RUNDUST) 
		rundust.momx = /*p.mo.momx + */P_RandomRange(-7, 7) * FRACUNIT
			rundust.momy = /*p.mo.momy + */P_RandomRange(-7, 7) * FRACUNIT
		rundust.momz = /*$ - p.mo.momz + */P_RandomRange(0, 5) * FRACUNIT
		rundust.state = S_SPINDUST1
	end
	--roll flash removal
	/*if p.mo.state == S_PLAY_ROLL and p.mo.frame == C
		p.mo.frame = D
	end*/
	
	////////////////////////////
	--kickoff
	--the "true" angle to thrust you in when you start moving
	local playertrueangle =
		p.cmd.angleturn<<16 + R_PointToAngle2(0, 0, p.cmd.forwardmove*FRACUNIT, -p.cmd.sidemove*FRACUNIT)
	--actual thrusting
	/*if FixedHypot(abs(p.cmd.forwardmove), abs(p.cmd.sidemove)) > 5
		if p.speed <= 6*FRACUNIT and p.mo.state != S_PLAY_SKID and P_IsObjectOnGround(p.mo)
			if p.mo.state == S_PLAY_WALK or p.mo.state == S_PLAY_WAIT or p.mo.state == S_PLAY_STND
				print("thrusting")
				P_InstaThrust(p.mo, playertrueangle, 7*FRACUNIT)
			end
		end
	end*/
	/*if skins[p.mo.skin].accelstart >= 96
		p.mo.accelstart = 999
	end*/
	
	
	
	
	////////////////////////////
	--rolling momentum adder
		--idfk how to do this lmfao
	/*if p.speed > p.lastspeed and p.mo.state == S_PLAY_ROLL and (p.pflags & PF_SPINNING) and P_IsObjectOnGround(p.mo)
		P_Thrust(p.mo, p.drawangle, 1*FRACUNIT/4)
	end*/
	
	p.lastspeed = p.speed	

		
	/////////////////////////////
	--Momentum Thok
    /*if p.mo and p.mo.valid and p.mo.health and skins[p.mo.skin].ability == CA_THOK --p.mo.skin == "sonic"
		p.ability = CA_NONE
		if not p.powers[pw_super]
			p.thokforce = p.speed + 16*FRACUNIT
			else
			p.thokforce = p.speed + 70*FRACUNIT
		end
			p.thokupforce = p.thokforce / 7
		if p.thokupforce < 6*FRACUNIT
			p.thokupforce = 6*FRACUNIT
		end
        if p.pflags & PF_THOKKED and p.thokeffects == true
			local AfterImageSpawn = P_SpawnGhostMobj(p.mo)
			if p.powers[pw_super]
				AfterImageSpawn.color = p.mo.color
				else
				AfterImageSpawn.color = 98
			end
			AfterImageSpawn.colorized = true
		end
    end*/
end)
local debug = 0
local UNCURL_LOCKTIME = 8
addHook('ThinkFrame', do
	--The momentum mod
		if not mapheaderinfo[gamemap].gfzcanyon then return end 
	for player in players.iterate do
		if player.mo and player.mo.scale and player.mo.friction and player.mo.movefactor then
			local pmo = player.mo
			//Create history
			if player.waterlast == nil then
				player.waterlast = false
				player.dashlast = false
				player.realfriction = pmo.friction
			end
			local skin = skins[pmo.skin]
			
			//Stat adjust
			--if player.charability2 == CA2_SPINDASH then
			--	player.mindash = skin.mindash * 3/2
			--end
			local water = 1+(pmo.eflags&MFE_UNDERWATER)/MFE_UNDERWATER //Water factor for momentum halving
			local grounded = P_IsObjectOnGround(pmo)
			local nmom = skin.normalspeed //Skin normalspeed, the integral component
			//Dashmode overrides skin normalspeed
			if player.dashmode >= 3*TICRATE and player.speed <= skin.normalspeed*35/10
			then
				nmom = player.normalspeed
			end
			
			local scale = pmo.scale //Normalspeed calculations are affected by scale
			local friction = FixedDiv(pmo.friction,pmo.movefactor) //Reversing friction is required for sustaining ground momentum
			local pmom = FixedDiv(FixedHypot(player.rmomx,player.rmomy),scale) //Current speed, scaled for normalspeed calculations
			local pwup = (player.powers[pw_sneakers]) or (player.powers[pw_super]) //Speed-ups multiply max allowed speed by 5/3
			local momangle = R_PointToAngle2(0,0,player.rmomx,player.rmomy) //Used for angling new momentum in ability cases
			//Adjust current speed reading for calculations with pwup status
			if pwup then
				pmom = $*3/5
			end
			local mom = FixedHypot(pmo.momx,pmo.momy)

						
			
			/////////
			//General momentum scaling
			
			//Do landing momentum cut
			if pmo.eflags&MFE_JUSTHITFLOOR then
				--player.normalspeed = skin.normalspeed
				--pmo.friction = $-$/10
			//Do ground momentum
			elseif grounded then
				//The amount of momentum to sustain
				//Also the speedcap.
				local sustain = FixedDiv(min(pmom*water,nmom*5/2),friction)
-- 				if pmom > player.normalspeed then
					player.normalspeed = max(nmom,sustain)
-- 				end
			//Do air momentum
			elseif not(player.dashmode) then //Dashmode overrides normalspeed in the air
				player.normalspeed = skin.normalspeed
			end
			
			///////
			//Thok momentum scaling
-- 			if player.charability == CA_THOK
			if player.charability == CA_JUMPTHOK
				then
				//Raise thokspeed to current momentum if above innate actionspd
				player.actionspd = max(pmom*water,skin.actionspd)
			end
			
			//////
			//Knuckles momentum renewal
			if player.charability == CA_GLIDEANDCLIMB then
				//Create glide history
				if player.glidelast == nil then
					player.glidelast = 0
				end
				local gliding = player.pflags&PF_GLIDING
				local thokked = player.pflags&PF_THOKKED
				local exitglide = (player.glidelast == 1 and not(gliding) and thokked)
				local landglide = (player.glidelast == 2 and not(gliding|thokked))
				//Restore glide momentum after deactivation
				if exitglide or landglide then
					pmo.momx = FixedMul(P_ReturnThrustX(nil,momangle,pmom),scale)
					pmo.momy = FixedMul(P_ReturnThrustY(nil,momangle,pmom),scale)
				end
				//Update glide history
				if gliding then
					player.glidelast = 1 //Gliding
				elseif exitglide then
					player.glidelast = 2 //Falling from glide
				elseif not(gliding|thokked) then
					player.glidelast = 0 //Not in glide state
				end
			end
			
			//////
			//Fang momentum renewal
			if player.charability == CA_BOUNCE then
				//Create bounce history
				if player.bouncelast == nil then
					player.bouncelast = false
				end
				if player.pflags&PF_BOUNCING and not(player.bouncelast) //Activate bounce
					or (not(player.pflags&PF_BOUNCING) and player.pflags&PF_THOKKED and player.bouncelast) //Deactivate bounce
					//Undo the momentum cut from bounce activation/deactivation
					pmo.momx = FixedMul(P_ReturnThrustX(nil,momangle,pmom),scale)
					pmo.momy = FixedMul(P_ReturnThrustY(nil,momangle,pmom),scale)
					pmo.momz = $*2
				end
				//Update bounce history
				player.bouncelast = (player.pflags&PF_BOUNCING > 0)
			end
			
			//Update history
			player.waterlast = (pmo.eflags&MFE_UNDERWATER > 0)
			player.dashlast = (player.pflags&PF_STARTDASH > 0)
			
			//DEBUG//
			if debug then
				print("momz " + pmo.momz/FRACUNIT)
				print("actionspd   " + player.actionspd/FRACUNIT)
				print("pmom        " + pmom/FRACUNIT)
				print("normalspeed " + player.normalspeed/FRACUNIT)
			end
		end
	end
end)