freeslot("S_PLAY_PEEL1", "S_PLAY_PEEL2", "S_PLAY_PEEL3", "S_PLAY_PEEL4", "SPR_PEEL", "S_PLAY_PWALK1", "S_PLAY_PWALK2", "S_PLAY_PWALK3", "S_PLAY_PWALK4", "S_PLAY_PWALK5", "S_PLAY_PWALK6", "S_PLAY_PWALK7", "S_PLAY_PWALK8", "S_PLAY_SPEEL1", "S_PLAY_SPEEL2")
states[S_PLAY_PWALK1] = {SPR_PLAY, SPR2_WALK1, 2, nil, 0, 0, S_PLAY_PWALK2}
states[S_PLAY_PWALK2] = {SPR_PLAY, SPR2_WALK2, 2, nil, 0, 0, S_PLAY_PWALK3}
states[S_PLAY_PWALK3] = {SPR_PLAY, SPR2_WALK3, 2, nil, 0, 0, S_PLAY_PWALK4}
states[S_PLAY_PWALK4] = {SPR_PLAY, SPR2_WALK4, 2, nil, 0, 0, S_PLAY_PWALK5}
states[S_PLAY_PWALK5] = {SPR_PLAY, SPR2_WALK5, 1, nil, 0, 0, S_PLAY_PWALK6}
states[S_PLAY_PWALK6] = {SPR_PLAY, SPR2_WALK6, 1, nil, 0, 0, S_PLAY_PWALK7}
states[S_PLAY_PWALK7] = {SPR_PLAY, SPR2_WALK7, 1, nil, 0, 0, S_PLAY_PWALK8}
states[S_PLAY_PWALK8] = {SPR_PLAY, SPR2_WALK8, 1, nil, 0, 0, S_PLAY_PEEL1}
states[S_PLAY_PEEL1] = {SPR_PEEL, A, 1, nil, 0, 0, S_PLAY_PEEL2}
states[S_PLAY_PEEL2] = {SPR_PEEL, B, 1, nil, 0, 0, S_PLAY_PEEL3}
states[S_PLAY_PEEL3] = {SPR_PEEL, C, 1, nil, 0, 0, S_PLAY_PEEL4}
states[S_PLAY_PEEL4] = {SPR_PEEL, D, 1, nil, 0, 0, S_PLAY_PEEL1}
states[S_PLAY_SPEEL1] = {SPR_PLAY, SPR2_RUN_1, 1, nil, 0, 0, S_PLAY_SPEEL2}
states[S_PLAY_SPEEL2] = {SPR_PLAY, SPR2_RUN_2, 1, nil, 0, 0, S_PLAY_SPEEL1}
addHook("ThinkFrame", do
	for player in players.iterate
		if not player.mo return end
			if player.mo and player.mo.skin == "classicsonic"
			//CONS_Printf(player, player.mo.peelouttimer)
				if player.mo.state == S_PLAY_STND
					player.normalspeed = 36*FRACUNIT
				end
				if player.mo.peelouttimer == nil
					player.mo.peelouttimer = 0
				end
				if player.mo.peelout == nil
					player.mo.peelout = 0
				end
				if player.mo.peeloutrun == nil
					player.mo.peeloutrun = 0
				end
				if player.mo.peelsound == nil
					player.mo.peelsound = 0
				end
				if player.mo.peelsound2 == nil
					player.mo.peelsound2 = 0
				end
				if player.pflags & PF_SPINNING
					player.mo.peelouttimer = 0
				end
				if (P_PlayerInPain(player))
				or (player.playerstate == PST_DEAD)
					player.normalspeed = 36*FRACUNIT
					player.mo.peelouttimer = 0
					player.mo.peelout = 0
					player.mo.peeloutrun = 0
					player.mo.peelsound = 0
					player.mo.peeloutsound = 0
				end
				if P_IsObjectOnGround(player.mo)
				and player.speed == 0
				and not (player.pflags & PF_SPINNING)
				and player.cmd.buttons & BT_CUSTOM1
			    and not (player.playerstate == PST_DEAD)
					if player.mo.peelsound == 0
						S_StartSound(player.mo, sfx_cdfm11)
						player.mo.peelsound = 1
						
					end
					if player.mo.peelouttimer < 60
						player.mo.peelouttimer = $1 + 1
					end
					player.normalspeed = 0
					player.pflags = $1|PF_STASIS
					if player.drawangle ~= player.mo.angle
						local diff = 0
						local factor = 0
						diff = player.mo.angle - player.drawangle
						factor = 8
						if diff > ANGLE_180
							diff = InvAngle(InvAngle(diff)/(factor or 1))
						else
							diff = $ / (factor or 1)
						end
						player.drawangle = $ + diff
					
					end
					if not (player.mo.eflags & MFE_GOOWATER) then
						for i=(leveltime%7)/2,(leveltime%7) do
							local particle = P_SpawnMobj(player.mo.x, player.mo.y,
							player.mo.z + ((player.mo.eflags & MFE_VERTICALFLIP)/MFE_VERTICALFLIP * (player.mo.height - mobjinfo[MT_SPINDUST].height)),
							MT_SPINDUST)
							if (player.powers[pw_shield] == SH_ELEMENTAL and not (player.mo.eflags & MFE_TOUCHWATER or player.mo.eflags & MFE_UNDERWATER)) then
								particle.state = S_SPINDUST_FIRE1
								particle.bubble = false
							elseif (player.mo.eflags & MFE_TOUCHWATER or player.mo.eflags & MFE_UNDERWATER) then
								particle.state = S_SPINDUST_BUBBLE1
								particle.bubble = true
							else
								particle.state = S_SPINDUST1
								particle.bubble = false
							end
					
							particle.target = player.mo
							particle.eflags = $1 | (player.mo.eflags & MFE_VERTICALFLIP)
							particle.scale = player.mo.scale*2/3
							P_SetObjectMomZ(particle, player.mo.peelouttimer*FRACUNIT/50+P_RandomByte()<<10, false)
							P_InstaThrust(particle, player.mo.angle+(P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT), FixedMul(-player.mo.peelouttimer*FRACUNIT/12-1*FRACUNIT-P_RandomByte()<<11, player.mo.scale))
							P_TryMove(particle, particle.x+particle.momx, particle.y+particle.momy, true)
						end
					end
				end
			if not (player.cmd.buttons & BT_CUSTOM1) 
				if ((player.mo.peelouttimer >= 1) and (player.mo.peelouttimer <= 35) and not (player.powers[pw_super]))
				or ((player.mo.peelouttimer >= 1) and (player.mo.peelouttimer <= 14) and (player.powers[pw_super]))
					player.normalspeed = 36*FRACUNIT
					player.mo.state = 14
					player.mo.peelouttimer = 0
					player.mo.peelsound = 0
				end
			end
			
			if player.powers[pw_super] == 0
				if player.mo.peelouttimer >= 1
				and player.mo.peelouttimer <= 10
					if not (player.mo.state >= S_PLAY_PWALK1)
					and (player.mo.state <= S_PLAY_PWALK8)
						player.mo.state = S_PLAY_PWALK1
					end
				end
				if player.mo.peelouttimer >= 15
					if not ((player.mo.state >= S_PLAY_PEEL1) and (player.mo.state <= S_PLAY_PEEL4))
					or ((player.mo.state >= S_PLAY_PWALK1) and (player.mo.state <= S_PLAY_PWALK8))
						player.mo.state = S_PLAY_PEEL1
					end
				end
			else
				if player.mo.peelouttimer >= 1
				and player.mo.peelouttimer <= 1
					if not (player.mo.state >= S_PLAY_PWALK4)
					and (player.mo.state <= S_PLAY_PWALK8)
						player.mo.state = S_PLAY_PWALK4
					end
				end
				if player.mo.peelouttimer >= 1
					if not (player.mo.state >= S_PLAY_SPEEL1)
					and (player.mo.state <= S_PLAY_SPEEL2)
						player.mo.state = S_PLAY_SPEEL1
					end
				end
			end
			if not (player.cmd.buttons & BT_CUSTOM1)
				if ((player.mo.peelouttimer >= 10) and not (player.powers[pw_super]))
				or ((player.mo.peelouttimer >= 1) and (player.powers[pw_super]))
					if player.mo.peelsound == 1
						player.mo.state = S_PLAY_RUN
						S_StartSound(player.mo, sfx_cdfm01)
						player.mo.peelsound = 0
						player.mo.peelout = 1
					end
					P_InstaThrust(player.mo, player.mo.angle, FixedMul(60*FRACUNIT, player.mo.scale))
					player.mo.peelouttimer = 0
					player.drawangle = player.mo.angle
				end
				
			end
			if player.speed > 40*FRACUNIT
			and player.mo.peelout == 1
				player.mo.peeloutrun = 1
				player.normalspeed = 60*FRACUNIT
			end
			if player.speed <= 40*FRACUNIT
			and player.mo.peeloutrun == 1
				player.mo.peelout = 0
				player.mo.peeloutrun = 0
				player.normalspeed = 36*FRACUNIT
			end
			if player.mo.peelout == 1
				player.charflags = $1|SF_RUNONWATER
			else
				player.charflags = $1 & ~SF_RUNONWATER
			end
			if player.pflags & PF_JUMPED
				if ((player.mo.state >= S_PLAY_PWALK1) and (player.mo.state <= S_PLAY_PWALK8))
				or ((player.mo.state >= S_PLAY_PEEL1) and (player.mo.state <= S_PLAY_PEEL4))
				or ((player.mo.state >= S_PLAY_SPEEL1) and (player.mo.state <= S_PLAY_SPEEL2))
					player.mo.state = S_PLAY_ROLL
				end
				if player.normalspeed == 0*FRACUNIT
					player.normalspeed = 36*FRACUNIT
				end
				player.mo.peelouttimer = 0
				player.mo.peelsound = 0
				player.mo.peelsound2 = 0
			end
		end
	end
end)
//These checks do two things: 1. Re-enable player control when spinning in the air super
addHook("ThinkFrame", do
	for player in players.iterate
		if player.mo.skin == "classicsonic"
			if player.pflags & PF_SPINNING
			and not P_IsObjectOnGround(player.mo)
				if player.pflags & PF_JUMPED
					player.pflags = $1 & ~PF_SPINNING
				else
					player.pflags = $1 & ~PF_SPINNING
					player.pflags = $1 | PF_JUMPED
					player.pflags = $1 | PF_THOKKED
					if (player.powers[pw_shield] & SH_WHIRLWIND)
					and player.pflags & PF_JUMPED
					and player.pflags & PF_THOKKED
					and (player.cmd.buttons & BT_USE)
					and not (player.mo.usedown >= 1)
					and not P_IsObjectOnGround(player.mo)
						player.pflags = $1 & ~PF_THOKKED
						P_DoJumpShield(player)
						player.mo.shielded = true
						player.mo.usedown = $ + 1
					end
				end
			end
		end
	end
end)

//dropdash
freeslot(
"sfx_drpdsh",
"S_DROPDASH1",
"S_DROPDASH2",
"S_DROPDASH3",
"S_DROPDASH4",
"S_DROPDASH5",
"S_DROPDASH6",
"S_DROPDASH7",
"S_DROPDASH8",
"SPR_DRPD"
)
sfxinfo[sfx_drpdsh] = {
	singular = false,
	caption = "Drop Dash"
}

states[S_DROPDASH1] = {
	sprite = SPR_DRPD,
	frame = A,
	tics = 1,
	nextstate = S_DROPDASH2
}

states[S_DROPDASH2] = {
	sprite = SPR_DRPD,
	frame = C,
	tics = 1,
	nextstate = S_DROPDASH3
}

states[S_DROPDASH3] = {
	sprite = SPR_DRPD,
	frame = B,
	tics = 1,
	nextstate = S_DROPDASH4
}

states[S_DROPDASH4] = {
	sprite = SPR_DRPD,
	frame = F,
	tics = 1,
	nextstate = S_DROPDASH5
}

states[S_DROPDASH5] = {
	sprite = SPR_DRPD,
	frame = D,
	tics = 1,
	nextstate = S_DROPDASH6
}

states[S_DROPDASH6] = {
	sprite = SPR_DRPD,
	frame = C,
	tics = 1,
	nextstate = S_DROPDASH7
}

states[S_DROPDASH7] = {
	sprite = SPR_DRPD,
	frame = E,
	tics = 1,
	nextstate = S_DROPDASH8
}

states[S_DROPDASH8] = {
	sprite = SPR_DRPD,
	frame = F,
	tics = 1,
	nextstate = S_DROPDASH1
}
assert(VERSION ~= nil, "script does not support game version")

addHook("ThinkFrame", do
	for player in players.iterate
		local mo = player.mo
		if player.mo.skin == "classicsonic"
			if player.dropswap == nil then
				player.dropswap = false
			end

			if not (player.dropready)
				player.dropready = false
			end

			if not (player.dropcharged)
				player.dropcharged = false
			end

			if not (player.spinprep)
				player.spinprep = 9
			end
			if (player.pflags & PF_JUMPED)
			and player.spinprep > 1
			and (player.jumping == false)
			and (player.cmd.buttons & BT_JUMP)
			and not (player.pflags & PF_THOKKED)
				player.spinprep = $1-1
				if player.spinprep == 1
					player.dropready = true
				end
			end

			local jump = player.cmd.buttons&BT_JUMP
			local spin = player.cmd.buttons&BT_SPIN
			local jumplast = player.pflags&PF_JUMPDOWN
			local spinlast = player.pflags&PF_SPINDOWN
			local lastswap = player.dropswap		
			local shieldtype = player.powers[pw_shield]&~(SH_PITY|SH_PINK|SH_STACK) and not(player.powers[pw_super])
			
			if P_IsObjectOnGround(mo) then
				player.dropswap = false
			end

			if (player.dropready)
			and P_IsObjectOnGround(player.mo)
				player.dropswap = true
			end
			player.charability = CA_NONE
		end
		if (player.mo.skin == "classicsonic" and player.charability == CA_NONE and player.charability2 == CA2_SPINDASH)
			if (player.mo.dropcharged == nil)
				player.mo.dropcharged = false
			end
			if (player.mo.eflags & MFE_SPRUNG)
			and not (player.powers[pw_carry] == CR_ROPEHANG)
			and not (player.powers[pw_carry] == CR_MACESPIN)
			and not (player.powers[pw_carry] == CR_PLAYER)
			or (player.exiting)
			or (player.pflags & PF_SLIDING)
			or (player.deadtimer)
			or P_PlayerInPain(player)
				player.mo.dropcharged = false
			end
			if (player.mo.dropcharged == true)
			and not (P_PlayerInPain(player) or (player.deadtimer))
				player.mo.state = S_DROPDASH1 // lock sprite
				if player.mo.state >= S_DROPDASH8
					player.mo.state = S_DROPDASH1
				end
			end
			if (player.mo.dropcharged == false)
			and ((player.mo.state >= S_DROPDASH1) and (player.mo.state <= S_DROPDASH8))
			and P_IsObjectOnGround(player.mo)
				player.mo.state = S_PLAY_WALK
			end
			if not (P_PlayerInPain(player) or (player.deadtimer))
				if not (player.mo.eflags & MFE_JUSTHITFLOOR) then
					if not (player.cmd.buttons & BT_JUMP) and player.mo.dropcharged then
						player.mo.dropcharged = false
					end
				end
			end
			if not (player.cmd.buttons & BT_JUMP)
			and player.spinprep < 8
				player.pflags = $1|PF_THOKKED
			end

			if player.spinprep > 0
			and P_IsObjectOnGround(player.mo)
				player.dropprep = false
			end
			
			if player.spinprep == 1
				player.dropready = true
			end

			if player.pflags&PF_JUMPED
				//Holding jump key
				if (jumplast) and not(spin)
					player.dropswap = 0
				end
			end
		end
	end
end)

addHook("JumpSpecial", function(player)
	local mo = player.mo
	//Drop Dash
	if player.mo.skin == "classicsonic"
		if player.pflags&PF_JUMPED and not(player.pflags&PF_JUMPDOWN)
			mo.dropprep = 1
			mo.spinprep = 1
			mo.dropmomz = 0
		end
	end
end)

local StopDropDash = function(player)
	local mo = player.mo
	if not(mo.dropprep) then return end
	mo.dropprep = 0
	mo.spinprep = 0
	if player.pflags&(PF_JUMPED) or (player.pflags&PF_JUMPED and not(player.pflags&PF_NOJUMPDAMAGE))
		mo.state = S_PLAY_ROLL
	end
end


addHook("AbilitySpecial",function(player)
	if player.mo.skin == "classicsonic"
		player.mo.dropprep = min(1,$)
	end
end)

addHook("ThinkFrame",function(player)
	for player in players.iterate()
		if player.mo.skin == "classicsonic"
			if player.mo.dropprep == nil then
				player.mo.dropprep = 0
				player.mo.spinprep = 0
				player.mo.dropmomz = 0
			end
			if P_PlayerInPain(player) or not(player.playerstate == PST_LIVE) or player.exiting or player.powers[pw_nocontrol]
				StopDropDash(player)
			end
			local mo = player.mo

			//Cancel drop dash
			if (not(player.cmd.buttons & BT_JUMP) and mo.dropprep)
			or mo.eflags & MFE_SPRUNG
			or P_PlayerInPain(player)
			or (not (mo.eflags & MFE_JUSTHITFLOOR) and not((player.pflags&PF_JUMPED)&~PF_NOJUMPDAMAGE))
				StopDropDash(player)
			return end
			
			//Handle drop dash
			if player.charability == CA_NONE and player.charability2 == CA2_SPINDASH 
				if mo.dropprep
					and mo.spinprep and not(mo.state >= S_PLAY_SUPER_TRANS1 and mo.state <= S_PLAY_SUPER_TRANS6)
					//Air state
					if not (mo.eflags & MFE_JUSTHITFLOOR)
						//Charge drop dash
						if (player.cmd.buttons & BT_JUMP or (player.cmd.buttons & BT_JUMP and player.cmd.buttons & BT_JUMP))
							if mo.dropprep < 100
								mo.dropprep = $+100/10
								if mo.dropprep >= 100
									S_StartSound(mo, sfx_drpdsh, player)
									mo.dropprep = 100
									mo.state = S_DROPDASH1
								end
							end
						end
					else
						if player.cmd.buttons & BT_JUMP and mo.dropprep == 100
							player.mo.state = S_PLAY_ROLL
							player.pflags = $1|PF_SPINNING
						if (player.mo.eflags & MFE_SPRUNG)
						or not (player.powers[pw_carry] == CR_ROPEHANG)
						or not (player.powers[pw_carry] == CR_PLAYER)
						or not (player.powers[pw_carry] == CR_MACESPIN)
						or (player.exiting)
						or (player.pflags & PF_SLIDING)
						or (player.deadtimer)
						or P_PlayerInPain(player)
							player.mo.dropcharged = false
						end
						if (player.mo.dropcharged == true)
						and ((player.mo.state >= S_DROPDASH1) and (player.mo.state <= S_DROPDASH8))
						and P_IsObjectOnGround(player.mo)
							player.mo.state = S_PLAY_WALK
						end
						if not (P_PlayerInPain(player) or (player.deadtimer))
							if not (player.mo.eflags & MFE_JUSTHITFLOOR) then
								if not (player.cmd.buttons & BT_JUMP) and player.mo.dropcharged then
									player.mo.dropcharged = false
								end
							end
						end
						if (player.mo.dropcharged and player.cmd.buttons & BT_JUMP)
						and ((player.mo.state >= S_DROPDASH1) and (player.mo.state <= S_DROPDASH8)) then
							if S_SoundPlaying(player.mo, sfx_drpdsh)
								S_StopSound(player.mo)
							end
							player.pflags = $1|PF_SPINNING
							player.mo.dropcharged = false
							if (MODID == 14)
								P_InstaThrust(player.mo, player.mo.angle, 11*FRACUNIT)
								S_StartSound(player.mo)
							end
							if (player.hasmomentum)
								if player.rspeed < 60*FRACUNIT
								and player.rspeed > 40*FRACUNIT
									if player.powers[pw_super]
										P_StartQuake(8*player.mo.scale, 8, nil, 256*player.mo.scale)
										S_StartSound(player.mo, sfx_cdfm01)
									else
										S_StartSound(player.mo, sfx_zoom)
									end
									P_InstaThrust(player.mo, player.mo.angle, player.rspeed)
								elseif player.rspeed > 60*FRACUNIT
									if player.powers[pw_super]
										P_StartQuake(8*player.mo.scale, 8, nil, 256*player.mo.scale)
										P_InstaThrust(player.mo, player.mo.angle, 50*FRACUNIT)
										S_StartSound(player.mo, sfx_cdfm01)
									else
										P_InstaThrust(player.mo, player.mo.angle, 40*FRACUNIT)
										S_StartSound(player.mo, sfx_zoom)
									end
								elseif player.rspeed < 40*FRACUNIT
									if player.powers[pw_super]
										P_StartQuake(8*player.mo.scale, 8, nil, 256*player.mo.scale)
										P_InstaThrust(player.mo, player.mo.angle, 40*FRACUNIT)
										S_StartSound(player.mo, sfx_cdfm01)
									else
										P_InstaThrust(player.mo, player.mo.angle, 30*FRACUNIT)
										S_StartSound(player.mo, sfx_zoom)
									end
								end
							end
						else
							if player.speed < 60*FRACUNIT
							and player.speed > 40*FRACUNIT
								if player.powers[pw_super]
									P_StartQuake(8*player.mo.scale, 8, nil, 256*player.mo.scale)
									S_StartSound(player.mo, sfx_cdfm01)
								else
									S_StartSound(player.mo, sfx_zoom)
								end
								P_InstaThrust(player.mo, player.mo.angle, player.speed)
							elseif player.speed > 60*FRACUNIT
								if player.powers[pw_super]
									P_StartQuake(8*player.mo.scale, 8, nil, 256*player.mo.scale)
									P_InstaThrust(player.mo, player.mo.angle, 50*FRACUNIT)
									S_StartSound(player.mo, sfx_cdfm01)
								else
									P_InstaThrust(player.mo, player.mo.angle, 40*FRACUNIT)
									S_StartSound(player.mo, sfx_zoom)
								end
							elseif player.speed < 29*FRACUNIT
								if player.powers[pw_super]
									P_StartQuake(8*player.mo.scale, 8, nil, 256*player.mo.scale)
									P_InstaThrust(player.mo, player.mo.angle, 40*FRACUNIT)
									S_StartSound(player.mo, sfx_cdfm01)
								else
									P_InstaThrust(player.mo, player.mo.angle, 30*FRACUNIT)
									S_StartSound(player.mo, sfx_zoom)
								end
							end
						end
						if not (player.mo.state >= S_PLAY_ROLL)
							player.mo.state = S_PLAY_ROLL
						end
						if not (player.mo.skin == "classicsonic")
							if not (player.mo.dropcharged == nil)
								player.mo.dropcharged = nil
							end
						end
						
							local speed = abs(player.mo.dropmomz/2)+FixedHypot(player.rmomx,player.rmomy)
							local actionspd = player.actionspd
							if player.powers[pw_super] then
								actionspd = $*3/2
							end
							if player.mo.eflags&MFE_UNDERWATER then actionspd = $*2/3 end
							P_InstaThrust(player.mo, player.mo.angle,max(actionspd,speed))

							for i=(leveltime%88)/2,(leveltime%88) do
								local particle2 = P_SpawnMobj(player.mo.x, player.mo.y,
									player.mo.z + ((player.mo.eflags & MFE_VERTICALFLIP)/MFE_VERTICALFLIP * (player.mo.height - mobjinfo[MT_PARTICLE].height)),
									MT_PARTICLE)
								if (player.powers[pw_shield] == SH_ELEMENTAL and not (player.mo.eflags & MFE_TOUCHWATER or player.mo.eflags & MFE_UNDERWATER)) then
									particle2.state = S_SPINDUST_FIRE1
									particle2.bubble = false
									particle2.fuse = 20
								elseif (player.mo.eflags & MFE_TOUCHWATER or player.mo.eflags & MFE_UNDERWATER) then
									particle2.state = S_SPINDUST_BUBBLE1
									particle2.bubble = true
									particle2.fuse = 20
								else
									particle2.state = S_SPINDUST1
									particle2.bubble = false
									particle2.fuse = 20
								end
								if (player.mo.eflags & MFE_GOOWATER) then
									particle2.flags2 = $1|MF2_DONTDRAW
								else
									particle2.flags2 = $1 & ~MF2_DONTDRAW
								end
								particle2.target = player.mo
								particle2.eflags = $1 | (player.mo.eflags & MFE_VERTICALFLIP)
								particle2.scale = player.mo.scale*2/3
								P_SetObjectMomZ(particle2, 35*FRACUNIT/50+P_RandomByte()<<10, false)
								P_InstaThrust(particle2, player.mo.angle+(P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT), FixedMul(-35*FRACUNIT/12-1*FRACUNIT-P_RandomByte()<<11, player.mo.scale))
								P_TryMove(particle2, particle2.x+particle2.momx, particle2.y+particle2.momy, true)
							end
						end
						StopDropDash(player)
					end
				end
			end
		end
	end
end)
//fast run
freeslot("S_FASTER1", "S_FASTER2", "S_FASTER3", "S_FASTER4", "SPR_FAST")

states[S_FASTER1] = {SPR_FAST, A, 1, nil, 0, 0, S_FASTER2}
states[S_FASTER2] = {SPR_FAST, B, 1, nil, 0, 0, S_FASTER3}
states[S_FASTER3] = {SPR_FAST, C, 1, nil, 0, 0, S_FASTER4}
states[S_FASTER4] = {SPR_FAST, D, 1, nil, 0, 0, S_FASTER1}
addHook("ThinkFrame", do
    for player in players.iterate
        if (player.mo and player.mo.skin == "classicsonic")
		and not player.powers[pw_super] then
            if (player.speed > 60*FRACUNIT)
				if not player.powers[pw_sneakers]
					player.normalspeed = 60*FRACUNIT
				end
				player.charflags = $1|SF_RUNONWATER
				
				if (player.mo and player.mo.skin == "classicsonic")
				and not player.powers[pw_super]
					if not (player.mo.state >= S_FASTER1)
					and (player.mo.state <= S_FASTER4)
					and not (player.pflags & PF_SPINNING)
					and P_IsObjectOnGround(player.mo)
					and (player.panim == PA_RUN)
						player.mo.state = S_FASTER1
					end
				end
			elseif (player.speed >= 0)
			and (player.speed < 53*FRACUNIT)
				player.charflags = $1 & ~SF_RUNONWATER
				if (player.mo and player.mo.skin == "classicsonic")
				and not player.powers[pw_super] then
					player.normalspeed = 36*FRACUNIT
				end	
				if (player.mo.state >= S_FASTER1) and (player.mo.state <= S_FASTER4)
				and not ((player.mo.state >= S_PLAY_PWALK1) and (player.mo.state <= S_PLAY_PWALK8))
				and P_IsObjectOnGround(player.mo)
					player.mo.state = S_PLAY_SKID
				end
            end
        end
    end
end)

//instashield katsy version
//lua ported over to 2.2, new insta-shield sprites, and bug-fixes by DirkTheHusky
freeslot(
	"MT_INSTASHIELD",
	"MT_INSTAHIT",
	"S_INSTASHIELD",
	"S_INSTASHIELD1",
	"S_INSTASHIELD1B",
	"S_INSTASHIELD2",
	"S_INSTASHIELD2B",
	"S_INSTASHIELD3",
	"S_INSTASHIELD3B",
	"S_INSTASHIELD4",
	"S_INSTASHIELD4B",
	"S_INSTASHIELD5",
	"S_INSTASHIELD5B",
	"S_INSTASHIELD6",
	"S_INSTASHIELD6B",
	"S_INSTASHIELD7",
	"S_INSTASHIELD7B",
	"S_INSTAHIT",
	"S_INSTAHIT1",
	"S_INSTAHIT2",
	"SPR_TWSP"
)

assert(VERSION ~= nil, "script does not support game version")

//soc crapA
mobjinfo[MT_INSTAHIT] = {
	doomednum = -1,
	spawnhealth = 1,
	spawnstate = S_INSTAHIT1,
	radius = 64*FRACUNIT,
	height = 64*FRACUNIT,
	flags = MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT
}

mobjinfo[MT_INSTASHIELD] = {
	doomednum = -1,
	spawnhealth = 1,
	spawnstate = S_INSTASHIELD1,
	radius = 32*FRACUNIT,
	height = 32*FRACUNIT,
	flags = MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOCLIPHEIGHT
}

states[S_INSTAHIT1] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTAHIT2}
states[S_INSTAHIT2] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTAHIT1}

states[S_INSTASHIELD1] = {SPR_TWSP, 0|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD2}
states[S_INSTASHIELD2] = {SPR_TWSP, 1|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD3}
states[S_INSTASHIELD3] = {SPR_TWSP, 2|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD4}
states[S_INSTASHIELD4] = {SPR_TWSP, 3|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD5}
states[S_INSTASHIELD5] = {SPR_TWSP, 4|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD6}
states[S_INSTASHIELD6] = {SPR_TWSP, 5|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD7}
states[S_INSTASHIELD7] = {SPR_TWSP, 6|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD1}

//the main fucntion that spawns the instashield
local function InstaShield(sonic)
	local player = sonic.player
	if not (player.mo and player.mo.skin == "classicsonic") return end
	if player.cmd.buttons & BT_USE
	and P_IsObjectOnGround(player.mo) 
		player.useground = 1
	end
	if not (player.cmd.buttons & BT_USE)
		player.useground = nil
	end
	if (player.cmd.buttons & BT_USE)
	and not (player.powers[pw_carry] == CR_NIGHTSMODE)
	and not (player.powers[pw_carry])
	and not (player.pflags & PF_SLIDING)
	and not (player.pflags & PF_THOKKED)
	and (player.pflags & PF_JUMPED)
	and not P_PlayerInPain(player)
	and not (player.exiting)
	and not P_IsObjectOnGround(sonic)
	and not player.useground
	and not (player.instashield == 1)
	and not player.powers[pw_shield]
		player.invisiframe = 1
		S_StartSound(player.mo, sfx_s3k42)
		local instahit = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_INSTAHIT)
		instahit.target = player.mo
		instahit.scale = player.mo.scale
		instahit.fuse = 8
		player.tracer = instahit
		local instashield = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_INSTASHIELD)
		instashield.target = player.mo
		instashield.scale = player.mo.scale * 4/5
		instashield.fuse = 8
		player.instashield = 1
		player.pflags = $ | PF_THOKKED
	end
	if (player.powers[pw_carry])
		player.useground = 1
		player.instashield = 0
	end
	if (player.instashield == 1)
	and P_IsObjectOnGround(sonic)
		player.instashield = 0
		if (player.tracer and player.tracer.valid)
		and player.tracer.type == MT_INSTAHIT
		P_KillMobj(player.tracer)
		end
	end
	
	if (player.instashield == 1) and (player.invisiframe == 1) and not (player.mo.state == S_PLAY_SPRING) and not (player.mo.state == S_PLAY_PAIN)
		player.mo.frame = ($1 & FF_FRAMEMASK)|TR_TRANS60
	end
	if (player.invisiframe == 1) and not (player.tracer and player.tracer.valid and player.tracer.type == MT_INSTAHIT)
		player.invisiframe = nil
	end
	if player.mo.state == S_PLAY_SPRING
		player.invisiframe = nil
	end
end

addHook("MobjThinker", InstaShield, MT_PLAYER)

//this makes stuff not damage sonic while the instashield is being used
local function InstaCheck(sonic, source)
	if ((sonic) and (sonic.player and sonic.skin == "classicsonic") and (sonic.player.tracer and sonic.player.tracer.valid) and ((sonic.player.tracer and sonic.player.tracer.health and sonic.player.tracer.valid) and sonic.player.tracer.type == MT_INSTAHIT)) 
		return false
	end
end

addHook("ShouldDamage", InstaCheck, MT_PLAYER)

local function InstaCollide(insta, mobj)
	if not (insta.z+(1*FRACUNIT) > mobj.z+mobj.height)
	and not(mobj.z+(1*FRACUNIT) > insta.z+insta.height)
		if (mobj.valid and mobj.health and mobj.flags & (MF_ENEMY|MF_BOSS))
			P_DamageMobj(mobj, insta, insta.target)
	//		P_SetObjectMomZ(insta.target, insta.target.momz-insta.target.momz*2)bt
		end
		if (mobj.valid and mobj.health and mobj.flags & MF_MONITOR)
			P_KillMobj(mobj, insta, insta.target)
	//		P_SetObjectMomZ(insta.target, insta.target.momz-insta.target.momz*2)
			end
	else
		return nil
	end
end

addHook("MobjMoveCollide", InstaCollide, MT_INSTAHIT)
addHook("MobjCollide", InstaCollide, MT_INSTAHIT)

//flip instashield stuff if the player is flipped

local function InstaFlip(inst)
	if inst.target
		inst.eflags = ((inst.target.eflags & MFE_VERTICALFLIP) and ($1|MFE_VERTICALFLIP) or ($1 & ~MFE_VERTICALFLIP))
	end
end

addHook("MobjThinker", InstaFlip, MT_INSTASHIELD)
addHook("MobjThinker", InstaFlip, MT_INSTAHIT)


COM_AddCommand("csonicsupermusic", function(player)
	if not player.cssm
		player.cssm = true
		CONS_Printf(player,"sonic 3 super music")
	else
		player.cssm = false
		CONS_Printf(player,"sonic 2 super music")
	end
end)
//Music
addHook("ThinkFrame", do
    for player in players.iterate do
        if (player.mo and player.mo.valid)
        player.hassupermusic = true
            if not player.powers[pw_extralife]
            and not (player.exiting)
            if player.powers[pw_super] and not (player.hyper and player.hyper.capable) then
                if player.mo.skin == "classicsonic"
                    if player.cssm == true
                    S_ChangeMusic("s3super",true,player) //(ALT) Sonic Mania Super theme
                    else
                    S_ChangeMusic("s2super",true,player) //SATFS Stardom Santuary's True Final Boss
                    end
                end
            end    
        else
            P_RestoreMusic(player)
            end
        end
    end
end)


//Sonic & ashuro run ghosts
addHook("PlayerThink", function(player)
	if not (player.mo and player.mo.skin == "classicsonic") then return end
	if (player.powers[pw_super])
	and player.speed + abs(player.mo.momz) > FixedMul(20*FRACUNIT,player.mo.scale)
		local gmobj = P_SpawnGhostMobj(player.mo)
		gmobj.fuse = 3
		if gmobj.tracer then gmobj.tracer.fuse = 3 end
		if (leveltime & 1)
			gmobj.frame = $&~FF_TRANSMASK
			gmobj.frame = $|tr_trans70<<FF_TRANSSHIFT
			if (gmobj.tracer)
				gmobj.tracer.frame = $&~FF_TRANSMASK
				gmobj.tracer.frame = $|tr_trans70<<FF_TRANSSHIFT
			end
		end
	end
end)
//same but for blue
addHook("PlayerThink", function(player)
	if not (player.mo and player.mo.skin == "classicsonic") then return end
	if player.mo.emeraldpower
	and player.speed + abs(player.mo.momz) > FixedMul(20*FRACUNIT,player.mo.scale)
		local gmobj = P_SpawnGhostMobj(player.mo)
		gmobj.fuse = 3
		gmobj.color = SKINCOLOR_SUPERSKY5
		if gmobj.tracer then gmobj.tracer.fuse = 3 end
		if (leveltime & 1)
			gmobj.frame = $&~FF_TRANSMASK
			gmobj.frame = $|tr_trans70<<FF_TRANSSHIFT
			if (gmobj.tracer)
				gmobj.tracer.frame = $&~FF_TRANSMASK
				gmobj.tracer.frame = $|tr_trans70<<FF_TRANSSHIFT
			end
		end
	end
end)

//Sonic & ashuro super dash
addHook("JumpSpinSpecial", function(player)
	if player.mo and player.mo.skin == "classicsonic"
	and player.powers[pw_super]
	and not (player.pflags & PF_THOKKED)
	and G_PlatformGametype()
	and (player.powers[pw_super])
	and player.rings >= 1
		P_NukeEnemies(player.mo, player.mo, 1000*FRACUNIT)
		P_FlashPal(player, PAL_WHITE, 1)
		S_StartSound(player.mo, sfx_zoom)
		player.mo.momz = 5
		P_InstaThrust(player.mo, player.mo.angle, 80*FRACUNIT)
		player.mo.state = S_PLAY_ROLL
		player.pflags = $|PF_THOKKED
	end
end)


addHook('ThinkFrame', do
    for player in players.iterate
        if player.mo and player.mo.valid
        and (player.mo.skin == "classicsonic")
          and player.mo.superblue == 1
            and player.powers[pw_super]
            and not (player.pflags & PF_FINISHED)
				end
				if (leveltime % 10) and player.mo.superblue == 1
					if (leveltime % 10) == 1
					or (leveltime % 10) == 8
					player.mo.color = SKINCOLOR_SUPERSKY2
					elseif (leveltime % 10) == 2
					or (leveltime % 10) == 7
					player.mo.color = SKINCOLOR_SUPERSKY3
					elseif (leveltime % 10) == 3
					or (leveltime % 10) == 6
					player.mo.color = SKINCOLOR_SUPERSKY4
					elseif (leveltime % 10) == 4
					or (leveltime % 10) == 5
					player.mo.color = SKINCOLOR_SUPERSKY5
					elseif (leveltime % 10) == 9
					player.mo.color = SKINCOLOR_SUPERSKY1
					end
				
     end 
end
end)

//Classic spindash behavior by rumia1!
addHook("ThinkFrame", do
	for player in players.iterate
		if player.mo and player.mo.valid
		and not (player.mo.state == S_PLAY_DEAD)
			if(player.mo.skin == "classicsonic")
				if player.mo.sprite2 == SPR2_FLY_
				or player.mo.sprite2 == SPR2_TIRE
					player.mo.spritexscale = 5*FRACUNIT/4
					player.mo.spriteyscale = 5*FRACUNIT/4
				else
					player.mo.spritexscale = FRACUNIT
					player.mo.spriteyscale = FRACUNIT
				end
			//setting up the variable to check for how many charges the current spindash has
				if player.spincharges == nil
					player.spincharges = 0
				end
			//this one checks how long the spindash has been held for
				if player.dashtime == nil
				or not (player.pflags & PF_STARTDASH)
					player.dashtime = 15
				end
			//and this one checks how many automatic charges we've added, as we can only have 4
				if player.dashcounter == nil
				or not (player.pflags & PF_STARTDASH)
					player.dashcounter = 0
				end
			//checks if player was holding jump last frame
				if player.jumpwasdown == nil
					player.jumpwasdown = 0
				end
				
				if player.forwardwasdown == nil
					player.forwardwasdown = 0
				end
				if player.backwasdown == nil
					player.backwasdown = 0
				end
				if player.leftwasdown == nil
					player.leftwasdown = 0
				end
				if player.rightwasdown == nil
					player.rightwasdown = 0
				end
				
			//makes our life easier
 				if player.pflags & PF_STARTDASH
 					player.dashspeed = player.maxdash
 					player.mindash = player.maxdash - (21*player.dashspeed)
 				end
		
				if player.dashcounter >= 3
					player.dashcounter = 3
				end
				if player.dashtime <= 0
					player.dashtime = 15
				end
				if testing == true then print(player.dashcounter, player.dashtime, player.dashspeed/FRACUNIT, player.spincharges) end
				if (player.pflags & PF_STARTDASH)
					player.jumpfactor = 0
					player.dashtime = $ - 1
					if player.spincharges == 0
						player.mindash = 23*FRACUNIT
						player.maxdash = 25*FRACUNIT
						player.mindash = player.maxdash - (21*player.dashspeed)
					else
						player.maxdash = (25*FRACUNIT) + (player.spincharges*(5*FRACUNIT))
					end
					if (player.cmd.forwardmove >= 25)
					and not (player.forwardwasdown)
					or (player.cmd.forwardmove <= -25)
					and not (player.backwasdown)
					or (player.cmd.sidemove >= 25)
					and not (player.rightwasdown)
					or (player.cmd.sidemove <= -25)
					and not (player.leftwasdown)
					or (player.cmd.buttons & BT_JUMP)
					and not (player.jumpwasdown)
						if player.spincharges < 15
							player.spincharges = $ + 1
						else
							player.spincharges = 15
						end
						S_StopSound(player.mo)
						S_StartSound(player.mo, 478 + player.spincharges)
					end

				else
					player.jumpfactor = skins[player.mo.skin].jumpfactor
					player.spincharges = 0
				end
			//Our "was jump pressed last frame?" check ends here
				player.jumpwasdown = (player.cmd.buttons & BT_JUMP)
				if (player.cmd.forwardmove >= 25)
					player.forwardwasdown = 1
				else
					player.forwardwasdown = 0
				end
				if (player.cmd.forwardmove <= -25)
					player.backwasdown = 1
				else
					player.backwasdown = 0
				end
				if (player.cmd.sidemove >= 25)
					player.rightwasdown = 1
				else
					player.rightwasdown = 0
				end
				if (player.cmd.sidemove <= -25)
					player.leftwasdown = 1
				else
					player.leftwasdown = 0
				end
			end
		end
	end
end)
