//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 == "ultsonic"
			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 == "ultsonic"
			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 == "ultsonic" 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 == "ultsonic"
		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 == "ultsonic"
		player.mo.dropprep = min(1,$)
	end
end)

addHook("ThinkFrame",function(player)
	for player in players.iterate()
		if player.mo.skin == "ultsonic"
			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 == "starsonic")
							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)