--Frostii's Physics Shit. bunch'a stuff smashed together in a way that vaguely resembles a vidjya game
--Momentum Mod by CobaltBW
--Everything made by Frostiikin, unless specified otherwise.
freeslot(
	"S_THOKKO",
	"SPR_THKO",
	"MT_THOKKO",
	"S_STARTHOK",
	"SPR_STHK",
	"MT_STARTHOK",
	"SPR_RNDS",
	"SPR_DSHE",
	"MT_DASHMODETRAIL",
	"S_DASHMODETRAIL",
	"SPR_DSHJ",
	"MT_DASHMODETRAILJUMP",
	"S_DASHMODETRAILJUMP",
	"SPR_DSHR",
	"MT_DASHMODETRAILROLL",
	"S_DASHMODETRAILROLL",
	"SPR_DSHF",
	"MT_DASHMODETRAILFALL",
	"S_DASHMODETRAILFALL",
	"MT_RUNDUST",
	"S_RUNDUST",
	"SFX_PUTFST",
	"SPR2_AMFL",
	"S_PLAY_AMYFALL",
	"S_PLAY_METALDASH",
	"SPR2_FAIR",
	"SPR2_FAIE",
	"S_PLAY_AIRSHOOT",
	"S_PLAY_AIRSHOOT_FINISH",
	"SPR2_SHIT",
	"SPR2_OOF_",
	"S_PLAY_FACEPLANT",
	"SPR2_TRKU",
	"SPR2_TRKD",
	"S_PLAY_TRICKUP",
	"S_PLAY_TRICKDOWN",
	"SFX_AWFUCK",
	"SFX_SQEAKT"
)

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

states[S_THOKKO] = {
	sprite = SPR_THKO,
	frame = TR_TRANS40|FF_PAPERSPRITE|A
}

mobjinfo[MT_STARTHOK] = {
	doomednum = -1,
	spawnstate = S_STARTHOK,
	flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOGRAVITY
}

states[S_STARTHOK] = {
	sprite = SPR_STHK,
	frame = TR_TRANS40|A
}

states[S_DASHMODETRAIL] = {
	sprite = SPR_DSHE,
	frame = TR_TRANS40|A,
	dispoffset = 2
}

mobjinfo[MT_DASHMODETRAIL] = {
	doomednum = -1,
	spawnstate = S_DASHMODETRAIL,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_DASHMODETRAILFALL] = {
	sprite = SPR_DSHF,
	frame = TR_TRANS40|A
}

mobjinfo[MT_DASHMODETRAILFALL] = {
	doomednum = -1,
	spawnstate = S_DASHMODETRAILFALL,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_DASHMODETRAILJUMP] = {
	sprite = SPR_DSHJ,
	frame = TR_TRANS40|A
}

mobjinfo[MT_DASHMODETRAILJUMP] = {
	doomednum = -1,
	spawnstate = S_DASHMODETRAILJUMP,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_DASHMODETRAILROLL] = {
	sprite = SPR_DSHR,
	frame = TR_TRANS40|A
}

mobjinfo[MT_DASHMODETRAILROLL] = {
	doomednum = -1,
	spawnstate = S_DASHMODETRAILROLL,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_METSONAURA] = {
	sprite = SPR_MAUR,
	frame = TR_TRANS30|FF_ANIMATE,
	var1 = 4,
	var2 = 2
}

mobjinfo[MT_METSONAURA] = {
	doomednum = -1,
	spawnstate = S_METSONAURA,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT,
	dispoffset = -3
}

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
}
spr2defaults[SPR2_OOF_] = SPR2_SHIT
spr2defaults[SPR2_SHIT] = SPR2_PAIN
spr2defaults[SPR2_TRKU] = SPR2_SPNG
spr2defaults[SPR2_TRKD] = SPR2_FALL

sfxinfo[sfx_kc5b].caption = "Powerful Thok"
addHook("AbilitySpecial",  function(p)
	if (p.noxmomchar or p.xmomtoggledoff)
	return 
	end
	--momentum thok
    if p.mo and p.mo.valid and p.mo.health and not (p.pflags & PF_THOKKED) and skins[p.mo.skin].ability == CA_THOK 
	and not (p.mo.skin == "vanillasonic" or p.mo.skin == "robo-hood" or p.mo.skin == "msonic" or p.mo.skin == "ray" or p.mo.skin == "altsonic" or p.mo.skin == "juniosonic" or p.mo.skin == "sms" or p.mo.skin == "inazuma" or p.mo.skin == "rafael" or p.mo.skin == "srbii" and not p.powers[pw_super] or p.mo.skin == "srbii" and p.powers[pw_super] and p.hyper.capable == false)
		
		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)
			p.thoktimer = 4
			if p.mo.skin == "srbii"
				P_NukeEnemies(p.mo, p.mo, 400*FRACUNIT)
				--P_StartQuake(50*FRACUNIT, 10)
				--P_FlashPal(p, PAL_WHITE, 8)
			end
			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
				local cometthok = P_SpawnMobjFromMobj(p.mo, 0, 0, p.mo.scale * 20, MT_STARTHOK)
				cometthok.angle = p.mo.angle
				cometthok.fuse = 27
				cometthok.scale = 2*FRACUNIT
				cometthok.destscale = 1*FRACUNIT/2
				--cometthok.colorized = true
				cometthok.color = p.mo.color
				cometthok.source = p.mo
				--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.thoktimer = 4
			if p.mo.skin == "srbii"
				P_NukeEnemies(p.mo, p.mo, 400*FRACUNIT)
				--P_StartQuake(50*FRACUNIT, 10)
				--P_FlashPal(p, PAL_WHITE, 8)
			end
			p.thokeffects = false
		end
        p.pflags = $ + PF_THOKKED
		return true
    end
	--fly burst
	if p.mo and p.mo.valid and p.mo.health and skins[p.mo.skin].ability == CA_FLY and p.flydowntimer == 0 and not (skins[p.mo.skin].flags & SF_MULTIABILITY) and not (p.pflags & PF_JUMPDOWN) and p.flightcounter < 3 and not (p.mo.eflags & MFE_UNDERWATER) and not p.bot and not (p.mo.skin == "eggman")
		p.mo.state = S_PLAY_FLY
		P_SetObjectMomZ(p.mo, 17*FRACUNIT, false)
		p.pflags = $1 & ~PF_SPINNING
		p.flightcounter = $ + 1
		--return true
	end
	
	
	--amycopter
	if p.mo.skin == "amy" 
		if p.mo.state != S_PLAY_MELEE and p.mo.state != S_PLAY_MELEE_LANDING and p.mo.state != S_PLAY_MELEE_FINISH
			if not (p.pflags & PF_JUMPDOWN) and p.amybruh == true and p.mo.state != S_PLAY_TWINSPIN
				p.mo.state = S_PLAY_AMYFALL
				if p.speed <= 44*FRACUNIT
					P_InstaThrust(p.mo, p.mo.angle, 44*FRACUNIT)
				else
					if not p.powers[pw_super] and not p.hyper.capable == true
						P_InstaThrust(p.mo, p.mo.angle, p.speed)
					end
				end
				p.amybruh = false
			end
		end
		/*if p.powers[pw_super] and p.hyper.capable == true and (p.pflags & PF_JUMPDOWN)
			if p.mo.state != S_PLAY_AMYFALL
				p.mo.state = S_PLAY_AMYFALL
			end
		end*/
		return true
	end
end)








addHook("JumpSpinSpecial", function(p)
	/*if p.mo and p.mo.valid and p.mo.health and skins[p.mo.skin].ability == CA_FLY and not (skins[p.mo.skin].flags & SF_MULTIABILITY) and not (p.pflags & PF_USEDOWN)
		if p.mo.state == S_PLAY_FLY
			if p.mo.momz <= 0
				p.mo.state = S_PLAY_FALL
			else
				p.mo.state = S_PLAY_SPRING
			end
			p.pflags = $1 & ~PF_SPINNING
			p.pflags = $1 & ~PF_JUMPED
		end
	end*/
end)
local boostpower = {10,20,30,35,45,47,50,52,55,75}
boostpower[0] = 0

addHook("PlayerThink", function(p)
		local playertrueangle = p.cmd.angleturn<<16 + R_PointToAngle2(0, 0, p.cmd.forwardmove*FRACUNIT, -p.cmd.sidemove*FRACUNIT)
		if P_GetPlayerControlDirection(p) == 0 or p.mo.flags2 & MF2_TWOD or twodlevel
		   playertrueangle = p.mo.angle
		end
	if p.noxmomchar --Set player.noxmomchar to 2 to disable ALL of Xmom's effects for your character!
		p.noxmomchar = $-1
	end
	--print(p.speed/FRACUNIT)
	--print(p.actionspd/FRACUNIT)
	--variable setup
	--keyword for easy control+F: scriptbegin
	if (p.noxmomchar or p.xmomtoggledoff)
	return 
	end
	if not p.mo and p.mo.valid and p.mo.health return end
	if p.thokforce == nil
		p.thokforce = 0*FRACUNIT
		p.thokupforce = 0*FRACUNIT
		p.thokeffects = false
		p.thoktimer = 0
		p.flydestimer = 0
		p.flydowntimer = 0
		p.xmomspindown = false
		p.lastz = 0
		p.lastx = 0
		p.lasty = 0
		p.spcanflip = false
		p.spflipping = 0
		p.spflipped = false
		p.frostiifrontflip = false
		p.flightcounter = 0 
		p.amybruh = false
		p.amyspeeb = 0 
		p.amycanspring = false
		p.amytimer = 0 
		p.wasmetdashing = false 
		p.metalcolorfucker = false
		p.isxmomentum = true
		p.isonlavafof = false
		p.hasnomomentum = false
		p.xmomlaststate = S_PLAY_WALK
	end
	/////////////////////////////
	--gotta put this up here 'cuz srbii doesn't get access to the rest of xmomentum
	if p.mo.skin == "srbii"
		p.charflags = $1|SF_NOSUPERSPIN
		p.actionspd = 70*FRACUNIT
	end
	--what the fuck is this shit
	if p.cr_skin
		if p.cr_skin == "microwave"
			p.cr_skin = "sonic"
		end
	end
	if p.mo.skin == "microwave"
		S_ChangeMusic("BEEEP",true,p)
	end
	if p.lastskin
		if p.lastskin == "microwave" and p.mo.skin != "microwave"
			P_RestoreMusic(p)
		end
	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 
	and not (p.mo.skin == "vanillasonic" or p.mo.skin == "vanillatails" or p.mo.skin == "altsonic" or p.mo.skin == "srbii" or p.mo.skin == "sms")
	and p.mo.state != S_PLAY_SPINDASH and not (p.pflags & PF_STARTDASH) and p.dashspeed == 0
		p.pflags = $1 & ~PF_SPINNING
		p.mo.state = S_PLAY_RUN
		p.restoremymomentumafteruncurlingpleasethankyouuuuu = FixedHypot(p.mo.momx, p.mo.momy)
	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 p.mo.skin != "nasya" and p.mo.skin != "ssnsonic" and p.mo.skin != "srbii"	
			if not P_IsObjectOnGround(p.mo)
			and p.powers[pw_carry] != CR_ROLLOUT
			and p.powers[pw_carry] != CR_MINECART
			and p.powers[pw_carry] != CR_MACESWING
			and p.powers[pw_carry] != CR_ZOOMTUBE
			and p.powers[pw_carry] != CR_ROPEHANG
			and p.powers[pw_carry] != CR_PLAYER
			and p.powers[pw_carry] != CR_NIGHTSMODE
			and not p.hyper.tailsflying
				if p.mo.momz >= 0
					p.mo.state = S_PLAY_SPRING
					p.cantrick = true
				else
					p.mo.state = S_PLAY_FALL
					--p.cantrick = true
				end
			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
	--also can't frontflip if you've began doing manual tricking
	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"
	or p.mo.skin == "fire"
	or skins[p.mo.skin].ability2 == CA2_SPINDASH
	or not (skins[p.mo.skin].flags & SF_NOJUMPSPIN) and not (skins[p.mo.skin].flags & SF_MARIODAMAGE)
		if p.mo.skin != "nasya"
			p.frostiifrontflip = true
		end
	end
	if p.mo.skin == "nasya"
		p.frostiifrontflip = false
	end
	--here's the fun part, the actual curling
	if p.frostiifrontflip == true
		if not P_IsObjectOnGround(p.mo)
			if p.mo.state == S_PLAY_SPRING and p.frontflipinterrupter == false
				p.spcanflip = true
			end
			if p.mo.state == S_PLAY_FALL and p.spcanflip == true and p.frontflipinterrupter == false
				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
				--p.mo.frame = 1
				--p.mo.anim_duration = 2
			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
	if p.mo.skin == "sms" return end
	//////////////////////////////////////////
	--Tricks! Do enough flips to get a speedboost when you land!
	if p.rollspeed == nil
		p.rollspeed = 5
		p.rolspeed2 = 5
		p.frontflipinterrupter = false
		p.springing = false
		p.cantrick = false
		p.trickboost1 = false
		p.trickboost2 = false
		p.steamvented = false
		p.rollangleexception = false
		p.trickboostcount = 0
		p.trickboostpower = 0
		p.lastrollangle = 0
		p.oldability = p.charability
		p.carttricks = false
	end
	if p.followitem == MT_TAILSOVERLAY
	--	p.followmobj.rollangle = p.mo.rollangle
	end
	--start tricking if you're able to trick and press jump. some characters are too high res for this.
	if (p.mo.state == S_PLAY_SPRING or p.mo.state == S_PLAY_FALL) and not (p.pflags & PF_JUMPED) and p.cantrick == true 
	and not (p.isuselesschar)
		if p.cmd.buttons & BT_JUMP
			if p.charability2 == CA2_SPINDASH
				p.charability2 = CA2_NONE
			end
			if p.mo.momz*P_MobjFlip(p.mo) > 0
				p.mo.state = S_PLAY_TRICKUP
			else
				p.mo.state = S_PLAY_TRICKDOWN
			end
		end
		if p.trickboostcount > 0 
			p.mo.state = S_PLAY_TRICKUP
		end
	end
	--the actual flipping
	if (p.mo.state == S_PLAY_TRICKUP or p.mo.state == S_PLAY_TRICKDOWN) --and not (p.pflags & PF_JUMPED) and p.cantrick == true
		if p.cmd.buttons & BT_JUMP and p.rollspeed != nil
			if p.rollspeed < 17
				p.rollspeed = $ + 1
			end
			--p.drawangle = $ + 15*FRACUNIT
			p.frontflipinterrupter = true
			p.mo.rollangle = $ + FixedAngle(p.rollspeed*FRACUNIT)
		else
			p.rollspeed = 5
		end
		if p.cmd.buttons & BT_SPIN and p.rollspeed2 != nil
			if p.rollspeed2 and p.rollspeed2 < 17
				p.rollspeed2 = $ + 1
			end
			--p.drawangle = $ - 15*FRACUNIT
			p.frontflipinterrupter = true
			p.mo.rollangle = $ - FixedAngle(p.rollspeed2*FRACUNIT)
		else
			p.rollspeed2 = 5
		end
		--if your head is facing the floor...
		if p.mo.rollangle >= (ANGLE_180 - ANG10) or p.mo.rollangle <= (ANGLE_180 + ANG10)
			--print("works")
			p.trickboost1 = true
		end
		--if your feet are facing the floor...
		if p.mo.rollangle >= (ANG350) and p.mo.rollangle <= (ANG10)
			--print("works2")
			p.trickboost2 = true
			--if not (S_SoundPlaying(p.mo, sfx_kc48))
				--S_StartSound(p.mo, sfx_kc48)
			--end
		end
		--if you've done a complete spin, add 1 to the counter
		if p.trickboost1 == true and p.trickboost2 == true and p.trickboostcount < 10
			p.trickboost1 = false
			p.trickboost2 = false
			--P_SpawnParaloop(p.mo.x, p.mo.y, p.mo.z, 80*FRACUNIT, 10, MT_NIGHTSPARKLE, 180*FRACUNIT, S_NULL, true)
			p.trickboostcount = $ + 1
			--if not (S_SoundPlaying(p.mo, sfx_kc48))
			for i = 1, 25 do
				local trickeffect = 
				P_SpawnMobjFromMobj(p.mo, P_RandomRange(-10, 10) * FRACUNIT, P_RandomRange(-10, 10) * FRACUNIT, 20*FRACUNIT, MT_BOXSPARKLE) 
					trickeffect.momx = P_RandomRange(-9, 9) * FRACUNIT-- + p.mo.momx
					trickeffect.momy = P_RandomRange(-9, 9) * FRACUNIT-- + p.mo.momy
					trickeffect.momz =  P_RandomRange(-9, 9) * FRACUNIT-- + p.mo.momz
					trickeffect.fuse = 10
					trickeffect.scale = p.mo.scale *P_RandomRange(-1, 2)
					trickeffect.source = p.mo
					trickeffect.flags = $ | MF_NOCLIP
					trickeffect.flags = $ | MF_NOCLIPHEIGHT
			end
			if p.trickboostcount <= 9
				S_StartSound(p.mo, sfx_kc48)
			else
				S_StartSound(p.mo, sfx_cdfm73)
			end
		end
	else
		--if you land on your feet, do a boost. if you don't, do a faceplant.
		if P_IsObjectOnGround(p.mo) and p.trickboostcount > 0 and p.mo.health
			--print("test")
			if p.mo.rollangle <= ANG60 and p.mo.rollangle >= ANG350 - ANG30 - ANG20
				P_InstaThrust(p.mo, p.mo.angle, (p.speed + p.trickboostpower*FRACUNIT))
				S_StartSound(p.mo, sfx_zoom)
				if p.mo.skin == "sonic" or p.mo.skin == "altsonic" or p.mo.skin == "srbii" or p.mo.skin == "ass"
					if P_RandomRange(0, 5) == 5 and p.trickboostcount < 10 
						S_StartSound(p.mo, sfx_cdpcm4)
					end
					if p.trickboostcount == 10 
						S_StartSound(p.mo, sfx_cdpcm2)
					end
				end
				p.trickboostcount = 0 
				p.trickboostpower = 0 
			else
				p.mo.state = S_PLAY_FACEPLANT
				p.pflags = $ | PF_FULLSTASIS
				--p.pflags = $ | PF_THOKKED
				if P_RandomRange(0, 15) == 10
					S_StartSound(p.mo, sfx_sqeakt)
				end
				if P_RandomRange(0, 35) == 10 and not S_SoundPlaying(p.mo, sfx_sqeakt)
					S_StartSound(p.mo, sfx_awfuck)
				end
				if not S_SoundPlaying(p.mo, sfx_sqeakt) and not S_SoundPlaying(p.mo, sfx_awfuck)
				S_StartSound(p.mo, sfx_kc46)
				end
				p.trickboostcount = 0
				p.trickboostpower = 0
			end
		end
		--if p.rollangleexception == false and not (p.powers[pw_carry] == CR_NIGHTSMODE)
			--p.mo.rollangle = FixedAngle(0*FRACUNIT)
		--end
		p.frontflipinterrupter = false
		--p.trickboostcount = 0 
		--p.trickboostpower = 0
	end
	if (p.xmomlaststate == S_PLAY_TRICKUP or p.xmomlaststate == S_PLAY_TRICKDOWN) and p.mo.state != S_PLAY_TRICKUP and p.mo.state != S_PLAY_TRICKDOWN
		p.mo.rollangle = FixedAngle(0*FRACUNIT)
		--print("reset rollangle")
	end
	--print(p.xmomlaststate)
	p.xmomlaststate = p.mo.state
	--print(p.trickboostcount)
	--lock controls until you fully stop after a faceplant
	if p.mo.state == S_PLAY_FACEPLANT
		if p.speed > 1*FRACUNIT
			 p.pflags = $ | PF_FULLSTASIS
		else
			p.pflags = $ & ~ PF_FULLSTASIS
			p.pflags = $ | PF_STASIS
		end
	end
	if p.laststate
		if p.laststate == S_PLAY_FACEPLANT and p.mo.state != S_PLAY_FACEPLANT and (p.pflags & PF_STASIS or p.pflags & PF_FULLSTASIS)
			p.pflags = $ & ~ PF_STASIS
			p.pflags = $ & ~ PF_FULLSTASIS
		end
	end
	if (p.mo.eflags & MFE_SPRUNG) --or p.mo.state == S_PLAY_SPRING
		p.cantrick = true
	end
	if P_IsObjectOnGround(p.mo) --or (p.mo.state != S_PLAY_SPRING or p.mo.state != S_PLAY_FALL)
		p.springing = false
	end
	/////oh boy its the values
	/*if p.trickboostcount == 0 
		p.trickboostpower = 0
	end
	if p.trickboostcount == 1
		p.trickboostpower = 10
	end
	if p.trickboostcount == 2
		p.trickboostpower = 20
	end
	if p.trickboostcount == 3
		p.trickboostpower = 30
	end
	if p.trickboostcount == 4
		p.trickboostpower = 35
	end
	if p.trickboostcount == 5
		p.trickboostpower = 45
	end
	if p.trickboostcount == 6
		p.trickboostpower = 47
	end
	if p.trickboostcount == 7
		p.trickboostpower = 50
	end
	if p.trickboostcount == 8
		p.trickboostpower = 52
	end
	if p.trickboostcount == 9
		p.trickboostpower = 55
	end
	if p.trickboostcount == 10
		p.trickboostpower = 75
	end*/
	p.trickboostpower = boostpower[p.trickboostcount]
	
	---end of that bullshit thank god
	p.lastrollangle = p.mo.rollangle
	if p.mo.state != S_PLAY_TRICKDOWN and p.mo.state != S_PLAY_TRICKUP
		p.trickboostcount = 0 
		p.trickboostpower = 0
	end
	if p.powers[pw_carry] == CR_DUSTDEVIL
		p.cantrick = true
	end
	if p.steamvented == true and p.mo.state == S_PLAY_FALL
		p.cantrick = true
		p.steamvented = false
	end
	if p.mo.state == S_PLAY_TRICKUP and p.mo.momz*P_MobjFlip(p.mo) <= 0 
		p.mo.state = S_PLAY_TRICKDOWN
	end
	if p.mo.state == S_PLAY_TRICKDOWN and p.mo.momz*P_MobjFlip(p.mo) > 0
		p.mo.state = S_PLAY_TRICKUP
	end
	--print(p.steamvented)
	if P_IsObjectOnGround(p.mo)
		p.cantrick = false
		p.trickboost1 = false
		p.trickboost2 = false
	end
	if (p.mo.state != S_PLAY_TRICKUP and p.mo.state != S_PLAY_TRICKDOWN) and (p.statelast == S_PLAY_TRICKUP or p.statelast == S_PLAY_TRICKDOWN)
		p.charability2 = p.oldability
	end
	p.statelast = p.mo.state
	--print(p.springing)
	if p.mo.state != S_PLAY_TRICKUP and p.mo.state != S_PLAY_TRICKDOWN
		p.oldability = p.charability2
	end
	
	if p.carttricks == true and not (p.powers[pw_carry] == CR_MINECART)
		p.cantrick = true
	end
	
	if (p.powers[pw_carry] == CR_MINECART)
		p.carttricks = true
	else
		p.carttricks = false
	end
	
	if (p.mo.skin == "vanillasonic" or p.mo.skin == "vanillatails" or p.mo.skin == "juniosonic") return end
	///////////////////////////////
	--waterrun local'd thing
	local function IsRunningOnWater(p)
		local waterBlock = p.mo.floorrover

		if (p.mo.eflags & MFE_VERTICALFLIP) then
			waterBlock = p.mo.ceilingrover
		end

		if (waterBlock) then
			return P_CanRunOnWater(p, waterBlock)
		end
	end
	///////////////////////////////
	--water running at high speeds
	if p.mo.skin != "srbii"
		if (p.speed >= 60*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) and p.speed <= 55*FRACUNIT
				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 >= 60*FRACUNIT
			if not IsRunningOnWater(p)
			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
		end
		local slope = p.mo.standingslope

		if slope and slope.valid
			local sector = P_ThingOnSpecial3DFloor(p.mo)
			if sector and sector.valid
				if sector.special & 3
					--print("lava slope")
					p.isonlavafof = true
				end
			end
		end
		--print(p.isonlavafof)
		if p.speed >= p.runspeed
		and P_IsObjectOnGround(p.mo)
		and IsRunningOnWater(p)
			if not p.waterboost
			and not p.waterboost2
				p.waterboost = P_SpawnMobjFromMobj(p.mo, -40*cos(p.drawangle + ANGLE_45), -40*sin(p.drawangle + ANGLE_45), 0, MT_WATER_BOOST)
				p.waterboost2 = P_SpawnMobjFromMobj(p.mo, -40*cos(p.drawangle - ANGLE_45), -40*sin(p.drawangle - ANGLE_45), 0, MT_WATER_BOOST)
				p.waterboost.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.waterboost.x, p.waterboost.y) --- ANG15
				p.waterboost2.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.waterboost2.x, p.waterboost2.y) --+ ANG15
			end
			if p.waterboost
				and p.waterboost2
				and p.waterboost.valid
				and p.waterboost2.valid
					p.waterboost.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.waterboost.x, p.waterboost.y) --- ANG15
					P_TeleportMove(p.waterboost, p.mo.x + (-40*cos(p.drawangle + ANGLE_45)), p.mo.y + (-40*sin(p.drawangle + ANGLE_45)), p.mo.z)
					p.waterboost2.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.waterboost2.x, p.waterboost2.y) --+ ANG15
					P_TeleportMove(p.waterboost2, p.mo.x + (-40*cos(p.drawangle - ANGLE_45)), p.mo.y + (-40*sin(p.drawangle - ANGLE_45)), p.mo.z)
					p.waterboost.anim_duration = p.mo.tics
					p.waterboost2.anim_duration = p.mo.tics
					if p.mo.eflags & MFE_TOUCHLAVA or p.isonlavafof == true
						p.waterboost.colorized = true
						p.waterboost.color = SKINCOLOR_KETCHUP
						p.waterboost2.colorized = true
						p.waterboost2.color = SKINCOLOR_KETCHUP
					else
						p.waterboost.colorized = false
						p.waterboost2.colorized = false
					end
				end
			else
				if p.waterboost
				and p.waterboost2
				and p.waterboost.valid
				and p.waterboost2.valid
					P_RemoveMobj(p.waterboost)
					P_RemoveMobj(p.waterboost2)
					p.waterboost = nil
					p.waterboost2 = nil
				end
			end
		end
		p.isonlavafof = false
	--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
	--actual thrusting
	/*if FixedHypot(abs(p.cmd.forwardmove), abs(p.cmd.sidemove)) > 5
		if (p.mo.state == S_PLAY_STND or p.mo.state == S_PLAY_WAIT) 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*/
	
	
		////////////////////////////
	--momentum adders/bonus acceleration
	--idfk how to do this lmfao
	--if p.mo.skin != "altsonic"
	--if not p.machspeedmode
	if not p.hasnomomentum
		if p.lastz > p.mo.z and P_IsObjectOnGround(p.mo) and (p.pflags & PF_SPINNING)
			P_Thrust(p.mo, R_PointToAngle2(p.mo.x, p.mo.y, p.lastx, p.lasty)+FixedAngle(180*FRACUNIT), max(0, min((p.mo.z-p.lastz)/20*-1, 10*p.mo.scale)))
		end
		--if /*p.lastz <= p.mo.z and*/ P_IsObjectOnGround(p.mo) and p.mo.state != S_PLAY_ROLL and not MAPPERSEDITION
			--if p.speed > p.runspeed
				--P_Thrust(p.mo, playertrueangle, p.speed/200)
			--end
		--end
	end
	
	p.lastz = p.mo.z
	p.lastx = p.mo.x
	p.lasty = p.mo.y
	--I think this works??? maybe??? It has some issues, there's this one bit in gfz2 where you can abuse the fuck out of it, but eh
	//////////////////////////////
	--Fly Burst
	if skins[p.mo.skin].ability == CA_FLY and not (skins[p.mo.skin].flags & SF_MULTIABILITY)and not (p.mo.skin == "eggman") and not p.bot
		p.charability = CA_SWIM
		if not (p.mo.eflags & MFE_UNDERWATER)
			if p.mo.state == S_PLAY_FLY or p.mo.state == S_PLAY_FLY_TIRED
				p.pflags = $ | PF_THOKKED
				if leveltime % 10 == 0 and p.mo.state == S_PLAY_FLY
					S_StartSound(p.mo, sfx_putput)
				end
				if leveltime % 10 == 0 and p.mo.state == S_PLAY_FLY_TIRED
					S_StartSound(p.mo, sfx_pudpud)
				end
				local flip = P_MobjFlip(p.mo)
				if p.cmd.buttons & BT_USE and p.xmomspindown == false
					p.flydestimer = 8
				end
				if not (p.cmd.buttons & BT_USE) and p.flydestimer > 0 and p.flydowntimer == 0 
					--print("hey it works holy shit")
					P_SetObjectMomZ(p.mo, -12*FRACUNIT)
					p.flydowntimer = 12
					--if p.mo.state != S_PLAY_FLY_TIRED and p.flightcounter < 3
						--p.flightcounter = $ - 1
					--end
				end
				if p.mo.momz * flip < 0 and not ((p.cmd.buttons & BT_USE) and p.flydestimer == 0) and p.flydowntimer == 0
					
					p.mo.momz = $ - P_GetMobjGravity(p.mo)*3/4
					if p.mo.momz/flip < -6*p.mo.scale then -- is the unflipped momz less than -6 * their scale?
						P_SetObjectMomZ(p.mo, 1*FRACUNIT/2, true) -- set to -6*FRACUNIT based off of flip and scale
					end
				end
				--print(p.flydowntimer)
				if p.flightcounter == 3 and not (p.mo.state == S_PLAY_FLY_TIRED)
					p.mo.state = S_PLAY_FLY_TIRED
				end
				if p.flydestimer > 0
					p.flydestimer = $ - 1
				end
				if p.flydowntimer > 0
					p.flydowntimer = $ - 1
				end
				if p.cmd.buttons & BT_SPIN
					p.xmomspindown = true
				else
					p.xmomspindown = false
				end
			else
				p.flydestimer = 0 
				p.flydowntimer = 0
			end
		end
		if (p.powers[pw_super] and p.hyper.capable == true and p.pflags & PF_THOKKED) or (p.mo.state == S_PLAY_FLY or p.mo.state == S_PLAY_FLY_TIRED)
			p.pflags = $ | PF_CANCARRY
			else
			p.pflags = $ & ~ PF_CANCARRY
		end
		if P_IsObjectOnGround(p.mo) or p.powers[pw_carry] or (p.mo.eflags & MFE_JUSTHITFLOOR)
			p.flightcounter = 0 
		end
		if p.pflags & PF_CANCARRY
			--print("fml")
		end
		if (p.mo.eflags & MFE_UNDERWATER) and p.mo.state == S_PLAY_FLY_TIRED
			p.mo.state = S_PLAY_SWIM
		end
	end
	/////////////////////////////
	--amee brhuj
	if p.mo.skin == "amy"
		--p.charability = CA_NONE
		if p.mo.state == S_PLAY_AMYFALL
			if p.mo.momz <= -7*FRACUNIT*P_MobjFlip(p.mo) and not (p.cmd.buttons & BT_USE)
				P_SetObjectMomZ(p.mo, -7*FRACUNIT, false)
			end
			--s3k42
			if leveltime % 10 == 0
				S_StartSound(p.mo, sfx_s3k42)
			end
		end
		if P_IsObjectOnGround(p.mo) or p.powers[pw_carry] or (p.mo.eflags & MFE_JUSTHITFLOOR)
			p.amybruh = true
		end
		if (p.mo.eflags & MFE_SPRUNG) and p.amycanspring == true
			p.mo.momz = $*5/4
			p.mo.momx = $*5/4
			p.mo.momy = $*5/4
			S_StartSound(p.mo, sfx_sprong)
		end
		if p.powers[pw_super] and p.hyper.capable == true and p.mo.state != S_PLAY_AMYFALL and p.amycanspring == true and p.cmd.buttons & BT_JUMP and not P_IsObjectOnGround(p.mo)
			p.mo.state = S_PLAY_AMYFALL
		end
		if p.mo.state == S_PLAY_AMYFALL
			p.amycanspring = true
		else
			p.amycanspring = false
		end
		if p.mo.state != S_PLAY_MELEE_LANDING --and p.mo.state != S_PLAY_MELEE_FINISH  
			p.amyspeeb = p.speed
		end
		if p.mo.state == S_PLAY_MELEE_LANDING and p.cmd.buttons & BT_JUMP
			p.amytimer = 12
			p.cantrick = false
			if not p.powers[pw_super] and not p.hyper.capable == true
				P_SetObjectMomZ(p.mo, p.amyspeeb*2/5, false)
			else
				P_SetObjectMomZ(p.mo, p.amyspeeb*6/10, false)
			end
			P_InstaThrust(p.mo, p.mo.angle, p.amyspeeb)
			p.mo.state = S_PLAY_ROLL
		end
		if p.powers[pw_super] and p.hyper.capable == true
			p.amybruh = true
			/*if p.mo.state == S_PLAY_AMYFALL and p.cmd.buttons & BT_JUMP
				P_SetObjectMomZ(p.mo, 7*FRACUNIT, false)
			end*/
		end
		if p.amytimer == 1
			if p.mo.state == S_PLAY_ROLL
				if p.mo.momz > 0 
					p.mo.state = S_PLAY_SPRING
				else
					p.mo.state = S_PLAY_FALL
				end
			end
		end
		if p.amytimer > 0 
			p.amytimer = $ - 1
		end
		--print(p.amyspeeb/FRACUNIT)
	end
	p.lastskin = p.mo.skin
	/////////////////////////////
	--metal thingies
	if (p.charflags & SF_DASHMODE)
		if p.mo.skin != "altsonic"
			if p.powers[pw_carry]
			or p.mo.state == S_PLAY_PAIN
			or p.playerstate == PST_DEAD
			or p.exiting
				p.wasmetdashing = false
			end
			if not P_IsObjectOnGround(p.mo)
				if p.wasmetdashing == true
					--print("FUCK")
					p.dashmode = max(p.dashmode, 3*36)
				end
			end
		end
		if p.mo.skin == "metalknuckles"
			if p.mo.state == S_PLAY_SPINDASH
				p.mo.state = S_PLAY_METALDASH
			end
		end
		if p.mo.skin == "metalsonic"
			if p.mo.state == S_PLAY_SPINDASH
				p.mo.state = S_PLAY_METALDASH
			end
			if (p.powers[pw_carry] == CR_ROLLOUT)
				p.drawangle = playertrueangle
			end
            if p.dashmode > 3*TICRATE
                if (((leveltime-3)/2) & 1)
                    p.mo.colorized = true
                    p.mo.color = SKINCOLOR_METALSONICAURA
                else
					if not (p.powers[pw_super] and p.hyper.capable == true)
						p.mo.colorized = false
						if not p.powers[pw_super]
							p.mo.color = p.skincolor
						else
							p.mo.color = SKINCOLOR_ORANGE
						end
					else
						p.mo.color = p.skincolor
						p.mo.colorized = false
					end
                end
				if p.mo.state == S_PLAY_DASH
					local dasheffect = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT*p.mo.scale, MT_DASHMODETRAIL)
					dasheffect.angle = p.drawangle
					dasheffect.fuse = 3
					dasheffect.scale = p.mo.scale
					dasheffect.rollangle = p.mo.rollangle
				end
				if p.mo.state == S_PLAY_SPRING
					local dasheffect = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT*p.mo.scale, MT_DASHMODETRAILJUMP)
					dasheffect.angle = p.drawangle
					dasheffect.fuse = 3
					dasheffect.scale = p.mo.scale
					dasheffect.rollangle = p.mo.rollangle
				end
				if p.mo.state == S_PLAY_FALL
					local dasheffect = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT*p.mo.scale, MT_DASHMODETRAILFALL)
					dasheffect.angle = p.drawangle
					dasheffect.fuse = 3
					dasheffect.scale = p.mo.scale
					dasheffect.rollangle = p.mo.rollangle
				end
				if p.mo.state == S_PLAY_TRICKUP
					local dasheffect = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT*p.mo.scale, MT_DASHMODETRAILJUMP)
					dasheffect.angle = p.drawangle
					dasheffect.fuse = 3
					dasheffect.scale = p.mo.scale
					dasheffect.rollangle = p.mo.rollangle
				end
				if p.mo.state == S_PLAY_TRICKDOWN
					local dasheffect = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT*p.mo.scale, MT_DASHMODETRAILFALL)
					dasheffect.angle = p.drawangle
					dasheffect.fuse = 3
					dasheffect.scale = p.mo.scale
					dasheffect.rollangle = p.mo.rollangle
				end
				if p.mo.state == S_PLAY_ROLL or p.mo.state == S_PLAY_JUMP
					local dasheffect = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT*p.mo.scale, MT_DASHMODETRAILROLL)
					dasheffect.angle = p.drawangle
					dasheffect.fuse = 3
					dasheffect.scale = p.mo.scale
					dasheffect.rollangle = p.mo.rollangle
				end
					local metalspark = P_SpawnMobjFromMobj(p.mo, 0, 0, 20*FRACUNIT, MT_WATERZAP)
						metalspark.momx = P_RandomRange(-9, 9) * FRACUNIT
						metalspark.momy = P_RandomRange(-9, 9) * FRACUNIT
						metalspark.momz =  P_RandomRange(-9, 9) * FRACUNIT
            else
				if p.mo.colorized == true
					p.mo.colorized = false
					if not p.powers[pw_super]
						p.mo.color = p.skincolor
					end
				end
			end
		end
		/*if p.metalstatelast
			if (p.mo.state == S_PLAY_ROLL) and (p.metalstatelast == S_PLAY_METALDASH) and P_IsObjectOnGround(p.mo)
				p.mo.state = S_PLAY_RUN
				p.pflags = $ & ~ PF_SPINNING
			end
		end*/
		p.metalstatelast = p.mo.state
		if p.dashmode > 3*TICRATE 
			p.wasmetdashing = true
		end
		if P_IsObjectOnGround(p.mo)
			if p.dashmode <= 3*TICRATE
				p.wasmetdashing = false
			end
		end
		--print(p.wasmetdashing)
	end
	if (p.mo.state == S_PLAY_HYPERTRNS_1
		or p.mo.state == S_PLAY_HYPERTRNS_2
		or p.mo.state == S_PLAY_HYPERTRNS_3
		or p.mo.state == S_PLAY_HYPERTRNS_4
		or p.mo.state == S_PLAY_HYPERTRNS_5
		or p.mo.state == S_PLAY_HYPERTRNS_6)
		p.hypertransforming = true
		p.pflags = $ | PF_FULLSTASIS
	else
		p.hypertransforming = false
	end
	/////////////////////////////
	--Fang Gang
	if p.mo.skin == "fang"
		--fuck vanilla gun. all my homies hate vanilla gun.
		p.charability2 = CA2_NONE
		--setting up the targeting
		if p.mo.state != S_PLAY_FIRE and p.mo.state != S_PLAY_FIRE_FINISH and p.mo.state != S_PLAY_AIRSHOOT and p.mo.state != S_PLAY_AIRSHOOT_FINISH or p.powers[pw_super] and p.hyper.capable == true
			p.popguntarget = P_LookForEnemies(p, false, true)
		end
		if (p.popguntarget 
		and p.popguntarget.valid 
		and p.popguntarget.health)
			
			p.popgunangle = R_PointToAngle2(p.mo.x, p.mo.y, p.popguntarget.x, p.popguntarget.y)
			if p.mo.state == S_PLAY_WALK 
			or p.mo.state == S_PLAY_RUN 
			or (p.pflags & PF_JUMPED) 
			or p.mo.state == S_PLAY_STND 
			or p.mo.state == S_PLAY_WAIT
				P_SpawnLockOn(p, p.popguntarget, S_LOCKON1)
			end
		end
		if p.mo.state == S_PLAY_WALK or p.mo.state == S_PLAY_RUN or (p.pflags & PF_JUMPED and p.hypertransforming == false) or p.mo.state == S_PLAY_STND or p.mo.state == S_PLAY_WAIT or p.mo.state == S_PLAY_FIRE or p.mo.state == S_PLAY_FIRE_FINISH or p.mo.state == S_PLAY_AIRSHOOT or p.mo.state == S_PLAY_AIRSHOOT_FINISH
			if p.cmd.buttons & BT_SPIN and p.fangspindown == true and p.fangcooldown == 0 or p.cmd.buttons & BT_SPIN and p.powers[pw_super] and p.hyper.capable == true
				if p.popguntarget and p.popguntarget.valid
					P_SpawnMissile(p.mo, p.popguntarget, MT_CORK)
					p.fangcooldown = 20
				else
					P_SPMAngle(p.mo, MT_CORK,p.mo.angle)
					p.fangcooldown = 20
				end
				if P_IsObjectOnGround(p.mo)
					if p.mo.state != S_PLAY_FIRE and p.mo.state != S_PLAY_FIRE_FINISH
						--if p.speed <= 10*FRACUNIT
						p.cantrick = false
						p.frontflipinterrupter = true
						p.spcanflip = false
						p.mo.state = S_PLAY_FIRE
						--else
						--	p.mo.state = S_PLAY_AIRSHOOT
						--end
						if (p.powers[pw_super] and p.hyper.capable == true)
							p.pflags = $ | PF_JUMPED
						end
						S_StartSound(p.mo, sfx_corkp)
						if not (p.mo.eflags & MFE_UNDERWATER)
							P_SetObjectMomZ(p.mo, 4*FRACUNIT, false)
						else
							P_SetObjectMomZ(p.mo, 2*FRACUNIT + 1*FRACUNIT/2, false)
						end
						if p.popguntarget
							p.drawangle = p.popgunangle
						end
					end
				else
					if p.mo.state != S_PLAY_AIRSHOOT and p.mo.state != S_PLAY_AIRSHOOT_FINISH
						p.cantrick = false
						p.frontflipinterrupter = true
						p.spcanflip = false
						p.mo.state = S_PLAY_AIRSHOOT
						if not p.powers[pw_super]
							p.charflags = $ & ~ SF_SUPER
						end
						if not (p.powers[pw_super] and p.hyper.capable == true)
							p.pflags = $ & ~ PF_JUMPED
						end
						S_StartSound(p.mo, sfx_corkp)
						--if p.popguntarget
							--p.drawangle = p.popgunangle
						--end
					end
				end
			end
		end
		if p.fangcooldown == nil
			p.fangcooldown = 0 
		end
		if p.fangcooldown > 0
			p.fangcooldown = $ - 1
		end
		if p.mo.state == S_PLAY_FIRE or p.mo.state == S_PLAY_FIRE_FINISH or p.mo.state == S_PLAY_AIRSHOOT or p.mo.state == S_PLAY_AIRSHOOT_FINISH
			if p.popguntarget
				if p.popguntarget.valid and p.popguntarget.health
					p.drawangle = p.popgunangle
				end
			end
		end
		--i hate how you cant use spindown in a playerthink
		if p.fangspindown == nil
			p.fangspindown = false
		end
		if p.cmd.buttons & BT_SPIN
			p.fangspindown = false
		else
			p.fangspindown = true
		end
	end
	/////////////////////////////
	--Momentum Thok
    if p.mo and p.mo.valid and skins[p.mo.skin].ability == CA_THOK 
	and not (p.mo.skin == "vanillasonic" or p.mo.skin == "robo-hood" or p.mo.skin == "msonic" or p.mo.skin == "altsonic" or p.mo.skin == "ray" or p.mo.skin == "inazuma" or p.mo.skin == "rafael" or p.mo.skin == "srbii" and not p.powers[pw_super] or p.mo.skin == "srbii" and p.powers[pw_super] and p.hyper.capable == false)
		--p.charability = CA_NONE
		if not p.powers[pw_super]
			p.thokforce = p.speed + p.speed / 6
			p.thokforceold = p.speed + 15*FRACUNIT
			else
			if p.hyper.capable
				p.thokforce = p.speed + p.speed / 2
				p.thokforceold = p.speed + 40*FRACUNIT
			else
				p.thokforce = p.speed + p.speed / 4
				p.thokforceold = p.speed + 40*FRACUNIT
			end
		end
			if p.speed > skins[p.mo.skin].normalspeed
				p.thokupforce = p.thokforceold / 7
			else
				p.thokupforce = 7*FRACUNIT
			end
		if p.thokupforce < 6*FRACUNIT
			p.thokupforce = 6*FRACUNIT
		end
		if (p.pflags & PF_JUMPED) and p.cmd.buttons & BT_JUMP and not P_IsObjectOnGround(p.mo)
			if p.thoktimer == 1
				--if p.speed > skins[p.mo.skin].normalspeed
					if p.mo.state != S_PLAY_FLOAT and p.mo.state != S_PLAY_FLOAT_RUN
						P_SetObjectMomZ(p.mo, p.thokupforce, false)
					end
					p.pflags = $ | PF_STARTJUMP
					
				--else
					--P_SetObjectMomZ(p.mo, 10*FRACUNIT, false)
				--end
			end
		end
		if p.thoktimer > 0
			p.thoktimer = $ - 1
		end
        if p.pflags & PF_THOKKED and p.thokeffects == true and p.mo.state != S_PLAY_FLOAT and p.mo.state != S_PLAY_FLOAT_RUN and not (p.hyper.capable == true and p.powers[pw_super])
			local AfterImageSpawn = P_SpawnGhostMobj(p.mo)
			if p.powers[pw_super]
				AfterImageSpawn.color = p.mo.color
				else
				if p.mo.color == SKINCOLOR_BLUE
					AfterImageSpawn.color = 98
				else
					AfterImageSpawn.color = p.mo.color
				end
			end
			AfterImageSpawn.colorized = true
		end
    end
	///////////////////////////////
	--Super Transformation handler
	if p.mo.skin != "robe" and p.mo.skin != "modernsonic"
		if skins[p.mo.skin].flags & SF_SUPER or (p.mo.skin == "juniosonic")
			if (p.mo.state == S_PLAY_FLY or p.mo.state == S_PLAY_FLY_TIRED)
				if not p.powers[pw_super]
					p.charflags = $ & ~ SF_SUPER
				end
			else
				--S_StartSound(p.mo, sfx_zoom)
				p.charflags = $ | SF_SUPER
			end
		end
	end
end)
local debug = 0
local UNCURL_LOCKTIME = 8
/*addHook('ThinkFrame', do
	--The momentum mod
	for player in players.iterate do
		if not (player.mo.skin == "vanillasonic" or player.mo.skin == "vanillatails" or player.mo.skin == "juniosonic" or player.mo.skin == "srbii" or player.mo.skin == "sms") and not player.mo.skipcrouching and not player.boomspindash --or (player.mo.flags2 & MF2_TWOD)
		and player.hasnomomentum == false	
			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
				if player.mo.skin == "altsonic"
					if player.speed <= 47*FRACUNIT
						nmom = skins[player.mo.skin].normalspeed
					else
						nmom = skins["sonic"].normalspeed
					end
				end
				//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] and not player.hyper.capable) //Speed-ups multiply max allowed speed by 5/3
				local hyper = (player.powers[pw_super] and player.hyper and player.hyper.capable) //being hyper makes you go sicko mode
				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 and not hyper then
					pmom = $*3/5
				end
				if hyper then
					pmom = $*61/100
				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.
					--if not (player.mo.flags2 & MF2_TWOD)
					local sustain = FixedDiv(min(pmom*water,nmom*4),friction)
					--else
					--if (player.mo.flags2 & MF2_TWOD)
						--local sustain = FixedDiv(min(pmom*water,nmom),friction)
					--end
					--end
	-- 				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
end)*/
--custom momentum made with a lot less hacks then CBWMom, heavily referenced from ChrispyChars. 
--Originally was gonna launch this in v2.0, but that's taking forever so i'm putting it in this minor update.
addHook("PreThinkFrame", function(p)
	for p in players.iterate
		if (p.noxmomchar or p.xmomtoggledoff)
		return 
		end
		if p.xmlastz == nil
			p.xmlastspeed = p.speed
			p.xmlastz = p.mo.z
			p.xmlastx = p.mo.x
			p.xmlasty = p.mo.y
			p.xmlastmomx = p.mo.momx
			p.xmomlastmomy = p.mo.momy
			p.xmlaststate = p.mo.state
		end
		if p.fakenormalspeed == nil
			p.fakenormalspeed = skins[p.mo.skin].normalspeed
		end
		local watermul = 1
		if (p.mo.eflags & MFE_UNDERWATER)
			watermul = 2
		end
		if (p.mo and p.mo.valid and p.mo.health)
			if p.xmlastskin and p.xmlastskin != p.mo.skin
				p.hasnomomentum = false
			end
			p.xmlastskin = p.mo.skin
		end
		local speed = FixedDiv(FixedHypot(p.mo.momx - p.cmomx, p.mo.momy - p.cmomy), p.mo.scale)
		local SPEED_INCREASE_LEEWAY = 0*FRACUNIT // the amount of speed above normalspeed needed to update normalspeed
		local SPEED_DECREASE_LEEWAY = 15*FRACUNIT // the amount of speed below normalspeed needed to update normalspeed
			if not p.hasnomomentum and not (p.pflags & PF_SPINNING)
				if p.restoremymomentumafteruncurlingpleasethankyouuuuu
					p.normalspeed = max(p.restoremymomentumafteruncurlingpleasethankyouuuuu, p.fakenormalspeed)
					p.restoremymomentumafteruncurlingpleasethankyouuuuu = nil
				end
				if p.xmlastz*P_MobjFlip(p.mo) > p.mo.z*P_MobjFlip(p.mo) and P_IsObjectOnGround(p.mo) and not (p.mo.eflags & MFE_JUSTHITFLOOR)
					--P_Thrust(p.mo, R_PointToAngle2(p.mo.x, p.mo.y, p.xmlastx, p.xmlasty)+FixedAngle(180*FRACUNIT), max(FRACUNIT*2+FRACUNIT/2, min((p.mo.z-p.xmlastz)/4*-1, 7*p.mo.scale)))
					p.normalspeed = $ + (p.mo.z*P_MobjFlip(p.mo)-p.xmlastz*P_MobjFlip(p.mo))/25*-1
					--print("aAAAAA")
				elseif p.powers[pw_super] and p.hyper and p.hyper.capable
					if P_IsObjectOnGround(p.mo)
						p.normalspeed = $ + FRACUNIT/3
					end
				else
					if P_IsObjectOnGround(p.mo)
						p.normalspeed = $ + FRACUNIT/15
					end
				end
				--temporarily restoring how metal used to work in 1.2 
				--since I wouldn't want to make a major change to gameplay in a minor update
				local restorefakenormalspeed = p.fakenormalspeed
				if p.dashmode > 3*TICRATE
					p.fakenormalspeed = p.normalspeed
				end
				if not p.powers[pw_super] and not p.powers[pw_sneakers]
					if (speed*watermul > p.normalspeed + SPEED_INCREASE_LEEWAY
					or speed*watermul < p.normalspeed - SPEED_DECREASE_LEEWAY)
						p.normalspeed = max(speed*watermul, p.fakenormalspeed)
					end
				else
					if (speed*3/5*watermul > p.normalspeed + SPEED_INCREASE_LEEWAY
					or speed*3/5*watermul < p.normalspeed - SPEED_DECREASE_LEEWAY)
						--if not (p.powers[pw_sneakers])
						--if not (p.hyper and p.hyper.capable and p.powers[pw_super])
							p.normalspeed = max((speed*3/5)*watermul, p.fakenormalspeed)
						--else
							--p.normalspeed = max(min(speed*watermul, 160*FRACUNIT*watermul), p.fakenormalspeed)
						--end
							
					end
				end 
				p.fakenormalspeed = restorefakenormalspeed
				if p.normalspeed > 145*FRACUNIT*watermul
					p.normalspeed = $ - p.normalspeed/50
				end
			end
			local momangle = R_PointToAngle2(0,0,p.rmomx,p.rmomy) //Used for angling new momentum in ability cases
			local pmom = FixedDiv(FixedHypot(p.rmomx,p.rmomy),p.mo.scale) //Current speed, scaled for normalspeed calculations
			//Knuckles momentum renewal
			if p.charability == CA_GLIDEANDCLIMB then
				//Create glide history
				if p.glidelast == nil then
					p.glidelast = 0
				end
				local gliding = p.pflags&PF_GLIDING
				local thokked = p.pflags&PF_THOKKED
				local exitglide = (p.glidelast == 1 and not(gliding) and thokked)
				local landglide = (p.glidelast == 2 and not(gliding|thokked))
				//Restore glide momentum after deactivation
				if exitglide or landglide then
					p.mo.momx = p.xmlastmomx
					p.mo.momy = p.xmlastmomy
				end
				//Update glide history
				if gliding then
					p.glidelast = 1 //Gliding
				elseif exitglide then
					p.glidelast = 2 //Falling from glide
				elseif not(gliding|thokked) then
					p.glidelast = 0 //Not in glide state
				end
			end
				
			//////
			//Fang momentum renewal
			if p.charability == CA_BOUNCE then
				//Create bounce history
				if p.bouncelast == nil then
					p.bouncelast = false
				end
				if p.pflags&PF_BOUNCING and not(p.bouncelast) //Activate bounce
					or (not(p.pflags&PF_BOUNCING) and p.pflags&PF_THOKKED and p.bouncelast) //Deactivate bounce
					//Undo the momentum cut from bounce activation/deactivation
					p.mo.momx = p.xmlastmomx
					p.mo.momy = p.xmlastmomy
					p.mo.momz = $*2
				end
				//Update bounce history
				p.bouncelast = (p.pflags&PF_BOUNCING > 0)
			end
		p.xmlastspeed = p.speed
		p.xmlastz = p.mo.z
		p.xmlastx = p.mo.x
		p.xmlasty = p.mo.y
		p.xmlastmomx = p.mo.momx
		p.xmlastmomy = p.mo.momy
		p.xmlaststate = p.mo.state
		--local speed = FixedDiv(FixedHypot(p.mo.momx - p.cmomx, p.mo.momy - p.cmomy), p.mo.scale)
	end
end)
addHook("PlayerCanDamage", function(p, badnik)
	if p.mo and p.mo.health and p.mo.valid and p.mo.skin == "amy"
		if p.mo.state == S_PLAY_AMYFALL
			return true
		end
	end
end)
addHook("MobjDeath", function(target, inflictor, source)
    if source
    and source.player
    and (target.flags & MF_ENEMY) then
		if source.skin == "amy"
			if source.player.mo.state == S_PLAY_AMYFALL
				P_SetObjectMomZ(source.player.mo, 18*FRACUNIT, true)
				source.player.amybruh = true
			end
		end
    end
end) 
addHook("MobjMoveCollide", function(mobj, steam)
	if mobj and mobj.valid and mobj.player and mobj.health
		if steam and steam.valid and steam.type == MT_STEAM
			mobj.player.steamvented = true
		end
	end
end, MT_PLAYER)

addHook("TouchSpecial", function(token, p)
	if (p.player.noxmomchar or p.player.xmomtoggledoff)
	return 
	end
	if p.player and p.valid and p.health and token.valid
		if All7Emeralds(emeralds)
			p.player.rings = $ + 50 
		end
	end
end, MT_TOKEN)
addHook("MobjMoveCollide", function(mobj, tornado)
	if mobj and mobj.valid and mobj.player and mobj.health
		if tornado and tornado.valid and tornado.type == MT_DUSTDEVIL
			mobj.player.cantrick = true
		end
	end
end, MT_PLAYER)
addHook("JumpSpecial", function(p)
	if (p.noxmomchar or p.xmomtoggledoff)
	return 
	end
	if p.mo and p.mo.health and p.mo.valid
		if p.trickboostcount != nil
			if p.mo.state == S_PLAY_FACEPLANT and p.speed > 1*FRACUNIT or p.trickboostcount > 0 
				return true
			end
		end
	end
end)
addHook("SpinSpecial", function(p)
	if (p.noxmomchar or p.xmomtoggledoff)
	return 
	end
	if p.mo and p.mo.health and p.mo.valid
		if p.trickboostcount != nil
			if p.mo.state == S_PLAY_FACEPLANT and p.speed > 1*FRACUNIT or p.trickboostcount > 0 
				return true
			end
		end
	end
end)
/*addHook("PreThinkFrame", function(motherfuckingbitchfuckyoufuckfuckfuckfuck)
	for p in players.iterate
		if p.mo.skin == "metalsonic"
			if ((leveltime/2) & 1)
				if p.metalcolorfucker == true
					p.metalcolorfucker = false
				else
					p.metalcolorfucker = true
					--p.metalcolorfucker = true
				end
			end
			if p.dashmode > 3*TICRATE
				if p.metalcolorfucker == true
					p.mo.colorized = true
					p.mo.color = SKINCOLOR_PURPLE
				end
				if p.metalcolorfucker == false
					p.mo.colorized = false
					p.mo.color = p.skincolor
				end
			else
				p.mo.colorized = false
				p.mo.color = p.skincolor
			end
			print(p.metalcolorfucker)
		end
	end
end)*/
local spikekiller = function(thing, tmthing)
	if not (thing and thing.valid and tmthing and tmthing.valid) return end
	if tmthing.player and tmthing.skin == "amy" and ((tmthing.state == S_PLAY_AMYFALL))
	and (abs(thing.z - tmthing.z) <= 60*tmthing.scale)
		if tmthing.z >= thing.z-tmthing.height and tmthing.z <= thing.z+thing.height+tmthing.height
			P_KillMobj(thing, tmthing)
			return true
		end
	end
end
addHook("MobjCollide", function(thing, tmthing) spikekiller(thing, tmthing) end, MT_SPIKE)
addHook("MobjCollide", function(thing, tmthing) spikekiller(thing, tmthing) end, MT_WALLSPIKE)
addHook("MobjThinker", function(mo)
    if not mo.source return end
    mo.lifetime = $ or 0
    --mo.x = mo.source.x + mo.lifetime * mo.momx
    --mo.y = mo.source.y + mo.lifetime * mo.momy
    --mo.z = mo.source.z + mo.lifetime * mo.momz
	P_TeleportMove(mo, mo.source.x, mo.source.y, mo.source.z + 17*FRACUNIT + mo.lifetime * mo.momz)
    mo.rollangle = $ + FixedAngle(9*FRACUNIT)
	if mo.source.player.powers[pw_super]
		mo.color = mo.source.color
	end
	if mo.source.player.hyper.capable == true and mo.source.player.powers[pw_super]
		mo.colorized = true
	else
		mo.colorized = false
	end
end, MT_STARTHOK)
addHook("MobjThinker", function(mo)
    if not mo.source return end
    mo.lifetime = $ or 0
    --mo.x = mo.source.x + mo.lifetime * mo.momx
    --mo.y = mo.source.y + mo.lifetime * mo.momy
    --mo.z = mo.source.z + mo.lifetime * mo.momz
	P_TeleportMove(mo, mo.source.x + mo.lifetime * mo.momx, mo.source.y + mo.lifetime * mo.momy, mo.source.z + 17*FRACUNIT + mo.lifetime * mo.momz)
    mo.lifetime = $ + 1
end, MT_BOXSPARKLE)
addHook("ShouldDamage", function(trg, inf, src)
	if trg and trg.valid and trg.health and trg.player and trg.skin == "amy" and (trg.state == S_PLAY_AMYFALL or trg.state == S_PLAY_TWINSPIN)
		if src and src.valid and src.type == MT_GSNAPPER
			return false
		end
	end
end, MT_PLAYER)
addHook("JumpSpinSpecial", function(p)
	if p.mo and p.mo.valid and skins[p.mo.skin].ability == CA_THOK and p.powers[pw_super] and not p.hyper.capable
	and not (p.mo.skin == "vanillasonic" or p.mo.skin == "robo-hood" or p.mo.skin == "msonic" or p.mo.skin == "altsonic" or p.mo.skin == "ray" or p.mo.skin == "inazuma" or p.mo.skin == "rafael")
	and p.speed > 5*p.mo.scale
	and P_MobjFlip(p.mo)*p.mo.momz <= 0
		if p.speed >= FixedMul(p.runspeed, p.mo.scale)
			if p.mo.state != S_PLAY_FLOAT_RUN
				p.mo.state = S_PLAY_FLOAT_RUN
			end
		else
			if p.mo.state != S_PLAY_FLOAT
				p.mo.state = S_PLAY_FLOAT
			end
		end
		P_SetObjectMomZ(p.mo, 0*FRACUNIT)
		p.pflags = $&~(PF_STARTJUMP|PF_SPINNING)
	end
end)
hud.add(function(v, player, cam)
	if player.mo and ((player.mo.state != S_PLAY_TRICKUP) and (player.mo.state != S_PLAY_TRICKDOWN)) return end	
		if cam.chase == false
			v.draw(hudinfo[HUD_LIVES].x + 8, hudinfo[HUD_LIVES].y - 7, v.getSprite2Patch(player.mo.skin, SPR2_XTRA, false, C, 0, player.mo.rollangle), V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTOLEFT, v.getColormap(TC_DEFAULT, player.skincolor))
		end
	end, "game")
	
--Golden Shine: Added an Xmom Switch/Toggle that completely turns off or on all xmom behaviour for a particular player if they want.

COM_AddCommand("ToggleXmomentum", function(p)
	if not (p and p.valid)
	CONS_Printf(p, "\x85"+"Command failed. No player.")
	return
	end
	if p.xmomtoggledoff
	p.xmomtoggledoff = false
	CONS_Printf(p, "\x85"+"Xmomentum has now been switched back on.")
	else
	p.xmomtoggledoff = true
	if (p.mo)
		p.normalspeed = skins[p.mo.skin].normalspeed
		if p.hyper.capable and p.powers[pw_super]
			p.jumpfactor = skins[p.mo.skin].jumpfactor
			p.mindash = skins[p.mo.skin].mindash
			p.maxdash = skins[p.mo.skin].maxdash
			p.actionspd = skins[p.mo.skin].actionspd
			p.hyper.capable = false
			P_RestoreMusic(p)
		end
		if skins[p.mo.skin].ability != p.charability
			p.charability = skins[p.mo.skin].ability
		end
		if skins[p.mo.skin].ability2 != p.charability2
			p.charability2 = skins[p.mo.skin].ability2
		end
	end
	CONS_Printf(p, "\x85"+"Xmomentum has now been switched off for you")
	end
end)