local spawnx = 0
local spawny = 0
local spawnz = 0
local spawnangle = 0
local spawndrawangle = 0

freeslot("sfx_ringtk",
"sfx_hypert",
"MT_SUPERWARP",
"S_SUPERWARP",
"SPR_WARP",
"MT_SUPERBOLT")
sfxinfo[sfx_ringtk].caption = "Got Token"
states[S_SUPERWARP] = {SPR_WARP, A|FF_ANIMATE|FF_FULLBRIGHT, 7, nil, 7, 1, S_NULL}

mobjinfo[MT_SUPERWARP] = {
	spawnstate = S_SUPERWARP,
	spawnhealth = 1,
    deathstate = S_NULL,
    speed = FRACUNIT,
    radius = FRACUNIT,
    height = FRACUNIT,
	flags = MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPTHING
}

addHook("NetVars", function(network)
	spawnx = network($)
	spawny = network($)
	spawnz = network($)
	spawnangle = network($)
	spawndrawangle = network($)
end)

addHook("MapLoad", function()
	for player in players.iterate
		if io and player == consoleplayer
			local file = io.openlocal("client/supersonic/superdata.dat")
			if file
				local string = file:read("*a")
				if string == "true"
					player.hyper.isunlocked = true
				elseif string == "false" or string == nil
					player.hyper.isunlocked = false
				end
				file:close()
			end
		end
		spawnx = player.mo.x
		spawny = player.mo.y
		spawnz = player.mo.z
		spawnangle = player.mo.angle
		spawndrawangle = player.drawangle
	end
end)

addHook("ThinkFrame", do
	for player in players.iterate
		if player.mo and player.mo.valid
			if not player.mo.storedrings
				player.mo.storedrings = 0
			end
			if not player.mo.signpost
				player.mo.signpost = 0
			end
			if not player.mo.storedmusicpos
				player.mo.storedmusicpos = 0
			end
			if not player.mo.got1up
				player.mo.got1up = 0
			end
			if not player.mo.issuper
				player.mo.issuper = false
			end
			if not player.mo.switchtimer
				player.mo.switchtimer = 0
			end
			if not player.mo.shoespower
				player.mo.shoespower = false
			end
			if not player.mo.shoestats
				player.mo.shoestats = false
			end
			if not player.mo.sparklespower
				player.mo.sparklespower = false
			end
			if not player.sshypermusic
				player.sshypermusic = false
			end
			if not player.supertime
				player.supertime = 0
			end
			if player.mo and player.mo.valid
			and player.powers[pw_extralife]
				player.mo.got1up = true
			else
				if player.mo.got1up == true
					S_SetMusicPosition(player.mo.storedmusicpos)
					S_SetInternalMusicVolume(0, player)
					S_FadeMusic(100, MUSICRATE, player)
					player.mo.got1up = false
				end
				player.mo.storedmusicpos = S_GetMusicPosition()
			end
			if player.mo.skin == "supersonic"
				if player.mo.switchtimer < 2
					player.mo.switchtimer = $ + 1
				end
				if player.mo.issuper == false
					player.mo.issuper = true
				end
				player.shieldscale = 0
			end
			if player.mo and player.mo.valid
			and player.mo.skin ~= "supersonic"
			and player.mo.issuper == true
				player.powers[pw_super] = 0
				player.mo.color = player.skincolor
				player.mo.state = $
				player.shieldscale = skins[player.mo.skin].shieldscale
				P_SpawnShieldOrb(player)
				player.mo.issuper = false
				player.mo.switchtimer = 0
			end
			if S_MusicName() == "_super"
			and player.mo.issuper == false
				P_RestoreMusic(player)
			end
			if player.mo and player.mo.valid and player.mo.skin == "supersonic"
				player.mo.frame = $|FF_FULLBRIGHT
				if player.rings < 1
				and not netgame
				and not player.hyper.transformed
					P_DamageMobj(player.mo, nil, nil, 0, DMG_INSTAKILL)
				end
				if netgame
					if player.rings < 1
					and player.mo.switchtimer >= 2
					and player.playerstate == PST_LIVE
					and not player.hyper.transformed
						player.powers[pw_carry] = CR_NONE
						player.pflags = player.pflags & ~(PF_JUMPED | PF_SPINNING | PF_STARTDASH | PF_THOKKED | PF_SHIELDABILITY | PF_GLIDING | PF_BOUNCING | PF_SLIDING)
						player.mo.momx = 0
						player.mo.momy = 0
						player.mo.momz = 0
						if not player.starpostnum
							player.mo.angle = spawnangle
							player.drawangle = spawndrawangle
						else
							player.mo.angle = player.starpostangle
							player.drawangle = player.starpostangle
						end
						player.mo.state = S_PLAY_STND
						player.mo.flags2 = player.mo.flags2 & ~MF2_TWOD
						player.mo.flags2 = player.mo.flags2 & ~MF2_OBJECTFLIP
						if not player.starpostnum
							P_TeleportMove(player.mo, spawnx, spawny, spawnz)
						else
							P_TeleportMove(player.mo, player.starpostx*FRACUNIT, player.starposty*FRACUNIT, player.starpostz*FRACUNIT)
						end
						S_StartSound(player.mo, sfx_s3kb3)
						P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_SUPERWARP)
						player.rings = 25
					end
					if not All7Emeralds(emeralds)
						R_SetPlayerSkin(player, "sonic")
						S_StartSound(player.mo, sfx_lose)
						if P_RandomChance(FRACUNIT/100*50)
							CONS_Printf(player, "\x85"+"You need all 7 Chaos Emeralds before using Super Sonic!")
						elseif P_RandomChance(FRACUNIT/100*30)
							CONS_Printf(player, "\x85"+"You must first collect all 7 gems of the chaotic variety.")
						elseif P_RandomChance(FRACUNIT/100*50)
							CONS_Printf(player, "\x85"+"Maybe collect all of those emeralds first!")
						elseif P_RandomChance(FRACUNIT/100*40)
							CONS_Printf(player, "\x85"+"He's named SUPER Sonic for a reason!")
						elseif P_RandomChance(FRACUNIT/100*30)
							CONS_Printf(player, "\x85"+"Did you get all of those Chaos Emeralds?")
						elseif P_RandomChance(FRACUNIT/100*30)
							CONS_Printf(player, "\x85"+"get all of them magic poprocks, my dude")
						elseif P_RandomChance(FRACUNIT/100*40)
							CONS_Printf(player, "\x85"+"I hope you didn't expect to go super without those Chaos Emeralds!")
						end
					end
				end
				if player.playerstate == PST_LIVE and player.lives > 0 and player.spectator == false and not netgame and All7Emeralds(emeralds) == false then
					emeralds = $ | EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7
				end
				if not player.powers[pw_super]
				and not player.exiting
					player.powers[pw_super] = 1
				end
				if player.powers[pw_sneakers] > 10*TICRATE
				and not player.hyper.transformed 
					player.powers[pw_sneakers] = 10*TICRATE
					player.mo.shoespower = true
					S_StartSound(player.mo, sfx_s3k9f)
				elseif not player.powers[pw_sneakers]
				and player.mo.shoespower == true
					player.mo.shoespower = false
					player.mo.shoestats = false
					S_StartSound(player.mo, sfx_kc65)
				end
				if player.powers[pw_invulnerability] > 10*TICRATE
				and not player.hyper.transformed 
					player.powers[pw_invulnerability] = 10*TICRATE
					player.mo.sparklespower = true
					S_StartSound(player.mo, sfx_s3k46)
				elseif not player.powers[pw_invulnerability]
				and player.mo.sparklespower == true
					player.mo.sparklespower = false
					S_StartSound(player.mo, sfx_kc65)
				end
				if player.mo.shoespower
				or player.hyper.transformed
					player.mo.shoestats = true
					if player.mo.shoespower
						if leveltime % 1 == 0
							local superbolt = P_SpawnMobjFromMobj(player.mo, FRACUNIT*P_RandomRange(-16,16), FRACUNIT*P_RandomRange(-16,16), FixedDiv(player.mo.height/2,player.mo.scale)+(P_RandomRange(-16,16)*FRACUNIT), MT_SUPERBOLT)
							//superbolt.momz = FixedMul(FRACUNIT*2, player.mo.scale)*P_MobjFlip(player.mo)
							superbolt.scale = player.mo.scale
							superbolt.colorized = true
							superbolt.color = SKINCOLOR_SKY
							superbolt.frame = $|FF_FULLBRIGHT
							superbolt.target = player.mo
							if superbolt.target.player == displayplayer
								local chasecam = CV_FindVar("chasecam")
								if (chasecam.value == 1)
									superbolt.flags2 = $ & ~MF2_DONTDRAW
								elseif (chasecam.value == 0)
									superbolt.flags2 = $ | MF2_DONTDRAW
								end
							end
						end
						local ghost1 = P_SpawnGhostMobj(player.mo)
						ghost1.color = player.mo.color
						if player.mo.colorized
							ghost1.colorized = true
						else
							ghost1.colorized = false
						end
						ghost1.rollangle = player.mo.rollangle
						ghost1.fuse = 4
						ghost1.eflags = player.mo.eflags & MFE_VERTICALFLIP
						ghost1.source = player.mo
						if ghost1.source.player == displayplayer
							local chasecam = CV_FindVar("chasecam")
							if (chasecam.value == 1)
								ghost1.flags2 = $ & ~MF2_DONTDRAW
							elseif (chasecam.value == 0)
								ghost1.flags2 = $ | MF2_DONTDRAW
							end
						end
					end
					player.normalspeed = 54*FRACUNIT
					player.actionspd = 90*FRACUNIT
				end
				if not player.mo.shoestats
					player.normalspeed = 36*FRACUNIT
					player.actionspd = 60*FRACUNIT
				end
				if (netgame and (player.pflags & PF_FINISHED or player.powers[pw_carry] == CR_MINECART))
				or player.mo.sparklespower
				or (player.hyper.transformed and player.hyper.transformed <= 34)
				or not (player.realtime > player.supertime) //waiting periods on bosses can go die (:
					if not player.mo.storedrings
					or player.rings > player.mo.storedrings
						player.mo.storedrings = player.rings
					end
					if player.rings < player.mo.storedrings
						player.rings = player.mo.storedrings
					end
				else
					player.mo.storedrings = 0
				end
				if player.cmd.buttons & BT_CUSTOM1
				and (player.hyper.capable == true)
				and not player.hyper.transformed
				and player.pflags & PF_JUMPED
				and not player.exiting
					player.hyper.transformed = 1
					S_StartSound(nil, sfx_hypert)
					P_SetMobjStateNF(player.mo, S_PLAY_SUPER_TRANS1)
					player.mo.state = S_PLAY_SUPER_TRANS1
					player.mo.frame = A
				end
				local sparkcolors = {SKINCOLOR_IRIDESCENCE1, SKINCOLOR_IRIDESCENCE2, SKINCOLOR_IRIDESCENCE3, SKINCOLOR_IRIDESCENCE4, SKINCOLOR_IRIDESCENCE5, SKINCOLOR_IRIDESCENCE6}
				local getColor = (leveltime % #sparkcolors )
				if player.hyper.capable
				and not player.hyper.transformed
				and not player.exiting
					if leveltime % 1 == 0
						local hyperspark = P_SpawnMobjFromMobj(player.mo, FRACUNIT*P_RandomRange(-16,16), FRACUNIT*P_RandomRange(-16,16), FixedDiv(player.mo.height/2,player.mo.scale)+(P_RandomRange(-16,16)*FRACUNIT), MT_SUPERBOLT)
						hyperspark.state = S_SEED
						hyperspark.fuse = 6
						hyperspark.scale = player.mo.scale
						hyperspark.colorized = true
						hyperspark.color = sparkcolors[getColor+1]
						hyperspark.frame = $|FF_FULLBRIGHT
						hyperspark.target = player.mo
						if hyperspark.target.player == displayplayer
							local chasecam = CV_FindVar("chasecam")
							if (chasecam.value == 1)
								hyperspark.flags2 = $ & ~MF2_DONTDRAW
							elseif (chasecam.value == 0)
								hyperspark.flags2 = $ | MF2_DONTDRAW
							end
						end
					end
				end
				if player.hyper.transformed 
					if player.powers[pw_invulnerability] > 0
					or	player.powers[pw_sneakers] > 0
						player.powers[pw_invulnerability] = 0
						player.powers[pw_sneakers] = 0
						P_GivePlayerRings(player, 20)
						S_StartSound(player.mo, sfx_token)
					end
					player.charflags = $|SF_CANBUSTWALLS
					if player.hyper.transformed < TICRATE
						player.hyper.transformed = $ + 1
					end
					//safety net so you don't die for going hyper.
					if player.rings < 1
					or player.exiting
						player.hyper.capable = false
						player.hyper.transformed = 0
						if player.rings < 1
							player.rings = 10
						end
						player.mo.shoestats = false //take away shoe stats.
						player.sshypermusic = false //music hinge
						S_StartSound(player.mo, sfx_s3k9c) //sound
						player.thrustfactor = skins[player.mo.skin].thrustfactor //thrustfactor reset
						player.powers[pw_flashing] = 35 //flashing for aesthetic purposes
						P_RestoreMusic(player) // music stuff
						S_SetMusicPosition(0)
						S_SetInternalMusicVolume(0, player)
						S_FadeMusic(100, MUSICRATE, player)
					end
				else
					player.charflags = $ & ~SF_CANBUSTWALLS
				end
			end
		end
	end
end)

//Give the player 25 Rings if they pick up an Emerald Token, and manage their color.
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid and player.mo.skin == "supersonic"
		player.mo.color = player.skincolor
		if player.mo.ringtokengrabbed
			P_GivePlayerRings(player, 25)
			P_AddPlayerScore(player, 1000)
			S_StartSound(player.mo, sfx_ringtk)
			player.mo.ringtokengrabbed = false
		end
	end
end)

addHook("TouchSpecial", function(emeraldtoken, mo)
	if All7Emeralds(emeralds)
	and mo.skin == "supersonic"
		if not emeraldtoken.grabbed then
			mo.ringtokengrabbed = true
			emeraldtoken.grabbed = true
			P_KillMobj(emeraldtoken)
			return true
		end
	elseif not All7Emeralds(emeralds)
		return false
	end
end, MT_TOKEN)

//Making it so you start with 25 rings and am super upon spawn.
addHook("PlayerSpawn", function(player)
	if player.mo and player.mo.valid and player.mo.skin == "supersonic"
		P_GivePlayerRings(player, 25)
		player.mo.state = $
		if player.hyper
		and player.hyper.transformed
			player.hyper.transformed = false
		end
	end
end)
		
addHook("MobjDamage", function(target, inflictor, source, damage, damagetype)
	if inflictor and inflictor.valid and inflictor.type == MT_PLAYER
		local issuper = false
		for player in players.iterate
			if player.mo and player.mo.valid
			and player.mo.skin == "supersonic"
				issuper = true
			end
		end
		if issuper
			if target.flags & MF_BOSS
				for player in players.iterate
					if target.type == MT_METALSONIC_BATTLE
						P_GivePlayerRings(player, 6)
					else
						P_GivePlayerRings(player, 5)
					end
				end
				S_StartSoundAtVolume(target.mo, sfx_kc5e, 105)
			end
			if target.flags & MF_ENEMY
			and issuper
			and inflictor.skin == "supersonic" --Double checking since the 'issuper' check isn't enough, apparently.
				if inflictor.player.hyper.transformed
				and not (damagetype & DMG_NUKE)
					P_GivePlayerRings(inflictor.player, 4)
				elseif (damagetype & DMG_NUKE)
					P_GivePlayerRings(inflictor.player, 2)
				else
					P_GivePlayerRings(inflictor.player, 2)
				end
				S_StartSoundAtVolume(inflictor, sfx_kc5d, 105)
			end
		end
	end
end)

addHook("ShouldDamage", function(target, inflictor, source, damage, damagetype)
    if target and target.valid and target.skin == "supersonic"
	and netgame
	and target.player.rings == 0
	and not (damagetype & DMG_DEATHMASK)
        return false
	end
end)

addHook("MobjThinker", function(sign)
	if sign.tracer.tracer  --tracers of tracers are dumb.
		if sign.tracer.tracer.skin == "supersonic"
			sign.tracer.tracer.tics = -1
			sign.tracer.tracer.frame = ((leveltime / 7) % 4) | (FF_FULLBRIGHT|FF_PAPERSPRITE)
		end
	end
end, MT_SIGN)

//Ring Attraction function based upon P_Attract from source.
local function SuperAttract(source, dest)
	local dist = 0
	local ndist = 0
	local speedmul = 0
	local tx = dest.x
	local ty = dest.y
	local tz = dest.z + (dest.height/2)
	local xydist = P_AproxDistance(tx - source.x, ty - source.y)
	if dest and dest.health and dest.valid and dest.type == MT_PLAYER
		source.angle = R_PointToAngle2(source.x, source.y, tx, ty)
		dist = P_AproxDistance(xydist, tz - source.z)
		if (dist < 1)
			dist = 1
		end
		speedmul = P_AproxDistance(dest.momx, dest.momy) + FixedMul(source.info.speed, source.scale)
		source.momx = FixedMul(FixedDiv(tx - source.x, dist), speedmul)
		source.momy = FixedMul(FixedDiv(ty - source.y, dist), speedmul)
		source.momz = FixedMul(FixedDiv(tz - source.z, dist), speedmul)
		ndist = P_AproxDistance(P_AproxDistance(tx - (source.x + source.momx), ty - (source.y+source.momy)), tz - (source.z+source.momz))
		if (ndist > dist)
			source.momx = 0
			source.momy = 0
			source.momz = 0
			P_TeleportMove(source, tx, ty, tz)
		end
	end
end

addHook("MobjThinker", function(ring)
    if ring and ring.valid and ring.health > 0
        local soup
        for p in players.iterate
            if p.mo and p.mo.valid and p.mo.skin == "supersonic" and R_PointToDist2(p.mo.x, p.mo.y, ring.x, ring.y) <= (RING_DIST/6) and abs(ring.z - p.mo.z) < (RING_DIST/6)
                soup = p.mo
            end
        end
        if soup
            local momRing = P_SpawnMobjFromMobj(ring, 0,0,0, MT_FLINGRING)
            momRing.followmo = soup
            P_RemoveMobj(ring)
        end
    end
end, MT_RING)

addHook("MobjThinker", function(ring)
    if ring and ring.valid and ring.health > 0 and ring.followmo and ring.followmo.valid
        if R_PointToDist2(ring.followmo.x, ring.followmo.y, ring.x, ring.y) <= RING_DIST/3 and abs(ring.z - ring.followmo.z) < RING_DIST/3
			SuperAttract(ring, ring.followmo)
        else
            ring.fuse = 5*TICRATE
        end
        if ring.fuse == 2
            P_SpawnMobjFromMobj(ring, 0,0,0, MT_RING)
            P_RemoveMobj(ring)
        end
    end
end, MT_FLINGRING)

//Bloops and GoldenShine were here having a conniption with me -Icezer
local function SCREWHEIGHTCHECKS(i_swear, to_god, you_bugger)
  if ((i_swear.z <= to_god.z + to_god.height + you_bugger)
  and (to_god.z <= i_swear.z + i_swear.height + you_bugger))
    return true
  end
end

local function SpikesBegone(spike, plmo)
    if not (plmo and plmo.valid and plmo.player) return end
    if (plmo.skin ~= "supersonic") return end
    if SCREWHEIGHTCHECKS(spike, plmo, 5*FU+abs(plmo.momz))
		local p = plmo.player
		if plmo.shoespower
		or (p.hyper and p.hyper.transformed)
			P_KillMobj(spike, plmo, plmo)
			return false
		end
	end
end

addHook("MobjCollide", SpikesBegone, MT_SPIKE)
addHook("MobjCollide", SpikesBegone, MT_WALLSPIKE)

addHook("PostThinkFrame", function(player)
	for player in players.iterate do
		if player.mo and player.mo.valid and player.mo.skin == "supersonic"
			player.supertime = player.realtime //doing this for reasons
		end
	end
end)

addHook("MobjThinker", function(s)
//This code here was originally written by Golden Shine for SA-Sonic. Reused with explicit permission, so please do NOT reuse without asking him.
	if s.target and s.target.valid and s.target.player --You have passed the vibe check, observe and steal nothing.
	and s.target.player.exiting and (s.target.player.powers[pw_carry] == CR_NIGHTSMODE)
		if (s.sprite == SPR_CEMG) and (s.frame == H or s.frame >= H|FF_FULLBRIGHT)
		or (gamemap == 57 and mapheaderinfo[gamemap].lvlttl == "Black Hole") --You're welcome, Goal Ring mod.
			for z in players.iterate
				s.target.player.hyper.isunlocked = true
			end
			if s.target.player.hyper.isunlocked == true
				if io and s.target.player == consoleplayer
					local file = io.openlocal("client/supersonic/superdata.dat", "w+")
					file:write('true')
					file:close()
				end
			end
		end
	end
end, MT_GOTEMERALD)