addHook("PlayerThink", function(player)
	if ((player.playerstate == PST_LIVE) and not (player.powers[pw_carry]) and player.mo.state != S_PLAY_SUPER_TRANS1 and player.mo.state != S_PLAY_SUPER_TRANS2 and player.mo.state != S_PLAY_SUPER_TRANS3 and player.mo.state != S_PLAY_SUPER_TRANS4 and player.mo.state != S_PLAY_SUPER_TRANS5 and player.mo.state != S_PLAY_SUPER_TRANS6 and (player.mo.skin == "sonic" or player.mo.skin == "tails" or player.mo.skin == "knuckles" or player.mo.skin == "amy" or player.mo.skin == "fang" or player.mo.skin == "metalsonic" or player.mo.skin == "espio" or player.mo.skin == "mighty" or player.mo.skin == "charmy" or player.mo.skin == "vector" or player.mo.skin == "heavy" or player.mo.skin == "bomb" or player.mo.skin == "ray" or player.mo.skin == "shadow" or player.mo.skin == "tangle" or player.mo.skin == "whisper" or player.mo.skin == "surge"))
		player.jumpfactor = skins[player.mo.skin].jumpfactor
		if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and not (player.climbing))
			if (player.powers[pw_tailsfly])
				if (player.cmd.buttons & BT_JUMP and not (player.plusbuttons & BT_JUMP) and player.speed >= FixedMul(8*FRACUNIT, player.mo.scale) and player.speed >= FixedMul(skins[player.mo.skin].normalspeed/2, player.mo.scale))
					P_Thrust(player.mo, R_PointToAngle2(0,0,player.mo.momx,player.mo.momy), FixedMul(4*FRACUNIT, player.mo.scale))
				end
				if (player.speed > FixedMul(skins[player.mo.skin].normalspeed/2, player.mo.scale) and not (player.cmd.forwardmove) and (player.cmd.sidemove or (player.cmd.angleturn and player.cmd.sidemove)))
					if (player.mo.eflags & MFE_UNDERWATER)
						player.thrustfactor = 3*(4*skins[player.mo.skin].thrustfactor)/2
					else
						player.thrustfactor = 4*skins[player.mo.skin].thrustfactor
					end
				elseif (player.speed > FixedMul(skins[player.mo.skin].normalspeed/2, player.mo.scale) and ((player.cmd.forwardmove and player.cmd.sidemove) or (player.cmd.angleturn and player.cmd.forwardmove and player.cmd.sidemove)))
					if (player.mo.eflags & MFE_UNDERWATER)
						player.thrustfactor = 3*(8*skins[player.mo.skin].thrustfactor)/2
					else
						player.thrustfactor = 8*skins[player.mo.skin].thrustfactor
					end
				else
					if (player.mo.eflags & MFE_UNDERWATER)
						player.thrustfactor = 3*(skins[player.mo.skin].thrustfactor)/2
					else
						player.thrustfactor = skins[player.mo.skin].thrustfactor
					end
				end
			elseif (player.pflags & PF_BOUNCING)
				if (player.mo.eflags & MFE_UNDERWATER)
					player.thrustfactor = 3*(8*skins[player.mo.skin].thrustfactor/3)/2
				else
					player.thrustfactor = 8*skins[player.mo.skin].thrustfactor/3
				end
			else
				if (player.mo.eflags & MFE_UNDERWATER)
					player.thrustfactor = 3*(2*skins[player.mo.skin].thrustfactor)/2
				else
					player.thrustfactor = 2*skins[player.mo.skin].thrustfactor
				end
			end
		elseif ((player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH) and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.mo.skin != "heavy" and player.mo.state != S_PLAY_SPINDASH)
			if (player.mo.eflags & MFE_UNDERWATER)
				player.thrustfactor = 3*(skins[player.mo.skin].thrustfactor/2)/2
			else
				player.thrustfactor = skins[player.mo.skin].thrustfactor/2
			end
		elseif ((player.mo.skin == "heavy" or player.mo.state == S_PLAY_SPINDASH) and (player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH) and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR))
			player.thrustfactor = 0
		else
			if (player.mo.eflags & MFE_UNDERWATER)
				player.thrustfactor = 3*(skins[player.mo.skin].thrustfactor)/2
			else
				player.thrustfactor = skins[player.mo.skin].thrustfactor
			end
		end
		if ((player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH) and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and not (player.mo.skin == "vector" and player.cmd.buttons & BT_SPIN) and not (player.mo.skin == "metalsonic" and player.dashmode >= 3*TICRATE))
			player.normalspeed = 0
		elseif (player.mo.skin == "espio" and player.climbing)
			if (player.powers[pw_sneakers] or player.powers[pw_super])
				player.normalspeed = 3*(20*FRACUNIT)/5
			else
				player.normalspeed = 20*FRACUNIT
			end
		else
			player.normalspeed = skins[player.mo.skin].normalspeed
		end
		if (player.mo.skin != "heavy" and (player.powers[pw_sneakers] or player.powers[pw_super]))
			if (player.mo.skin == "sonic" or player.mo.skin == "tails" or player.mo.skin == "knuckles" or player.mo.skin == "metalsonic" or player.mo.skin == "mighty" or player.mo.skin == "ray" or player.mo.skin == "espio" or player.mo.skin == "charmy" or player.mo.skin == "vector" or player.mo.skin == "bomb" or player.mo.skin == "shadow" or player.mo.skin == "surge")
				if (player.mo.eflags & MFE_UNDERWATER)
					player.mindash = 30*FRACUNIT
					player.maxdash = 36*FRACUNIT
				else
					player.mindash = 60*FRACUNIT
					player.maxdash = 72*FRACUNIT
				end
			end
			if (player.powers[pw_super])
				player.runspeed = 36*(29*FRACUNIT/32)
			else
				player.runspeed = 60*(29*FRACUNIT/32)
			end
		else
			if (player.mo.skin == "sonic" or player.mo.skin == "tails" or player.mo.skin == "knuckles" or player.mo.skin == "metalsonic" or player.mo.skin == "mighty" or player.mo.skin == "ray" or player.mo.skin == "espio" or player.mo.skin == "charmy" or player.mo.skin == "vector" or player.mo.skin == "bomb" or player.mo.skin == "shadow" or player.mo.skin == "surge")
				if (player.mo.eflags & MFE_UNDERWATER)
					player.mindash = 18*FRACUNIT
					player.maxdash = 36*FRACUNIT
				else
					player.mindash = 36*FRACUNIT
					player.maxdash = 72*FRACUNIT
				end
			end
			if (player.mo.skin == "heavy")
				player.runspeed = 24*FRACUNIT
			else
				player.runspeed = 36*(29*FRACUNIT/32)
			end
		end
		if (P_IsObjectOnGround(player.mo) and not (player.mo.eflags & MFE_JUSTHITFLOOR))
			player.charflags = $|SF_RUNONWATER
		else
			player.charflags = $ & ~SF_RUNONWATER
		end
		if ((player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH) and player.mo.skin != "charmy" and player.mo.skin != "heavy" and player.mo.skin != "bomb")
			if (player.pflags & PF_JUMPED and not (player.pflags & PF_THOKKED))
				player.pflags = $ & ~(PF_SPINNING|PF_THOKKED)
			else
				player.pflags = $|PF_THOKKED
			end
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.speed > 5*FRACUNIT and not (player.pflags & PF_STARTDASH))
				P_Thrust(player.mo, R_PointToAngle2(0, 0, player.rmomx, player.rmomy), -(FRACUNIT/4))
			end
		elseif ((player.mo.skin == "charmy" or player.mo.skin == "heavy") and (player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH))
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.speed > 5*FRACUNIT and not (player.pflags & PF_STARTDASH) and player.mo.skin == "charmy")
				P_Thrust(player.mo, R_PointToAngle2(0, 0, player.rmomx, player.rmomy), -(FRACUNIT/4))
			end
			player.pflags = $|PF_SPINNING|PF_THOKKED
		end
		if ((player.mo.skin == "sonic" or player.mo.skin == "tails" or player.mo.skin == "knuckles" or player.mo.skin == "metalsonic" or player.mo.skin == "espio" or player.mo.skin == "mighty" or player.mo.skin == "ray" or player.mo.skin == "shadow" or player.mo.skin == "surge") and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.cmd.buttons & BT_SPIN and not (player.plusbuttons & BT_SPIN) and player.skidtime)
			player.mo.state = S_PLAY_SPINDASH
			player.pflags = $|PF_STARTDASH|PF_SPINNING
			player.pflags = $ & ~PF_THOKKED
			P_InstaThrust(player.mo, player.mo.angle, 0)
			S_StartSound(player.mo, sfx_spndsh)
			player.dashspeed = player.mindash
		end
		if (player.secondjump == UINT8_MAX and player.pflags & PF_THOKKED and not (player.charflags & SF_NOJUMPSPIN))
			player.mo.state = S_PLAY_JUMP
			player.pflags = $|PF_JUMPED
			player.pflags = $ & ~(PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY)
			player.secondjump = 0
		end
		if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and (player.pflags & PF_JUMPED or player.pflags & PF_BOUNCING or player.mo.state == S_PLAY_MELEE or player.mo.state == S_PLAY_MELEE_FINISH) and (player.mo.momz*P_MobjFlip(player.mo) <     0) and not (player.pflags & PF_GLIDING) and not (player.powers[pw_tailsfly]) and not (player.secondjump == 2 and player.mo.skin == "metalsonic") and not (player.mo.eflags & MFE_GOOWATER))		
			if (player.mo.eflags & MFE_VERTICALFLIP)
				player.mo.momz = $+FRACUNIT/4
			else
				player.mo.momz = $-FRACUNIT/4
			end
		end
		if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.speed <= 72*FRACUNIT and (player.cmd.forwardmove or player.cmd.sidemove or (player.cmd.angleturn and (player.cmd.forwardmove or player.cmd.sidemove))) and not (player.pflags & PF_SPINNING) and not (player.skidtime) and player.mo.skin != "heavy" and player.mo.state != S_PLAY_MELEE_LANDING)
			if ((not (player.mo.eflags & MFE_UNDERWATER) and not (player.powers[pw_super]) and player.speed >= player.runspeed) or (not (player.mo.eflags & MFE_UNDERWATER) and player.powers[pw_super] and player.speed >= 5*player.runspeed/3) or (player.mo.eflags & MFE_UNDERWATER and not (player.powers[pw_super]) and player.speed >= player.runspeed/2) or (player.mo.eflags & MFE_UNDERWATER and player.powers[pw_super] and player.speed >= 5*player.runspeed/6))
				player.mo.friction = FRACUNIT
				if (player.mo.skin == "metalsonic" and player.dashmode >= 3*TICRATE)
					P_Thrust(player.mo,R_PointToAngle2(0, 0, player.rmomx, player.rmomy), (FRACUNIT/4))
				end
			end
		else
			player.mo.friction = 29*(FRACUNIT)/32
		end
		if (player.mo.skin != "heavy" and player.pflags & PF_JUMPED and ((player.charflags & SF_NOJUMPSPIN and player.mo.state == S_PLAY_JUMP) or player.mo.state == S_PLAY_FLOAT or player.mo.state == S_PLAY_FLOAT_RUN or player.mo.state == S_PLAY_SPRING or player.mo.state == S_PLAY_FALL or (player.mo.skin == "mighty" and player.mo.state == S_MIGHTY_HAMMERDROP_SPRING)) and not (player.powers[pw_super]) and not (player.powers[pw_invulnerability]) and not (player.mo.skin == "metalsonic" and player.dashmode >= 3*TICRATE))
			player.pflags = $|PF_NOJUMPDAMAGE
		else
			player.pflags = $ & ~PF_NOJUMPDAMAGE
		end
		if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and ((player.charflags & SF_NOJUMPSPIN and player.mo.state == S_PLAY_JUMP) or player.mo.state == S_PLAY_SPRING or player.mo.state == S_PLAY_FALL or (player.mo.skin == "mighty" and player.mo.state == S_MIGHTY_HAMMERDROP_SPRING) or player.mo.state == S_PLAY_STND or player.mo.state == S_PLAY_WALK or player.mo.state == S_PLAY_RUN or player.mo.state == S_PLAY_SKID or player.mo.state == S_PLAY_WAIT or player.mo.state == S_PLAY_EDGE or player.mo.state == S_PLAY_FLOAT or player.mo.state == S_PLAY_FLOAT_RUN or player.mo.state == S_PLAY_DASH) and not (player.mo.skin == "metalsonic" and player.secondjump))
			player.pflags = $|PF_JUMPED
			player.pflags = $ & ~PF_SPINNING
			if not (player.mo.skin == "mighty" and player.mo.state == S_MIGHTY_HAMMERDROP_SPRING)
				if (player.mo.momz*P_MobjFlip(player.mo) > 0)
					player.mo.state = S_PLAY_SPRING
				elseif (player.mo.momz*P_MobjFlip(player.mo) <= 0)
					player.mo.state = S_PLAY_FALL
				end
			end
		end
		if (player.pflags & PF_SHIELDABILITY and not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR))
			player.pflags = $|PF_SPINNING|PF_THOKKED
			if (player.mo.state != S_PLAY_JUMP and not (player.charflags & SF_NOJUMPSPIN))
				player.mo.state = S_PLAY_JUMP
			elseif (player.mo.state != S_PLAY_ROLL and player.charflags & SF_NOJUMPSPIN)
				player.mo.state = S_PLAY_ROLL
			end
		end
		if (player.mo.skin == "tails")
			if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and (player.mo.state == S_PLAY_FLY or player.mo.state == S_PLAY_FLY_TIRED or player.mo.state == S_PLAY_SWIM))				
				if (player.cmd.buttons & BT_JUMP and player.cmd.buttons & BT_SPIN)
					player.mo.state = S_PLAY_JUMP
					player.pflags = $|PF_JUMPED|PF_SPINNING|PF_THOKKED
					player.pflags = $ & ~PF_NOJUMPDAMAGE
				end
				if (player.mo.state != S_PLAY_FLY_TIRED)
					if (player.cmd.buttons & BT_JUMP)
						player.fly1 = 1
					else
						player.fly1 = 0
					end
				end
				if (player.powers[pw_tailsfly] > 3*TICRATE and not (player.powers[pw_super]))
					player.powers[pw_tailsfly] = 3*TICRATE
				end
			end
		end
		if (player.mo.skin == "knuckles")
			if player.momentumplusglidelast == nil
				player.momentumplusglidelast = 0
			end
			local gliding = player.pflags & PF_GLIDING
			local thokked = player.pflags & PF_THOKKED
			local exitglide = (player.momentumplusglidelast == 1 and not (gliding) and thokked)
			local landglide = (player.momentumplusglidelast == 2 and not (gliding|thokked))
			if ((exitglide or landglide) and (player.mo.state == S_PLAY_SPRING or player.mo.state == S_PLAY_FALL or player.mo.state == S_PLAY_GLIDE or player.mo.state == S_PLAY_GLIDE_LANDING))
				player.mo.momx = $*2
				player.mo.momy = $*2
				if (exitglide)
					if (player.mo.state != S_PLAY_JUMP)
						player.mo.state = S_PLAY_JUMP
					end
					player.pflags = $|PF_JUMPED|PF_SPINNING|PF_THOKKED
					player.pflags = $ & ~(PF_NOJUMPDAMAGE|PF_GLIDING)
				end
			end
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_GLIDING)
				player.mo.state = S_PLAY_GLIDE_LANDING
				S_StartSound(player.mo, sfx_s3k4c)
				player.pflags = $ & ~PF_GLIDING
				player.skidtime = 0
			end
			if gliding
				player.momentumplusglidelast = 1
			elseif exitglide
				player.momentumplusglidelast = 2
			elseif not(gliding|thokked)
				player.momentumplusglidelast = 0
			end
		end
		if (player.mo.skin == "amy")
			if (player.powers[pw_super])
				player.thokitem = MT_LHRT
				player.revitem = MT_LHRT
			else
				player.thokitem = MT_NULL
				player.revitem = MT_NULL
			end
			if (player.mo.state == S_PLAY_MELEE or player.mo.state == S_PLAY_MELEE_FINISH)
				player.charability2 = CA2_MELEE
				if (player.mo.state == S_PLAY_MELEE_FINISH)
					player.mo.state = S_PLAY_MELEE
					player.powers[pw_strong] = STR_MELEE
				end
			else
				player.charability2 = CA2_NONE
			end
			if (player.cmd.buttons & BT_SPIN and not (player.plusbuttons & BT_SPIN) and (player.pflags & PF_JUMPED or (player.pflags & PF_SPINNING and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR)) or P_IsObjectOnGround(player.mo)) and player.mo.state != S_PLAY_MELEE and player.mo.state != S_PLAY_MELEE_FINISH and player.mo.state != S_PLAY_MELEE_LANDING and not (player.mo.state == S_PLAY_ROLL and player.pflags & PF_JUMPED and player.pflags & PF_SPINNING and player.pflags & PF_THOKKED))
				P_ResetPlayer(player)
				player.pflags = $|PF_THOKKED
				player.pflags = $ & ~(PF_SPINNING|PF_JUMPED)
				player.mo.state = S_PLAY_MELEE
				player.powers[pw_strong] = STR_MELEE
				player.drawangle = player.mo.angle
				player.skidtime = 0
				S_StartSound(player.mo, sfx_s3k42)
				if (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR)
					if (player.mo.eflags & MFE_UNDERWATER)
						P_SetObjectMomZ(player.mo, 585*player.mindash/1000, false)
					else
						P_SetObjectMomZ(player.mo, player.mindash, false)
					end
					if (P_MobjFlip(player.mo)*player.mo.pmomz < 0)
						player.mo.momz = $+player.mo.pmomz
					elseif (P_MobjFlip(player.mo)*player.mo.pmomz >= 0)
						player.mo.pmomz = 0
					end
				elseif (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR))
					player.mo.momz = $/2
				end
				if (player.cmd.forwardmove or player.cmd.sidemove or (player.cmd.angleturn and (player.cmd.forwardmove or player.cmd.sidemove)))
					if (player.powers[pw_super] or player.powers[pw_sneakers]) and not (player.mo.eflags & MFE_UNDERWATER)
						if (player.speed < 60*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 60*FRACUNIT)
						elseif (player.speed >= 60*FRACUNIT and player.speed < 72*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, player.speed+(6*FRACUNIT))
						elseif (player.speed >= 72*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 72*FRACUNIT)
						end
					elseif not (player.powers[pw_super]) and not (player.powers[pw_sneakers]) and not (player.mo.eflags & MFE_UNDERWATER)
						if (player.speed < 36*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 36*FRACUNIT)
						elseif (player.speed >= 36*FRACUNIT and player.speed < 72*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, player.speed+(6*FRACUNIT))
						elseif (player.speed >= 72*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 72*FRACUNIT)
						end
					elseif (player.powers[pw_super] or player.powers[pw_sneakers]) and (player.mo.eflags & MFE_UNDERWATER)
						if (player.speed < 30*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 30*FRACUNIT)
						elseif (player.speed >= 30*FRACUNIT and player.speed < 36*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, player.speed+(6*FRACUNIT))
						elseif (player.speed >= 36*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 36*FRACUNIT)
						end
					elseif not (player.powers[pw_super]) and not (player.powers[pw_sneakers]) and (player.mo.eflags & MFE_UNDERWATER)
						if (player.speed < 18*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 18*FRACUNIT)
						elseif (player.speed >= 18*FRACUNIT and player.speed < 36*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, player.speed+(6*FRACUNIT))
						elseif (player.speed >= 36*FRACUNIT)
							P_InstaThrust(player.mo, player.mo.angle, 36*FRACUNIT)
						end
					end
				elseif (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR))
					P_InstaThrust(player.mo, player.mo.angle, 0)
				end
			end
			if (player.mo.state == S_PLAY_MELEE_LANDING)
				if (player.cmd.buttons & BT_SPIN and not (player.cmd.buttons & BT_JUMP) and player.speed > 5*FRACUNIT)
					player.mo.state = S_PLAY_ROLL
					player.pflags = $|PF_SPINNING|PF_THOKKED
					S_StartSound(player.mo, sfx_spin)
				elseif (player.cmd.buttons & BT_JUMP)
					P_DoJump(player, true)
				else
					player.mo.state = S_PLAY_STND
					player.pflags = $ & ~PF_SPINNING|PF_THOKKED
				end
			end
		end
		if (player.mo.skin == "fang")
			local fanglockon = P_LookForEnemies(player, false, true)
			local fangbullet = nil
			local fangbomb = nil
			if (fanglockon and fanglockon.valid)
				P_SpawnLockOn(player, fanglockon, mobjinfo[MT_LOCKON].spawnstate)
			end
			if player.momentumplusbouncelast == nil
				player.momentumplusbouncelast = false
			end
			if ((player.pflags & PF_BOUNCING and not (player.momentumplusbouncelast)) or (not (player.pflags & PF_BOUNCING) and player.momentumplusbouncelast) and (player.mo.state == S_PLAY_BOUNCE or player.mo.state == S_PLAY_JUMP or player.mo.state == S_PLAY_SPRING or player.mo.state == S_PLAY_FALL))
				player.mo.momx = $*2
				player.mo.momy = $*2
				if (not (player.pflags & PF_BOUNCING) and player.momentumplusbouncelast and player.mo.state != S_PLAY_ROLL)
					player.mo.state = S_PLAY_ROLL
					player.pflags = $|PF_JUMPED|PF_THOKKED
					player.pflags = $ & ~(PF_SPINNING|PF_BOUNCING)
				end
			end
			if (player.cmd.buttons & BT_SPIN and not (player.plusbuttons & BT_SPIN) and not (player.weapondelay) and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR or player.pflags & PF_BOUNCING or player.pflags & PF_JUMPED or (player.pflags & PF_SPINNING and P_IsObjectOnGround(player.mo))) and player.mo.state != S_PLAY_FIRE and player.mo.state != S_PLAY_FIRE_FINISH and not (player.pflags & PF_JUMPED and player.pflags & PF_THOKKED and player.mo.state == S_PLAY_ROLL))
				player.mo.state = S_PLAY_FIRE
				player.pflags = $ & ~(PF_SPINNING|PF_JUMPED|PF_THOKKED|PF_BOUNCING)
				if (player.powers[pw_super])
					player.weapondelay = 6
				else
					player.weapondelay = TICRATE/2
				end
				if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR))
					player.mo.momz = $/2
				end
				if (fanglockon and fanglockon.valid)
					player.mo.angle = R_PointToAngle2(player.mo.x, player.mo.y, fanglockon.x, fanglockon.y)
					fangbullet = P_SpawnPointMissile(player.mo, fanglockon.x, fanglockon.y, fanglockon.z, player.revitem, player.mo.x, player.mo.y, player.mo.z)
				end
				if not (fanglockon and fanglockon.valid)
					fangbullet = P_SpawnPointMissile(player.mo, player.mo.x + P_ReturnThrustX(nil, player.mo.angle, FRACUNIT), player.mo.y + P_ReturnThrustY(nil, player.mo.angle, FRACUNIT), player.mo.z, player.revitem, player.mo.x, player.mo.y, player.mo.z)
				end
			end
			if (player.mo.state == S_PLAY_FIRE or player.mo.state == S_PLAY_FIRE_FINISH)
				player.pflags = $|PF_JUMPDOWN
				player.pflags = $ & ~PF_BOUNCING
				if not (player.weapondelay)
					player.pflags = $ & ~PF_BOUNCING
					if (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR)
						if ((player.cmd.buttons & BT_SPIN or player.plusbuttons & BT_SPIN) and player.speed > FixedMul(5<<FRACBITS, player.mo.scale)) and not (player.cmd.buttons & BT_JUMP or player.plusbuttons & BT_JUMP)
							player.mo.state = S_PLAY_ROLL
							player.pflags = $|PF_SPINNING|PF_THOKKED
							S_StartSound(player.mo, sfx_spin)
						elseif (player.cmd.buttons & BT_JUMP or player.plusbuttons & BT_JUMP)
							P_DoJump(player, false)
							player.mo.state = S_PLAY_ROLL
							player.pflags = $|PF_JUMPED
							player.pflags = $ & ~(PF_SPINNING|PF_THOKKED)
							S_StartSound(player.mo, sfx_jump)
						else
							player.mo.state = S_PLAY_STND
							player.pflags = $ & ~(PF_SPINNING|PF_THOKKED)
						end
					elseif (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR))
						player.mo.state = S_PLAY_ROLL
						player.pflags = $|PF_JUMPED|PF_THOKKED
						player.pflags = $ & ~PF_SPINNING
					end
				end
			end
			if ((player.mo.state == S_PLAY_BOUNCE_LANDING or ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and (player.pflags & PF_BOUNCING or player.momentumplusbouncelast))))
				if not (player.weapondelay)
					fangbomb = P_SpawnMobjFromMobj(player.mo,5*FRACUNIT,5*FRACUNIT,player.mo.height+5*FRACUNIT,MT_FBOMB)
					fangbomb.target = player.mo
					fangbomb.momz = 10*FRACUNIT
					player.weapondelay = 6
					S_StartSound(player.mo, sfx_s3k51)
				end
				if (player.cmd.forwardmove or player.cmd.sidemove or (player.cmd.angleturn and (player.cmd.forwardmove or player.cmd.sidemove)))
					if not (player.mo.eflags & MFE_UNDERWATER) and not (player.powers[pw_super]) and not (player.powers[pw_sneakers])
						P_InstaThrust(player.mo, player.mo.angle, 36*FRACUNIT)
					elseif (player.mo.eflags & MFE_UNDERWATER) and not (player.powers[pw_super]) and not (player.powers[pw_sneakers])
						P_InstaThrust(player.mo, player.mo.angle, 18*FRACUNIT)
					elseif not (player.mo.eflags & MFE_UNDERWATER) and (player.powers[pw_super] or player.powers[pw_sneakers])
						P_InstaThrust(player.mo, player.mo.angle, 60*FRACUNIT)
					elseif (player.mo.eflags & MFE_UNDERWATER and (player.powers[pw_super] or player.powers[pw_sneakers]))
						P_InstaThrust(player.mo, player.mo.angle, 30*FRACUNIT)
					end
				else
					P_InstaThrust(player.mo, player.mo.angle, 0)
				end
			end
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_SPINNING)
				player.pflags = $|PF_JUMPDOWN
				if (player.cmd.buttons & BT_JUMP and not (player.plusbuttons & BT_JUMP))
					P_DoJump(player, false)
					player.mo.state = S_PLAY_ROLL
					player.pflags = $|PF_JUMPED
					player.pflags = $ & ~(PF_SPINNING|PF_THOKKED)
					S_StartSound(player.mo, sfx_jump)
				end
			end
		end
		if (player.mo.skin == "metalsonic")
			if (player.dashmode < 3*TICRATE and player.mo.state == S_PLAY_SPINDASH and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR))
				if not (maptol & TOL_NIGHTS)
					player.dashmode = 3*TICRATE
					S_StartSound(player.mo, sfx_kc4d)
				end
			end
			if (player.secondjump)
				player.pflags = $ | PF_JUMPED | PF_THOKKED
				player.secondjump = 2
				player.mo.flags = $ | MF_NOGRAVITY
				if (player.speed < player.runspeed)
					player.mo.state = S_PLAY_FLOAT
				elseif (player.speed >= player.runspeed and not (player.dashmode >= 3*TICRATE))
					player.mo.state = S_PLAY_FLOAT_RUN
				elseif (player.speed >= player.runspeed and player.dashmode >= 3*TICRATE)
					player.mo.state = S_PLAY_DASH
				end
				if (player.cmd.buttons & BT_JUMP and not (player.cmd.buttons & BT_SPIN))
					if P_MobjFlip(player.mo)*player.mo.momz < 5*FRACUNIT
						P_SetObjectMomZ(player.mo, FRACUNIT/2, true)
					elseif P_MobjFlip(player.mo)*player.mo.momz > 5*FRACUNIT
						P_SetObjectMomZ(player.mo, -(FRACUNIT/2), true)
					end
				elseif (player.cmd.buttons & BT_SPIN and not (player.cmd.buttons & BT_JUMP))
					if P_MobjFlip(player.mo)*player.mo.momz > -(5*FRACUNIT)
						P_SetObjectMomZ(player.mo, -(FRACUNIT/2), true)
					elseif P_MobjFlip(player.mo)*player.mo.momz < -(5*FRACUNIT)
						P_SetObjectMomZ(player.mo, FRACUNIT/2, true)
					end
				elseif (not (player.cmd.buttons & BT_JUMP) and not (player.cmd.buttons & BT_SPIN))
					if P_MobjFlip(player.mo)*player.mo.momz > 0
						P_SetObjectMomZ(player.mo, -(FRACUNIT/2), true)
					elseif P_MobjFlip(player.mo)*player.mo.momz < 0
						P_SetObjectMomZ(player.mo, FRACUNIT/2, true)
					end
				elseif (player.cmd.buttons & BT_JUMP and player.cmd.buttons & BT_SPIN)
					player.mo.state = S_PLAY_JUMP
					player.pflags = $|PF_JUMPED|PF_SPINNING|PF_THOKKED
					player.secondjump = 0
					player.mo.momz = player.plusmomz
				end
			elseif not (player.secondjump)
				player.mo.flags = $ & ~MF_NOGRAVITY
			end
		end
		if (((player.mo.skin == "espio" and (player.mo.state == S_PLAY_JUMP or player.mo.state == S_PLAY_ROLL or player.mo.state == S_ESPIO_ROLL)) or (player.mo.skin == "surge" and (player.mo.state == S_PLAY_JUMP or player.mo.state == S_PLAY_ROLL))) and not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_JUMPED and player.pflags & PF_THOKKED and not (player.pflags & PF_SHIELDABILITY))
			if (player.mo.state != S_PLAY_JUMP)
				player.mo.state = S_PLAY_JUMP
			end
			player.pflags = $|PF_SPINNING
		end
		if (player.mo.skin == "mighty" and not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_JUMPED and player.pflags & PF_THOKKED and not (player.pflags & PF_SPINNING)and not (player.pflags & PF_SHIELDABILITY) and player.mo.state == S_PLAY_ROLL)
			player.mo.state = S_PLAY_JUMP
			player.pflags = $ | PF_JUMPED
			player.pflags = $ & ~(PF_SPINNING|PF_THOKKED)
			if (player.cmd.forwardmove or player.cmd.sidemove or (player.cmd.angleturn and (player.cmd.forwardmove or player.cmd.sidemove)))
				if not (player.mo.eflags & MFE_UNDERWATER) and not (player.powers[pw_super]) and not (player.powers[pw_sneakers])
					P_InstaThrust(player.mo, player.mo.angle, 36*FRACUNIT)
				elseif (player.mo.eflags & MFE_UNDERWATER) and not (player.powers[pw_super]) and not (player.powers[pw_sneakers])
					P_InstaThrust(player.mo, player.mo.angle, 18*FRACUNIT)
				elseif not (player.mo.eflags & MFE_UNDERWATER) and (player.powers[pw_super] or player.powers[pw_sneakers])
					P_InstaThrust(player.mo, player.mo.angle, 60*FRACUNIT)
				elseif (player.mo.eflags & MFE_UNDERWATER and (player.powers[pw_super] or player.powers[pw_sneakers]))
					P_InstaThrust(player.mo, player.mo.angle, 30*FRACUNIT)
				end
			else
				P_InstaThrust(player.mo, player.mo.angle, 0)
			end
		end
		if (player.mo.skin == "vector" and not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_JUMPED and player.pflags & PF_THOKKED and (player.mo.state == S_PLAY_JUMP or player.mo.state == S_PLAY_SPRING or player.mo.state == S_PLAY_FALL or player.mo.state == S_PLAY_ROLL) and not (player.pflags & PF_SHIELDABILITY))
			if (player.mo.state != S_PLAY_JUMP)
				player.mo.state = S_PLAY_JUMP
			end
			player.pflags = $|PF_SPINNING
		end
		if (player.mo.skin == "heavy" and (player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH) and player.mo.heavyvars.tics > 3)
			player.mo.heavyvars.tics = 3
		end
		if (player.mo.skin == "bomb")
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and (player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH))
				player.pflags = $|PF_JUMPDOWN|PF_SPINNING|PF_THOKKED
				if not (player.pflags & PF_STARTDASH and player.mo.state == S_PLAY_SPINDASH)
					P_Thrust(player.mo, R_PointToAngle2(0, 0, player.rmomx, player.rmomy), -(FRACUNIT/4))
				end
				if (player.cmd.buttons & BT_JUMP and not (player.plusbuttons & BT_JUMP))
					P_DoJump(player, false)
					S_StartSound(player.mo, sfx_jump)
					if (player.speed >= 18*FRACUNIT and not (player.pflags & PF_STARTDASH))
						player.mo.state = S_BOMB_TOPSPIN_FAST
						player.mo.tics = min(2, $)
					elseif (player.speed <= 12*FRACUNIT and not (player.pflags & PF_STARTDASH))
						player.mo.state = S_BOMB_TOPSPIN
						if (player.speed <= 12*FRACUNIT)
							player.mo.tics = 1
						end
					elseif (player.pflags & PF_STARTDASH)
						player.mo.state = S_PLAY_SPINDASH
					end
					player.pflags = $|PF_JUMPED
					player.pflags = $ & ~(PF_SPINNING|PF_THOKKED|PF_NOJUMPDAMAGE)
				end
			end
			if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and (player.pflags & PF_SPINNING or player.pflags & PF_STARTDASH))
				player.mo.bomb_thokked = 2 ^ 1
			end
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_SPINNING and player.cmd.buttons & BT_SPIN and not (player.plusbuttons & BT_SPIN) and not (player.mo.bomb_volatile) and not (player.pflags & PF_STARTDASH and player.mo.state == S_PLAY_SPINDASH))
				player.mo.state = S_PLAY_SPINDASH
				player.pflags = $|PF_SPINNING|PF_STARTDASH|PF_THOKKED
				player.mo.bomb_fusedash = true
				player.mo.bomb_fusedash_charge = 1
				player.mo.bomb_fusedash_frame = 0
				player.mo.bomb_fusedash_frametics = 3
				S_StartSound(mo, sfx_sc0a5h)
			end
		end
		if (player.mo.skin == "ray" and not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_THOKKED and (player.mo.state == S_PLAY_JUMP or player.mo.state == S_PLAY_ROLL) and not (player.pflags & PF_SHIELDABILITY))
			if (player.mo.state != S_PLAY_JUMP)
				player.mo.state = S_PLAY_JUMP
			end
			player.pflags = $|PF_SPINNING
		end
		if (player.mo.skin == "shadow")
			if ((P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_SPINNING and player.mo.state != S_PLAY_ROLL and player.mo.state != S_PLAY_SPINDASH)
				player.mo.state = S_PLAY_ROLL
			end
			if (not (P_IsObjectOnGround(player.mo)) and not (player.mo.eflags & MFE_JUSTHITFLOOR) and player.pflags & PF_JUMPED and player.pflags & PF_THOKKED and (player.mo.state == S_PLAY_JUMP or player.mo.state == S_PLAY_ROLL) and not (player.pflags & PF_SHIELDABILITY))
				player.pflags = $|PF_SPINNING
			end
		end
		if (player.mo.skin == "surge" and player.mo.state == S_PLAY_ROLL and player.pflags & PF_JUMPED)
			player.mo.state = S_PLAY_JUMP
		end
	end
	player.momentumplusbouncelast = (player.pflags & PF_BOUNCING > 0)
	player.plusbuttons = player.cmd.buttons
	player.pluslastspeed = player.speed
	player.plusmomz = player.mo.momz
end)
-- Repurposed Spam Dash Code by Starlight
addHook("SpinSpecial", function(player)
	if ((player.mo.skin == "sonic" or player.mo.skin == "tails" or player.mo.skin == "knuckles" or player.mo.skin == "metalsonic" or player.mo.skin == "espio" or player.mo.skin == "mighty" or player.mo.skin == "ray" or player.mo.skin == "shadow" or player.mo.skin == "surge") and player.playerstate == PST_LIVE and not (player.powers[pw_carry]))
		if (player.speed > 5*FRACUNIT and player.pflags & PF_STARTDASH) then return true end
		if (P_IsObjectOnGround(player.mo) and player.pflags & PF_SPINNING and not (player.pflags & (PF_SPINDOWN|PF_STARTDASH))) then
			player.mo.state = S_PLAY_STND
			player.pflags = $ & ~PF_SPINNING
			player.pflags = $|PF_SPINDOWN
			return true
		end
	end
end)
addHook("MobjDamage", function(enemy, mo, source)
	if ((mo and mo.valid) and not (P_IsObjectOnGround(mo)) and not (mo.eflags & MFE_JUSTHITFLOOR) and (mo.skin == "sonic" or mo.skin == "tails" or mo.skin == "knuckles" or mo.skin == "amy" or mo.skin == "fang" or mo.skin == "metalsonic" or mo.skin == "espio" or mo.skin == "mighty" or mo.skin == "vector" or mo.skin == "ray" or mo.skin == "shadow" or mo.skin == "tangle" or mo.skin == "whisper" or mo.skin == "surge"))
		if ((enemy and enemy.valid) and (mo.state == S_PLAY_JUMP or mo.state == S_PLAY_SPRING or mo.state == S_PLAY_FALL or mo.state == S_PLAY_ROLL or (mo.skin == "espio" and mo.state == S_ESPIO_ROLL)))
			mo.player.pflags = $ & ~(PF_THOKKED|PF_SPINNING|PF_SHIELDABILITY)
			mo.player.pflags = $ | PF_JUMPED
		end
	end
end)
addHook("MobjDeath", function(enemy, mo, source)
	if ((mo and mo.valid) and not (P_IsObjectOnGround(mo)) and not (mo.eflags & MFE_JUSTHITFLOOR) and (mo.skin == "sonic" or mo.skin == "tails" or mo.skin == "knuckles" or mo.skin == "amy" or mo.skin == "fang" or mo.skin == "metalsonic" or mo.skin == "espio" or mo.skin == "mighty" or mo.skin == "vector" or mo.skin == "ray" or mo.skin == "shadow" or mo.skin == "tangle" or mo.skin == "whisper" or mo.skin == "surge"))
		if ((enemy and enemy.valid) and (mo.state == S_PLAY_JUMP or mo.state == S_PLAY_SPRING or mo.state == S_PLAY_FALL or mo.state == S_PLAY_ROLL or (mo.skin == "espio" and mo.state == S_ESPIO_ROLL)))
			mo.player.pflags = $ & ~(PF_THOKKED|PF_SPINNING|PF_SHIELDABILITY)
			mo.player.pflags = $ | PF_JUMPED
		end
	end
end)