--Hyper stars
local function SpawnHyperStars(player)
	local hyperstar = P_SpawnMobjFromMobj(player.mo, 0, 0, 0, MT_SUPERSPARK)
	hyperstar.momx = P_RandomRange(-14, 14) * FRACUNIT + FixedMul(-12, 12, player.mo.scale)
	hyperstar.momy = P_RandomRange(-14, 14) * FRACUNIT + FixedMul(-12, 12, player.mo.scale)
	hyperstar.momz = P_RandomRange(-1, 9) * FRACUNIT + FixedMul(-12, 12, player.mo.scale)
	hyperstar.fuse = 7
	hyperstar.scale = player.mo.scale * 20/22
	hyperstar.source = player.mo
	if hyperstar.source.player == displayplayer
		local chasecam = CV_FindVar("chasecam")
		if (chasecam.value == 1)
			hyperstar.flags2 = $ & ~MF2_DONTDRAW
		elseif (chasecam.value == 0)
			hyperstar.flags2 = $ | MF2_DONTDRAW
		end
	end
end

//Tables of colors used for Hyper form's fading.
local fadingcolors = {SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE1, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE2, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE3, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE4, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE5, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE6}
local fadedcolors = {SKINCOLOR_IRIDESCENCE1, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE2, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE3, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE4, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE5, SKINCOLOR_IRIDESCENCEF, SKINCOLOR_IRIDESCENCE6, SKINCOLOR_IRIDESCENCEF}


--the actual hyper form stuff
addHook("PlayerThink",  function(player)
	local pmo = player.mo
	if not (pmo and pmo.valid) return end
	if (player == nil) return end

	if player.hyper == nil
		local hyper = {
		isunlocked = false,
		transformed = false,
		capable = false
		}
		player.hyperscript = true
		if pmo
			player.hyper = hyper
		else
			player.hyper = nil
		end
	end

	--if you're capable of going hyper
	if /*(skins[pmo.skin].flags & SF_SUPER)*/ pmo.skin == "supersonic" and player.hyper.isunlocked == true
		--let's fucking go
		if player.rings >= 100
		and not player.hyper.transformed
			player.hyper.capable = true
		end
		--If you haven't collected enough rings, fuck off, you aren't going hyper.
		if player.rings < 100
		and not player.hyper.transformed
			player.hyper.capable = false
		end
		--Going hyper will drain your rings twice as fast!
		if (leveltime % 35 == 18) and (player.hyper.transformed)
			P_GivePlayerRings(player, -1)
		end
		if player.hyper.transformed
			SpawnHyperStars(player)
			--Set the correct skincolor for Hyper stuff.
			pmo.color = (SKINCOLOR_SUPERSILVER1 + 5*((leveltime >> 1) % 7))
			--Adjust stats for hyper forms
			/*if not (player.charflags & SF_NOSUPERJUMPBOOST)
				player.jumpfactor = skins[pmo.skin].jumpfactor * 4 / 3
			end*/
			//player.actionspd = skins[pmo.skin].actionspd * 6 / 4
			player.thrustfactor = skins[pmo.skin].thrustfactor * 4 / 3
			--Hyper forms don't need to breathe.
			if (pmo.eflags & MFE_UNDERWATER)
				player.powers[pw_underwater] = 0
			end
			if P_InSpaceSector(pmo)
				player.powers[pw_spacetime] = 0
			end
			--afterimages
			if (player.speed > 2*FRACUNIT or pmo.momz > 2*FRACUNIT or pmo.momz < -1*FRACUNIT)
				local afterimage = P_SpawnGhostMobj(pmo)
				afterimage.rollangle = pmo.rollangle
				afterimage.fuse = 5
				afterimage.colorized = true
				afterimage.color = pmo.color
				afterimage.blendmode = AST_ADD
				afterimage.source = pmo
				if afterimage.source.player == displayplayer
					local chasecam = CV_FindVar("chasecam")
					if (chasecam.value == 1)
						afterimage.flags2 = $ & ~MF2_DONTDRAW
					elseif (chasecam.value == 0)
						afterimage.flags2 = $ | MF2_DONTDRAW
					end
				end
			end
		elseif (player.hyper.transformed == false or player.hyper.isunlocked == false)
			//player.actionspd = skins[pmo.skin].actionspd
			player.thrustfactor = skins[pmo.skin].thrustfactor
		end
	end
	if player.mo and player.mo.valid and player.mo.skin == "supersonic" and player.hyper.transformed
		if not player.sshypermusic
			P_PlayJingleMusic(player, "SSHYP", 0, true, JT_OTHER)
		end
		player.sshypermusic = true
	else
		player.sshypermusic = false
	end
end)

addHook("ThinkFrame", do
	for player in players.iterate do
		if player.mo and player.mo.valid and player.mo.skin == "supersonic"
			if player.mo.hypercolortimer == nil
				player.mo.hypercolortimer = 0
			end
			if player.mo.hypercolortimerdelay == nil
				player.mo.hypercolortimerdelay = 0
			end
			if player.mo.frame & FF_TRANSMASK
				player.mo.hypercolortimer = nil
			end
			if player.hyper.transformed
			and player.mo.frame > 0
				if (player.mo.hypercolortimerdelay)
					player.mo.hypercolortimerdelay = $ - 1
				else
					player.mo.hypercolortimer = $ or 0
				end
				if player.mo.hypercolortimer != nil
					player.mo.hypercolortimer = $ + 1
					local overlay = P_SpawnGhostMobj(player.mo)
					overlay.frame = ($ & ~FF_TRANSMASK)
					overlay.color = fadingcolors[((player.mo.hypercolortimer % 132) / 11) + 1]
					overlay.tics = 1
					local fade = 11 - (player.mo.hypercolortimer % 11)
					local transition
					if (fade >= 1 and fade <= 11)
						transition = P_SpawnGhostMobj(player.mo)
						transition.frame = ($ & ~FF_TRANSMASK) | (fade << FF_TRANSSHIFT)
						transition.color = fadedcolors[((player.mo.hypercolortimer % 132) / 11) + 1]
						transition.tics = 1
					end
					if (player.mo.hypercolortimer == ((22*#fadingcolors)-1))
						player.mo.hypercolortimer = nil
					end
				end
			end
		end
	end
end)

--local variables
local vertical_dash_dist = 20*FRACUNIT

--The quakes should only appear for the player creating them
local function StartQuakes(player)
	if (player == consoleplayer)
         P_StartQuake(7*FRACUNIT, 4)
	end
end

--Handles dashing in 3D
local function Do3DHyperDash(player)
    local pmo = player.mo
    --my god is this code a mess
    local dash_forward = (player.cmd.forwardmove) and not (((player.pflags & PF_USEDOWN) and (player.cmd.forwardmove) or ((player.cmd.forwardmove) and (player.cmd.sidemove))) and not (pmo.state == S_PLAY_FLOAT or pmo.state == S_PLAY_FLOAT_RUN))
    local dash_diagonal = ((player.cmd.forwardmove) and (player.cmd.sidemove)) and not ((player.pflags & PF_USEDOWN) and not (pmo.state == S_PLAY_FLOAT or pmo.state == S_PLAY_FLOAT_RUN))
	local dash_sideward = (player.cmd.sidemove) and not ((player.cmd.forwardmove) and (player.cmd.sidemove))  and not ((player.pflags & PF_USEDOWN) and not (pmo.state == S_PLAY_FLOAT or pmo.state == S_PLAY_FLOAT_RUN))
	local dash_upward = P_GetPlayerControlDirection(player) == 0 and not ((player.pflags & PF_USEDOWN) and not (pmo.state == S_PLAY_FLOAT or pmo.state == S_PLAY_FLOAT_RUN))
	local dash_downward = (player.pflags & PF_USEDOWN) and pmo.state != S_PLAY_FLOAT and pmo.state != S_PLAY_FLOAT_RUN
    if dash_forward
    	P_InstaThrust(pmo, pmo.angle, player.actionspd)
    elseif dash_diagonal
    	P_InstaThrust(pmo, player.drawangle, player.actionspd)
	elseif dash_sideward
    	P_InstaThrust(pmo, player.drawangle, player.actionspd)
    elseif dash_upward
    	P_SetObjectMomZ(pmo, vertical_dash_dist, false)
	elseif dash_downward
        P_SetObjectMomZ(pmo, -vertical_dash_dist, false)
	end
end
--Handles dashing in 2D
--the exact same way it worked in Sonic 3 & Knuckles
local function Do2DHyperDash(player)
    local pmo = player.mo
    local dash_forward = (player.cmd.forwardmove)
	local dash_upward = (player.cmd.forwardmove > 0) and not (player.cmd.forwardmove < 0)
	local dash_downward = (player.cmd.forwardmove < 0) and not (player.cmd.forwardmove > 0)
    if not dash_forward
		P_InstaThrust(pmo, pmo.angle, player.actionspd)
	elseif dash_upward
        P_SetObjectMomZ(pmo, vertical_dash_dist, false)
	elseif dash_downward
        P_SetObjectMomZ(pmo, -vertical_dash_dist, false)
	end
end

--now we can dash, yay :DDDDDD
addHook("AbilitySpecial", function(player)
    local pmo = player.mo
	if pmo.skin != "supersonic" then
	    return
	end
	if (player.pflags & PF_THOKKED) then
    	return
	end
	
	if (player.hyper.transformed) 
	    P_SpawnThokMobj(player)
        S_StartSound(pmo, sfx_s3kb6) 
        P_NukeEnemies(pmo, pmo, 1214*FRACUNIT)
--        StartQuakes(player)
        player.pflags = $ | PF_THOKKED
        P_FlashPal(player, PAL_WHITE, 3)
    	if not (pmo.flags2 & MF2_TWOD)
    	    Do3DHyperDash(player) --3D Hyper Dash
		else
		    Do2DHyperDash(player) --2D Hyper Dash
		end
	elseif (player.hyper.transformed == false) then
	    player.charability = skins[pmo.skin].ability
	end 
end)