if not(kirbyabilitytable)
	rawset(_G, "kirbyabilitytable", {})
end
kirbyabilitytable["altsonic"] = 9

local superdash
local hypertrans
local hypertransend
freeslot("MT_ALTSPARKLES",
	"S_ASPARKLES1",
	"S_ASPARKLES2",
	"S_ASPARKLES3",
	"S_ASPARKLES4",
	"S_ASPARKLES5",
	"S_ASPARKLES6",
	"S_ASPARKLES7",
	"S_ASPARKLES8",
	"S_ASPARKLES9",
	"S_ASPARKLES10",
	"S_ASPARKLES11",
	"S_ASPARKLES12",
	"S_ASPARKLES13",
	"S_ASPARKLES14",
	"S_ASPARKLES15",
	"SPR_ASPK",
	"MT_ALTSSPARKLES",
	"S_ASSPARKLES1",
	"S_ASSPARKLES2",
	"S_ASSPARKLES3",
	"S_ASSPARKLES4",
	"S_ASSPARKLES5",
	"S_ASSPARKLES6",
	"S_ASSPARKLES7",
	"S_ASSPARKLES8",
	"S_ASSPARKLES9",
	"SPR_ASSP",
	"S_PLAY_SUPERDASH",
	"S_PLAY_HYPER_TRANS",
	"S_PLAY_HYPER_TRANSEND",
	"SPR2_SDSH",
	"SPR2_HTRN",
	"sfx_sdsh",
	"sfx_ispn",
	"sfx_aspn",
	"sfx_chrg",
	"sfx_astp",
	"sfx_atwn",
	"sfx_adsh",
	"sfx_abom",
	"sfx_ahom",
	"sfx_hypert",
	"S_ALTSHOCKWAVE1",
	"S_ALTSHOCKWAVE2",
	"S_ALTSHOCKWAVE3",
	"S_ALTSHOCKWAVE4",
	"S_ALTSHOCKWAVE5",
	"SPR_SCKW",
	"MT_ALTSHOCKWAVE",
	"SPR_ATHK",
	"S_ALTTHOK",
	"MT_ALTTHOK"
)

sfxinfo[sfx_sdsh].caption = "Supercharged"
sfxinfo[sfx_ispn].caption = "Instaspin"
sfxinfo[sfx_cdfm35].caption = "Dash"
sfxinfo[sfx_astp].caption = "Atom Stop"
sfxinfo[sfx_atwn].caption = "Twinkle"
sfxinfo[sfx_chrg].caption = "Atom Dash Max Charge"
sfxinfo[sfx_adsh].caption = "Atom Dash"
sfxinfo[sfx_abom].caption = "Atom Crash"
sfxinfo[sfx_ahom].caption = "Homing Thok"
sfxinfo[sfx_s23c].caption = "Launch"
sfxinfo[sfx_hypert].caption = "Transformation"
sfxinfo[sfx_aspn].priority = 9999999

superdash = S_PLAY_SUPERDASH
states[superdash].sprite = SPR_PLAY
states[superdash].frame = SPR2_SDSH|FF_ANIMATE
states[superdash].var1 = 3
states[superdash].var2 = 1
states[superdash].tics = -1
states[superdash].nextstate = S_PLAY_DASH

//Hyper form states.
hypertrans = S_PLAY_HYPER_TRANS
states[hypertrans] = {
  sprite = SPR_PLAY,
  frame = SPR2_HTRN|FF_FULLBRIGHT,
  tics = -1,
  nextstate = S_PLAY_HYPER_TRANS
}

hypertransend = S_PLAY_HYPER_TRANSEND
states[hypertransend] = {
  sprite = SPR_PLAY,
  frame = SPR2_HTRN|FF_FULLBRIGHT,
  tics = 19,
  nextstate = S_PLAY_FALL
}

//Thoksplosion originally by Bloops.
local function Thoksplosion(mo)
	if mo and mo.valid
		for i = 1, 64
			if i <= 32 --we'll have 32 thok-based booms
				local boom2 = P_SpawnMobjFromMobj(mo, P_RandomRange(-25, 25)*FRACUNIT,
				P_RandomRange(-25, 25)*FRACUNIT,
				P_RandomRange(-25, 25)*FRACUNIT,
				MT_THOK)
				boom2.tics = TICRATE*2
				boom2.boomer = true --we'll attach a separate hook to this mobj
				P_InstaThrust(boom2, FixedAngle(P_RandomRange(0, 360)*FRACUNIT), P_RandomRange(5, 10)*FRACUNIT)
				boom2.momz = P_RandomRange(5, 10)*FRACUNIT*P_MobjFlip(boom2)
				boom2.flags = MF_NOCLIPHEIGHT|MF_NOCLIP
				boom2.destscale = 0
				boom2.scalespeed = FRACUNIT/(TICRATE*2)
				boom2.color = SKINCOLOR_YELLOW
			else
				local boom2 = P_SpawnMobjFromMobj(mo, P_RandomRange(-60, 60)*FRACUNIT,
				P_RandomRange(-60, 60)*FRACUNIT,
				P_RandomRange(-60, 60)*FRACUNIT,
				P_RandomChance(FRACUNIT/2) and MT_BOSSEXPLODE or MT_SONIC3KBOSSEXPLODE)--50% chance of spawning either
				boom2.tics = $ + P_RandomRange(0, 10) --asking for a bit more variety
				boom2.scale = $ + P_RandomRange(0, FRACUNIT/2)
			end
		end
	end		
end

//Command for homing attack.
COM_AddCommand("legacymode", function(player, arg)
	if arg
		if arg == "1" or arg == "true" or arg == "on"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/legacymode.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.althoming = true
			CONS_Printf(player, "Homing Attack set as Main Ability.")
		elseif arg == "0" or arg == "false" or arg == "off"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/legacymode.dat", "w+")
				file:write(arg)
				file:close()
			end	
			player.althoming = false
			CONS_Printf(player, "Atom Dash set as Main Ability.")
		elseif player.althoming
			CONS_Printf(player, "legacymode [on/off] - Switches Alt Sonic's main ability from the Atom Dash to a Homing Attack. Currently on.")
		else
			CONS_Printf(player, "legacymode [on/off] - Switches Alt Sonic's main ability from the Atom Dash to a Homing Attack. Currently off.")
		end
	elseif player.althoming
		CONS_Printf(player, "legacymode [on/off] - Switches Alt Sonic's main ability from the Atom Dash to a Homing Attack. Currently on.")
	else
		CONS_Printf(player, "legacymode [on/off] - Switches Alt Sonic's main ability from the Atom Dash to a Homing Attack. Currently off.")
	end
end, 0)

local powertrailss = true
//Command to toggle blending trails for Super Dash Mode/ Hyper Form for EVERYONE. Only usable by server hosts/admins.
COM_AddCommand("powertrails_server", function(player, arg)
	if arg
		if arg == "1" or arg == "true" or arg == "on"
			powertrailss = true
			CONS_Printf(player, "Blending trails globally enabled.")
		elseif arg == "0" or arg == "false" or arg == "off"
			powertrailss = false
			CONS_Printf(player, "Blending trails globally disabled.")
		elseif powertrailss
			CONS_Printf(player, "powertrails_server [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form for everyone in a netgame. Currently on.")
		else
			CONS_Printf(player, "powertrails_server [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form for everyone in a netgame. Currently off.")
		end
	elseif powertrailss
		CONS_Printf(player, "powertrails_server [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form for everyone in a netgame. Currently on.")
	else
		CONS_Printf(player, "powertrails_server [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form for everyone in a netgame. Currently off.")
	end
end, COM_ADMIN)

addHook("NetVars", function(network)
	powertrailss = network($)
end)

//Command to toggle blending trails for Super Dash Mode/ Hyper Form.
COM_AddCommand("powertrails", function(player, arg)
	if arg
		if arg == "1" or arg == "true" or arg == "on"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/powertrails.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.powertrails = true
			CONS_Printf(player, "Blending trails enabled.")
		elseif arg == "0" or arg == "false" or arg == "off"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/powertrails.dat", "w+")
				file:write(arg)
				file:close()
			end	
			player.powertrails = false
			CONS_Printf(player, "Blending trails disabled.")
		elseif player.powertrails
			CONS_Printf(player, "powertrails [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form. Currently on.")
		else
			CONS_Printf(player, "powertrails [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form. Currently off.")
		end
	elseif player.powertrails
		CONS_Printf(player, "powertrails [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form. Currently on.")
	else
		CONS_Printf(player, "powertrails [on/off] - Toggles additive blending trails for Super Dash mode/Hyper Form. Currently off.")
	end
end, 0)

//Command for quakes. Used to be a CVAR but I/O doesn't like those.
COM_AddCommand("altquakes", function(player, arg)
	if arg
		if arg == "1" or arg == "true" or arg == "on"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altquakes.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altquakes = true
			CONS_Printf(player, "Quakes enabled.")
		elseif arg == "0" or arg == "false" or arg == "off"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altquakes.dat", "w+")
				file:write(arg)
				file:close()
			end	
			player.altquakes = false
			CONS_Printf(player, "Quakes disabled.")
		elseif player.altquakes
			CONS_Printf(player, "altquakes [on/off] - Toggles Alt Sonic's quakes, which can be seen in Hyper Form/Super Dash Mode. Currently enabled.")
		else
			CONS_Printf(player, "altquakes [on/off] - Toggles Alt Sonic's quakes, which can be seen in Hyper Form/Super Dash Mode. Currently disabled.")
		end
	elseif player.altquakes
		CONS_Printf(player, "altquakes [on/off] - Toggles Alt Sonic's quakes, which can be seen in Hyper Form/Super Dash Mode. Currently enabled.")
	else
		CONS_Printf(player, "altquakes [on/off] - Toggles Alt Sonic's quakes, which can be seen in Hyper Form/Super Dash Mode. Currently disabled.")
	end
end, 0)

//Command to change Hyper theme.
COM_AddCommand("hypermusic", function(player, arg)
	if arg
		if arg == "default" or arg == "speedy"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = true
			player.altmusic2 = false
			player.altmusic3 = false
			player.altmusic4 = false
			player.altmusic5 = false
			player.altmusic6 = false
			player.altmusic7 = false
			CONS_Printf(player, "Hyper music set to 'Beyond the Speed Of (Sonic Runners)'")
		elseif arg == "adventurous"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = false
			player.altmusic2 = true
			player.altmusic3 = false
			player.altmusic4 = false
			player.altmusic5 = false
			player.altmusic6 = false
			player.altmusic7 = false
			CONS_Printf(player, "Hyper music set to 'It Doesn't Matter (Sonic Adventure 2)'")
		elseif arg == "boundless"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = false
			player.altmusic2 = false
			player.altmusic3 = true
			player.altmusic4 = false
			player.altmusic5 = false
			player.altmusic6 = false
			player.altmusic7 = false
			CONS_Printf(player, "Hyper music set to 'Endless Possibilities (Sonic Unleashed)'")
		elseif arg == "olympic"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = false
			player.altmusic2 = false
			player.altmusic3 = false
			player.altmusic4 = true
			player.altmusic5 = false
			player.altmusic6 = false
			player.altmusic7 = false
			CONS_Printf(player, "Hyper music set to 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'")
		elseif arg == "radiant"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = false
			player.altmusic2 = false
			player.altmusic3 = false
			player.altmusic4 = false
			player.altmusic5 = true
			player.altmusic6 = false
			player.altmusic7 = false
			CONS_Printf(player, "Hyper music set to 'Reach For The Stars (Sonic Colors)'")
		elseif arg == "nights"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = false
			player.altmusic2 = false
			player.altmusic3 = false
			player.altmusic4 = false
			player.altmusic5 = false
			player.altmusic6 = true
			player.altmusic7 = false
			CONS_Printf(player, "Hyper music set to 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'")
		elseif arg == "unstoppable"
			if io and player == consoleplayer
				local file = io.openlocal("client/altsonic/altmusic.dat", "w+")
				file:write(arg)
				file:close()
			end
			player.altmusic1 = false
			player.altmusic2 = false
			player.altmusic3 = false
			player.altmusic4 = false
			player.altmusic5 = false
			player.altmusic6 = false
			player.altmusic7 = true
			CONS_Printf(player, "Hyper music set to 'Super Sonic Racing (Sonic Generations)'\n")
		elseif player.altmusic1
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Beyond the Speed Of (Sonic Runners)'")
		elseif player.altmusic2
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'It Doesn't Matter (Sonic Adventure 2)'")
		elseif player.altmusic3
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Endless Possibilities (Sonic Unleashed)'")
		elseif player.altmusic4
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'")
		elseif player.altmusic5
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Reach For The Stars (Sonic Colors)'")
		elseif player.altmusic6
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'")
		elseif player.altmusic7
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Super Sonic Racing (Sonic Generations)'")
		else
			CONS_Printf(player, "Something seems to have broken.")
		end
		elseif player.altmusic1
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Beyond the Speed Of (Sonic Runners)'")
		elseif player.altmusic2
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'It Doesn't Matter (Sonic Adventure 2)'")
		elseif player.altmusic3
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Endless Possibilities (Sonic Unleashed)'")
		elseif player.altmusic4
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'")
		elseif player.altmusic5
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Reach For The Stars (Sonic Colors)'")
		elseif player.altmusic6
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'")
		elseif player.altmusic7
			CONS_Printf(player, "hypermusic [argument] - Changes what music plays for hyper form. Acceptable arguments are:\n"..
			"\n"..
			"speedy - 'Beyond the Speed Of (Sonic Runners)'\n"..
			"adventurous - 'It Doesn't Matter (Sonic Adventure 2)'\n"..
			"boundless - 'Endless Possibilites (Sonic Unleashed)'\n"..
			"olympic - 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'\n"..
			"radiant - 'Reach For The Stars (Sonic Colors)'\n"..
			"nights - 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'\n"..
			"unstoppable - Super Sonic Racing (Sonic Generations)'\n"..
			"\n"..
			"Currently 'Super Sonic Racing (Sonic Generations)'")
		else
			CONS_Printf(player, "Something seems to have broken.")
	end
end, 0)

local function FixedLerp(a, b, w)
    return FixedMul((FRACUNIT - w), a) + FixedMul(w, b)
end

local TRAIL_SPACE = 4*FRACUNIT
local function SpawnTrail(p)
	local mo = p.mo
	local crystal = p.crystal

	local x1, y1, z1 = mo.previousx, mo.previousy, mo.previousz
	local x2, y2, z2 = p.mo.x, p.mo.y, p.mo.z
	local xDist, yDist, zDist = x1 - x2, y1 - y2, z1 - z2
	local space = FixedMul(TRAIL_SPACE, mo.scale)
	local dist = FixedHypot(FixedHypot(xDist, yDist), zDist)
	local distance = dist
	if dist <= 0 return end
	local xFactor = FixedDiv(xDist, dist)
	local yFactor = FixedDiv(yDist, dist)
	local zFactor = FixedDiv(zDist, dist)
	if mo.eflags & MFE_VERTICALFLIP
		zFactor = -$
	end
	while dist > 0
		local thok = P_SpawnMobjFromMobj(p.mo,
			FixedMul(xFactor, dist),
			FixedMul(yFactor, dist),
			FixedMul(zFactor, dist) - 6*FU,
			MT_ALTTHOK, player)
		if p.althyper.transforming
			thok.frame = B|TR_TRANS80
		else
			thok.frame = A|TR_TRANS40
		end
		local oldHeight = thok.height
		if p.powers[pw_super]
		and p.althyper.transforming
			thok.blendmode = AST_ADD
			if p.mo.color == SKINCOLOR_SUPER_HYPER_1
				thok.color = SKINCOLOR_BUBBLEGUM
			elseif p.mo.color == SKINCOLOR_SUPER_HYPER_2
				thok.color = SKINCOLOR_ROSY
			elseif p.mo.color == SKINCOLOR_SUPER_HYPER_3
				thok.color = SKINCOLOR_APRICOT
			elseif p.mo.color == SKINCOLOR_SUPER_HYPER_4
				thok.color = SKINCOLOR_EMERALD
			elseif p.mo.color == SKINCOLOR_SUPER_HYPER_5
				thok.color = SKINCOLOR_SKY
			end
		elseif p.mo.color == SKINCOLOR_ALTBLUE
			thok.color = SKINCOLOR_BLUE
			thok.blendmode = AST_ADD
		else
			thok.color = p.mo.color
			thok.blendmode = AST_ADD
		end
		if p.althyper.transforming
			thok.scale = p.mo.scale*5/2
		else
			thok.scale = p.mo.scale
		end
		thok.source = p.mo
		if thok.source.player == displayplayer
			local chasecam = CV_FindVar("chasecam")
			if (chasecam.value == 1)
				thok.flags2 = $ & ~MF2_DONTDRAW
			elseif (chasecam.value == 0)
				thok.flags2 = $ | MF2_DONTDRAW
			end
		end
		thok.destscale = 0
		thok.scalespeed = thok.scale/thok.tics
		P_SetScale(thok, thok.scale - FixedMul(thok.scalespeed, FixedDiv(dist, distance)))
		thok.z = $ + (oldHeight - thok.height)/2
		dist = $ - space
	end
end

addHook("PostThinkFrame", function()
    for player in players.iterate()
		if player.mo and player.mo.valid and player.mo.skin == "altsonic"
			if player.althoming == false return end
			if player.bonkvar == true return end
			local mo = player.mo
			if not (mo and mo.valid) continue end
			if (player == nil) or (player.playerstate != PST_LIVE) continue end
		
			if (mo.oldx == nil) or (mo.oldy == nil) or (mo.oldz == nil)
				mo.oldx = mo.x
				mo.oldy = mo.y
				mo.oldz = mo.z
			end
			
			if player.hominglockon and player.hominglockon.valid and player.hominglockon.health //make sure we have a target
			and not (player.hominglockon.flags2 & MF2_FRET)
			and player.hominglockon.type ~= MT_BIGMINE
			and player.hominglockon.type ~= MT_EGGSHIELD
			and player.hominglockon.type ~= MT_TNTBARREL
			and player.hominglockon.type ~= MT_DETON
			and player.hominglockon.type ~= MT_FAKEMOBILE 
			and player.pflags & PF_THOKKED
				for i = 0, 9
					local percent = FRACUNIT * (i * 10) / 100
					local trail = P_SpawnGhostMobj(mo)
					local tx = FixedLerp(mo.x,mo.oldx,percent)
					local ty = FixedLerp(mo.y,mo.oldy,percent)
					local tz = FixedLerp(mo.z + 3*FRACUNIT,mo.oldz + 4*FRACUNIT,percent)
					P_TeleportMove(trail, tx, ty, tz - 7 * FRACUNIT)
					trail.fuse = 13
					trail.state = S_THOK
					trail.scalespeed = FRACUNIT/12
					trail.scale = (FRACUNIT * 5/6) - (i * FRACUNIT/120)
					trail.destscale = 0
					trail.frame = TR_TRANS70|A
					trail.blendmode = AST_ADD
					if player.powers[pw_super]
					and player.althyper.transforming
						trail.blendmode = AST_ADD
						if player.mo.color == SKINCOLOR_SUPER_HYPER_1
							trail.color = SKINCOLOR_BUBBLEGUM
						elseif player.mo.color == SKINCOLOR_SUPER_HYPER_2
							trail.color = SKINCOLOR_ROSY
						elseif player.mo.color == SKINCOLOR_SUPER_HYPER_3
							trail.color = SKINCOLOR_APRICOT
						elseif player.mo.color == SKINCOLOR_SUPER_HYPER_4
							trail.color = SKINCOLOR_EMERALD
						elseif player.mo.color == SKINCOLOR_SUPER_HYPER_5
							trail.color = SKINCOLOR_SKY
						end
					elseif player.mo.color == SKINCOLOR_ALTBLUE
						trail.color = SKINCOLOR_BLUE
						trail.blendmode = AST_ADD
					else
						trail.color = player.mo.color
						trail.blendmode = AST_ADD
					end
				end
			end
			mo.oldx = mo.x
			mo.oldy = mo.y
			mo.oldz = mo.z
		end
    end
end)

local function DoRunDust(player) //Running particle function based on spindash dust from source.
	local mo = player.mo
	local prandom = {}
	for i = 0, (leveltime%7) >> 1 // 1, 2, 3 or 4 particles
		local particle = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_SDMPARTICLES)
		particle.color = player.mo.color
		particle.colorized = true

		particle.target = mo
		particle.destscale = (mo.destscale << 1)/3
		P_SetScale(particle, particle.destscale)
		if mo.eflags & MFE_VERTICALFLIP // readjust z position if needed
			particle.z = mo.z + mo.height - particle.height
		end
		prandom[0] = P_RandomFixed()<<2 // P_RandomByte()<<10
		prandom[1] = P_RandomRange(-30, 30) // P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT
		prandom[2] = P_RandomFixed()<<3 // P_RandomByte()<<11
		P_SetObjectMomZ(particle, player.normalspeed/50 + prandom[0], false)
		P_InstaThrust(particle,
				player.drawangle + prandom[1]*ANG1,
				-FixedMul(player.normalspeed/12 + FRACUNIT + prandom[2], mo.scale))
		P_TryMove(particle, particle.x + particle.momx, particle.y + particle.momy, true)
	end
end

addHook("MobjThinker", function(mo)
	if mo and mo.valid
		if not mo.source return end
		mo.lifetime = $ or 0
		--mo.x = mo.source.x + mo.lifetime * mo.momx
		--mo.y = mo.source.y + mo.lifetime * mo.momy
		--mo.z = mo.source.z + mo.lifetime * mo.momz
		P_TeleportMove(mo, mo.source.x + mo.lifetime * mo.momx, mo.source.y + mo.lifetime * mo.momy, mo.source.z + 17*FRACUNIT + mo.lifetime * mo.momz)
		mo.lifetime = $ + 1
	end
end, MT_ALTSPARKLES)

addHook("MobjThinker", function(mo)
    if not mo.source return end
    mo.lifetime = $ or 0
    --mo.x = mo.source.x + mo.lifetime * mo.momx
    --mo.y = mo.source.y + mo.lifetime * mo.momy
    --mo.z = mo.source.z + mo.lifetime * mo.momz
	P_TeleportMove(mo, mo.source.x + mo.lifetime * mo.momx, mo.source.y + mo.lifetime * mo.momy, mo.source.z + 17*FRACUNIT + mo.lifetime * mo.momz)
    mo.lifetime = $ + 1
end, MT_ALTSSPARKLES)

//AbilitySpecial Hook which handles super float/homing attack.
addHook("AbilitySpecial", function(player)
	if player.mo and player.mo.skin == "altsonic" and player.charability == CA_THOK
		if not (player.pflags & PF_THOKKED)
			player.pflags = $1 | PF_THOKKED
		end
		if player.althoming == true
		and player.homingdash ~= true
			player.hominglockon = P_LookForEnemies(player, true, true)
			if player.homingdash == false
				player.homingdash = true
				if player.althyper.transforming
				and not player.hominglockon
					player.homingdash = false
				end
				local ghost = P_SpawnGhostMobj(player.mo)
				ghost.scale = FRACUNIT
				ghost.destscale = FRACUNIT*25
				ghost.color = player.mo.color
				ghost.colorized = true
				S_StartSound(player.mo,sfx_ahom)
				if player.mo.eflags & MFE_UNDERWATER
					if player.powers[pw_super]
						P_InstaThrust(player.mo,player.mo.angle,player.normalspeed)
					else
						P_InstaThrust(player.mo,player.mo.angle,player.normalspeed*75/100)
					end
				else
					if player.powers[pw_super]
						P_InstaThrust(player.mo,player.mo.angle,player.normalspeed*2)
					else
						P_InstaThrust(player.mo,player.mo.angle,player.normalspeed)
					end
				end
			end
		end
	end
end)

addHook("PlayerThink",  function(p)
	if p.mo and p.mo.valid
		p.mo.superdashtimer = $ or 0
		if p.mo.skin == "altsonic"
			//Hyper stuff by Frostiikin
			if p.althoming == nil
				p.althoming = 0
			end
			if p.altquakes == nil
				p.altquakes = 0
			end
			if p.powertrails == nil
				p.powertrails = true
			end
			if p.altmusic1 == nil
				p.altmusic1 = true
			end
			if p.altmusic2 == nil
				p.altmusic2 = false
			end
			if p.altmusic3 == nil
				p.altmusic3 = false
			end
			if p.altmusic4 == nil
				p.altmusic4 = false
			end
			if p.altmusic5 == nil
				p.altmusic5 = false
			end
			if p.altmusic6 == nil
				p.altmusic6 = false
			end
			if p.altmusic7 == nil
				p.altmusic7 = false
			end
			if p.althyper == nil
				local althyper = {
				transforming = 0,
				capable = false,
				dashlatch = false,
				atomlatch = false,
				altnuker = 0
				}
				if p.mo
					p.althyper = althyper
				else
					p.althyper = nil
				end
			end
			--if you're capable of going super
			if (p.charflags & SF_SUPER)
				--You need to have 100 rings to go hyper.
				if p.rings >= 100
				and p.powers[pw_super]
				and not p.althyper.transforming
				and not p.mo.iswithcaptive
					p.althyper.capable = true
				end
				--If you haven't collected enough rings, fuck off, you aren't going hyper.
				if p.rings < 100
				and not p.althyper.transforming
					p.althyper.capable = false
				end
				--If you lose all your rings while hyper, you... aren't hyper anymore.
				if not p.powers[pw_super]
					p.althyper.transforming = 0
				end
				--Going hyper will drain your rings twice as fast!
				if (leveltime % 35 == 18) and (p.powers[pw_super] >= 2) and (p.althyper.transforming)
					P_GivePlayerRings(p, -1)
				end
				--If you're super, and elegible for hyper bonuses...
				if (p.powers[pw_super] and p.althyper.transforming)
					--Hyper forms don't need to breathe.
					if (p.mo.eflags & MFE_UNDERWATER)
						p.powers[pw_underwater] = 100*TICRATE
					elseif not (p.powers[pw_super] and p.althyper.transforming)
						p.powers[pw_underwater] = 30*TICRATE
					end
					if P_InSpaceSector(p.mo)
						p.powers[pw_spacetime] = 100*TICRATE
					elseif not (p.powers[pw_super] and p.althyper.transforming)
						p.powers[pw_spacetime] = 11*TICRATE
					end
					--altsonic instantly enters dashmode, and causes screen nukes when he uses the atom dash
					if not p.dashmode
						p.althyper.dashlatch = true
					end
					if p.dashmode >= 3*TICRATE
					and not p.mo.colorized
					and not p.althyper.transforming
						p.mo.colorized = true
					else
						p.mo.colorized = false
					end
					if not p.powers[pw_carry]
						if p.speed > p.normalspeed or p.speed == p.normalspeed then
							p.dashmode = max(p.dashmode, 3*TICRATE)
							if p.althyper.dashlatch == true
								S_StartSound(p.mo, sfx_cdfm40)
							end
							p.althyper.dashlatch = false
						end
					end
					
					--alt nuke shit
					if p.mo.puatomdash == 1
					and not (p.mo.state == S_PLAY_HYPER_TRANS or p.mo.state == S_PLAY_HYPER_TRANSEND)
						if p.althyper.atomlatch == true
							p.althyper.altnuker = 3
							p.althyper.atomlatch = false
						end
					else
						p.althyper.atomlatch = true
					end
					if p.althyper.altnuker == 2
					and not p.althoming
						P_NukeEnemies(p.mo, p.mo, 2048*FRACUNIT)
						if p.altquakes == true
						and p == displayplayer
							P_StartQuake(50*FRACUNIT, 10)
						end
						P_FlashPal(p, PAL_WHITE, 10)
					end
					if p.althyper.altnuker > 0
						p.althyper.altnuker = $ - 1
					end
					--Visuals
					if p.powers[pw_super]
					and p.althyper.transforming
						p.mo.color = (SKINCOLOR_SUPER_HYPER_1 + abs( ( (p.powers[pw_super] >> 1) % 9) - 4))
					end
					local althyperparticle = P_SpawnMobjFromMobj(p.mo, P_RandomRange(-10, 10) * FRACUNIT, P_RandomRange(-10, 10) * FRACUNIT, 20*FRACUNIT, MT_ALTSPARKLES)
						althyperparticle.momx = P_RandomRange(-5, 5) * FRACUNIT
						althyperparticle.momy = P_RandomRange(-5, 5) * FRACUNIT
						althyperparticle.momz =  P_RandomRange(-5, 5) * FRACUNIT
						althyperparticle.color = SKINCOLOR_SILVER
						althyperparticle.scale = p.mo.scale/3*2
						althyperparticle.source = p.mo
						if althyperparticle.source.player == displayplayer
							local chasecam = CV_FindVar("chasecam")
							if (chasecam.value == 1)
								althyperparticle.flags2 = $ & ~MF2_DONTDRAW
							elseif (chasecam.value == 0)
								althyperparticle.flags2 = $ | MF2_DONTDRAW
							end
						end
					end
				end
				if (p.powers[pw_super])
				and not (p.althyper.transforming)
				and not (p.mo.iswithcaptive)
					p.charflags = SF_SUPER
				else
					p.charflags = SF_SUPER|SF_DASHMODE
				end
				if p.powers[pw_super]
					p.powers[pw_invulnerability] = 0
					p.powers[pw_sneakers] = 0
				end
			//Super Dash Stuff.
			if p.mo.speedreached == nil
				p.mo.speedreached = 0
			end
			if p.mo.shoebonus == nil
				p.mo.shoebonus = 0
			end
			if p.homingdash == nil
				p.homingdash = 0
			end
			if p.homingtrailtimer == nil
				p.homingtrailtimer = 0
			end
			if p.homingvar == nil
				p.homingvar = 0
			end
			if p.bonkvar == nil
				p.bonkvar = 0
			end
			if p.bonktimer == nil
				p.bonktimer = 0
			end
			//print (p.althyper.transforming)
			if (p.dashmode)
			and (p.mo.superdashtimer >= 200)
			and not (p.powers[pw_super] and not p.mo.iswithcaptive)
			and not (p.althyper.transforming)
				if leveltime % 5 == 0
					local altsparkle = P_SpawnMobjFromMobj(p.mo, FRACUNIT*P_RandomRange(-16,16), FRACUNIT*P_RandomRange(-16,16), FixedDiv(p.mo.height/2,p.mo.scale)+(P_RandomRange(-16,16)*FRACUNIT), MT_ALTSPARKLES)
					altsparkle.scale = p.mo.scale/3*2
					altsparkle.color = p.mo.color
					altsparkle.colorized = true
					altsparkle.target = p.mo
					if altsparkle.target.player == displayplayer
						local chasecam = CV_FindVar("chasecam")
						if (chasecam.value == 1)
							altsparkle.flags2 = $ & ~MF2_DONTDRAW
						elseif (chasecam.value == 0)
							altsparkle.flags2 = $ | MF2_DONTDRAW
						end
					end
				end
			end
			if (p.mo.previousx == nil) or (p.mo.previousy == nil) or (p.mo.previousz == nil)
				p.mo.previousx = p.mo.x
				p.mo.previousy = p.mo.y
				p.mo.previousz = p.mo.z
			end
			p.mo.previousx = p.mo.x
			p.mo.previousy = p.mo.y
			p.mo.previousz = p.mo.z
			if p.mo.superdashtimer <= 199
			and (p.dashmode >= 3*TICRATE)
			and ((p.speed > 28*FRACUNIT) or (p.mo.state == S_PLAY_SPINDASH))
				p.mo.superdashtimer = $ + 1
			elseif (p.dashmode < 3*TICRATE)
				p.mo.superdashtimer = 0
				p.mo.speedreached = 0
				p.camerascale = FRACUNIT+(1/10)
				p.althyper.dashlatch = true
			end
			if p.mo.speedreached == 0
			and (p.dashmode >= 104)
			and (p.mo.superdashtimer >= 200)
			and not (p.powers[pw_super] and not p.mo.iswithcaptive)
			and not (p.althyper.transforming)
				p.mo.speedreached = 1
				local sdmfx = P_SpawnMobj(p.mo.x, p.mo.y, p.mo.z+p.mo.height/2, MT_ALTSSPARKLES)
				sdmfx.color = p.mo.color
				sdmfx.colorized = true
				sdmfx.scale = p.mo.scale * 7/2
				sdmfx.source = p.mo
				if p.altquakes == true
				and p == displayplayer
					P_StartQuake(16*FRACUNIT,10)
				end
				S_StartSound(p.mo, sfx_cdfm40)
				S_StartSound(p.mo, sfx_sdsh)
				p.camerascale = $+(FRACUNIT*30/100)
			elseif (p.mo.state == S_PLAY_DASH)
			and p.mo.speedreached == 1
			and (p.mo.superdashtimer >= 200)
			and not (p.powers[pw_super])
				p.mo.state = S_PLAY_SUPERDASH
			elseif ((p.mo.superdashtimer == 0) or (P_IsObjectInGoop(p.mo)))
			and p.mo.state == S_PLAY_SUPERDASH
				p.mo.state = S_PLAY_DASH
			elseif (p.dashmode == 0)
				p.mo.speedreached = 0
				p.mo.superdashtimer = 0
			end
			if p.dashmode >= 106
			and p.mo.superdashtimer == 175
			and not p.althyper.transforming
				S_StartSound(p.mo,sfx_s3ka2)
			end
			//Super Dash Mode/Super Form Running Dust.
			if P_IsObjectOnGround(p.mo)
				if (p.mo.speedreached and p.mo.state == S_PLAY_SUPERDASH)
				or ((p.mo.state == S_PLAY_RUN or p.mo.state == S_PLAY_DASH) and p.powers[pw_super])
					DoRunDust(p)
				end
			end
			//Physics.
			if ((p.mo.state == S_PLAY_STND) or (p.mo.state == S_PLAY_WAIT) or (p.mo.state == S_PLAY_WALK) or (p.mo.state == S_PLAY_RUN) or (p.mo.state == S_PLAY_DASH) or (p.mo.state == S_PLAY_SUPERDASH))
				and not (p.mo.eflags & MFE_JUSTHITFLOOR)
				and not (p.mo.state == S_PLAY_ROLL)
				and not (p.powers[pw_carry] == CR_NIGHTSMODE)
				and not (p.secondjump)
				and p.playerstate == PST_LIVE
					if ((p.mo.momz*P_MobjFlip(p.mo)) > 2*FRACUNIT)
					and not (p.mo.eflags & MFE_GOOWATER)
						p.cantrick = true
						p.mo.state = S_PLAY_SPRING
					elseif ((p.mo.momz*P_MobjFlip(p.mo)) < -2*FRACUNIT)
						p.mo.state = S_PLAY_FALL
					end
				end
			//Instaspin.
			if (P_IsObjectOnGround(p.mo) == false) and not (p.powers[pw_carry] == CR_NIGHTSMODE) and (p.panim == PA_SPRING) and (p.cmd.buttons & BT_SPIN)
				S_StartSound(p.mo, sfx_ispn)
				p.pflags = $ + PF_JUMPED
				p.mo.state = S_PLAY_JUMP
			end
			//Give Dash Mode instantly upon entering run state with sneakers.
			if p.powers[pw_sneakers]
				if p.dashmode < 3*TICRATE
					p.mo.shoebonus = true
				end
				if p.speed > p.normalspeed or p.speed == p.normalspeed then
					p.dashmode = max(p.dashmode, 3*TICRATE)
					if p.mo.shoebonus == true
						S_StartSound(p.mo, sfx_cdfm40)
					end
					p.mo.shoebonus = false
				end
			end
			//Hyper coloring stuff.
			if p.powers[pw_super]
			and p.althyper.transforming
				p.mo.color = (SKINCOLOR_SUPER_HYPER_1 + abs( ( (p.powers[pw_super] >> 1) % 9) - 4))
			end
			//All who approach you shall perish.
			if p.powers[pw_super]
			and p.althyper.transforming
				local px = p.mo.x
				local py = p.mo.y
				local br = 100*p.mo.scale
				searchBlockmap("objects", function(mo, found)
					if found and found.valid
					and(abs(mo.z - found.z) <= 200*mo.scale)
					and found.health
						if found.type == MT_CYBRAKDEMON_ELECTRIC_BARRIER --Ruins brak, he's powerless against you!
						or found.type == MT_SPIKE --Endlessly harrass spikes!
						or found.type == MT_WALLSPIKE --Endlessly harrass spikes! X2
						or found.type == MT_WALLSPIKEBASE --Endlessly harrass spikes! X3
						or found.type == MT_EGGSHIELD //lol
							P_KillMobj(found, mo, mo)
						elseif found.type == MT_METALSONIC_BATTLE
						and found.state == S_METALSONIC_FLOAT
							found.flags2 = $ | MF2_CLASSICPUSH --Endlessly harrass metal sonic too!
						elseif found.flags & MF_BOSS|MF_SHOOTABLE|MF_ENEMY --Punch bosses and other objects!
						and not (found.flags & MF_MONITOR)
							found.badnikpop = true
							P_DamageMobj(found, mo, mo, 2)
						end--This kills the things
					end
				end, p.mo, px-br, px+br, py-br, py+br)
			end
			//Homing attack. Why is it here, you ask? Blame order of operations.
			if p.althoming == true
			and p.playerstate != PST_DEAD
				//*Bonk*
				if p.homingvar
				and p.bonkvar == false
				and not (p.pflags & PF_SHIELDABILITY)
				and not P_PlayerInPain(p)
				and FixedHypot(FixedHypot(p.mo.momx, p.mo.momy), p.mo.momz) < FixedMul(p.normalspeed, p.mo.scale) >> 2
					p.bonktimer = 2
					p.bonkvar = true
					p.homingdash = false
					p.hominglockon = nil
					P_InstaThrust(p.mo, p.mo.angle, -FixedMul(p.normalspeed >> 4, p.mo.scale))
					P_SetObjectMomZ(p.mo, p.normalspeed >> 4, false)
					if p.mo.eflags & MFE_UNDERWATER
						p.mo.momz = $ / 2
					end
					S_StartSound(p.mo, sfx_s3k49)
					p.homingvar = false
				end
				//Normal Stuff.
				if p.playerstate != PST_DEAD
					p.homingreticle = P_LookForEnemies(p, true, true)
				end
				if p.bonktimer > 0
					p.bonktimer = $ - 1
				end
				if p.bonktimer == 0
					p.bonkvar = false
				end
				if p.homingvar
				and P_PlayerInPain(p)
					p.bonkvar = true
				end
				if p.homingreticle and p.homingreticle.valid
				and p.althoming == true
				and not p.homingdash
				and not (p.homingreticle.flags2 & MF2_FRET)
				and p.homingreticle.type ~= MT_BIGMINE
				and p.homingreticle.type ~= MT_EGGSHIELD
				and p.homingreticle.type ~= MT_TNTBARREL
				and p.homingreticle.type ~= MT_DETON
				and p.homingreticle.type ~= MT_FAKEMOBILE 
				and p.pflags & PF_JUMPED
				and not (P_IsObjectOnGround(p.mo))
					P_SpawnLockOn(p, p.homingreticle, S_LOCKON1)
				end
				if (p.pflags & PF_THOKKED)
				and (p.pflags & PF_JUMPED)
					if p.hominglockon and p.hominglockon.valid
					and not (p.hominglockon.flags2 & MF2_FRET)
					and not (p.mo.eflags & MFE_SPRUNG)
					and p.hominglockon.type ~= MT_BIGMINE
					and p.hominglockon.type ~= MT_EGGSHIELD
					and p.hominglockon.type ~= MT_TNTBARREL
					and p.hominglockon.type ~= MT_DETON
					and p.hominglockon.type ~= MT_FAKEMOBILE 
					and p.bonkvar == false
						p.homingvar = true
						if p.homingvar == true
							P_HomingAttack(p.mo, p.hominglockon)
							local zdist = (P_MobjFlip(p.mo) == 1) and (p.hominglockon.z + p.hominglockon.height) - (p.mo.z + p.mo.height) or (p.hominglockon.z - p.mo.z) //variables for distance and stuff!
							local dist = P_AproxDistance(P_AproxDistance(p.hominglockon.x - p.mo.x, p.hominglockon.y - p.mo.y), zdist)
							if p.powers[pw_super]
							or p.powers[pw_sneakers]
								p.mo.momx = FixedMul(FixedDiv(p.hominglockon.x - p.mo.x, dist), p.normalspeed + 10*FRACUNIT * 4)
								p.mo.momy = FixedMul(FixedDiv(p.hominglockon.y - p.mo.y, dist), p.normalspeed + 10*FRACUNIT * 4)
								p.mo.momz = FixedMul(FixedDiv(zdist, dist), p.normalspeed + 10*FRACUNIT * 4)
							else
								p.mo.momx = FixedMul(FixedDiv(p.hominglockon.x - p.mo.x, dist), p.normalspeed + 10*FRACUNIT)
								p.mo.momy = FixedMul(FixedDiv(p.hominglockon.y - p.mo.y, dist), p.normalspeed + 10*FRACUNIT)
								p.mo.momz = FixedMul(FixedDiv(zdist, dist), p.normalspeed + 10*FRACUNIT)
							end
						end
					end
				end
				if (p.powers[pw_carry] == CR_PLAYER)
				or (p.powers[pw_carry] == CR_ROPEHANG)
				or (p.powers[pw_carry] == CR_MACESPIN)
				or (p.powers[pw_carry] == CR_DUSTDEVIL)
				or (p.mo.eflags & MFE_SPRUNG)
				or (p.mo.eflags & MFE_JUSTHITFLOOR)
				or (P_IsObjectOnGround(p.mo))
				or p.exiting
					p.homingdash = false
					p.hominglockon = nil
					p.homingvar = false
					p.bonkvar = false
				end
			end
			//New Hyper Form Trigger.
			if p.cmd.buttons & BT_CUSTOM3
			and p.powers[pw_super] >= 3
			and (p.althyper.capable == true)
			and not p.althyper.transforming
			and p.pflags & PF_JUMPED
				p.althyper.transforming = 1
				S_StartSound(nil, sfx_hypert)
			end
			//Transformation.
			local e = {1, 8, 11, 13, 15, 17}
			if p.althyper.transforming
			and p.althyper.transforming < TICRATE
				p.mo.momx = 0
				p.mo.momy = 0
				p.mo.momz = 0
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.chargecancel = true
				p.homingdash = true
				p.hominglockon = nil
				if p.althyper.transforming < e[#e]
					for i = 1, #e-1
						if p.althyper.transforming == e[i]
							p.mo.state = S_PLAY_HYPER_TRANS
						end
					end
				elseif p.althyper.transforming == e[#e]
					p.mo.state = S_PLAY_HYPER_TRANSEND
					p.mo.frame = 6|FF_FULLBRIGHT
					//print("e")
				end
				p.althyper.transforming = $ + 1
			end
			//Makes it so an Attraction Shield's homing attack can't be used if 'legacymode' is on. Bless SF_NOSHIELDABILITY.
			if p.althoming
				if p.powers[pw_shield] & SH_NOSTACK == SH_ATTRACT
					p.charflags = $ | SF_NOSHIELDABILITY
				else
					p.charflags = $ & ~SF_NOSHIELDABILITY
				end
			end
			//Atom Dash.
			//Giant piece of code.
			//Defining the variables. Let's begin.
			if p.althoming == true return end
			if p.mo.altsonicvar == nil
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.chargecancel = 0
				p.mo.chargefalling = 0
				p.mo.chargesound = 0
				p.mo.atomdash = 0
				p.mo.puatomdash = 0
				p.mo.atomdashc1 = 0
				p.mo.atomdashc2 = 0
				p.mo.atomdashc3 = 0
				p.mo.atomdashpc1 = 0
				p.mo.atomdashpc2 = 0
				p.mo.atomdashpc3 = 0
				p.mo.altsonicvar = true
			end
			//Atom charge with Dash mode/Super
			if (p.pflags & PF_THOKKED)
			and (p.pflags & PF_JUMPED)
			and (p.pflags & PF_JUMPDOWN)
			and not (p.pflags & PF_SHIELDABILITY)
			and not (p.powers[pw_carry])
			and not (p.mo.state == S_PLAY_SPRING)
			and p.mo.chargecancel == false
			and p.mo.puatomdash == 0
			and not (p.mo.puatomdashtimer >= 96)
			and not (P_PlayerInPain(p))
			and not (p.mo.eflags & MFE_JUSTHITFLOOR)
			and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super] >= 2))
			and not (p.powers[pw_super] == 1)
			and not p.exiting
			and p.playerstate == PST_LIVE
				p.dashmode = $
				p.mo.puatomdashtimer = $ + 1
				p.mo.state = S_PLAY_JUMP
				p.mo.momx = FixedMul($, FRACUNIT*88/100)
				p.mo.momy = FixedMul($, FRACUNIT*88/100)
				p.mo.momz = 0
			//Atom charge
			elseif (p.pflags & PF_THOKKED)
			and (p.pflags & PF_JUMPED)
			and (p.pflags & PF_JUMPDOWN)
			and not (p.pflags & PF_SHIELDABILITY)
			and not (p.powers[pw_carry])
			and not (p.mo.state == S_PLAY_SPRING)
			and p.mo.chargecancel == false
			and p.mo.atomdash == 0
			and not (p.mo.atomdashtimer >= 115)
			and not (P_PlayerInPain(p))
			and not (p.mo.eflags & MFE_JUSTHITFLOOR)
			and not ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super] == 1))
			and not p.exiting
			and p.playerstate == PST_LIVE
				p.mo.atomdashtimer = $ + 1
				p.mo.state = S_PLAY_JUMP
				p.mo.momx = FixedMul($, FRACUNIT*88/100)
				p.mo.momy = FixedMul($, FRACUNIT*88/100)
				p.mo.momz = 0
			//Super?
			elseif (p.powers[pw_super] == 1)
			and (p.mo.atomdashtimer >= 1)
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.chargecancel = true
				p.mo.chargefalling = true
				p.mo.state = S_PLAY_SUPER_TRANS1
				p.mo.frame = B
			//Resetting variables after all possible cases, along with carry/spring/landing stuff.
			elseif (p.powers[pw_carry] == CR_PLAYER)
			or (p.powers[pw_carry] == CR_ROPEHANG)
			or (p.powers[pw_carry] == CR_MACESPIN)
			or (p.powers[pw_carry] == CR_DUSTDEVIL)
			or (p.mo.eflags & MFE_SPRUNG)
			or (p.mo.eflags & MFE_JUSTHITFLOOR)
			or (P_IsObjectOnGround(p.mo))
			or p.exiting
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.atomdash = 0
				p.mo.puatomdash = 0
				p.mo.chargecancel = false
				p.mo.chargefalling = false
				p.mo.chargesound = 0
			end
			//Atom charge beginning sound cue
			if (p.pflags & PF_THOKKED)
			and (p.mo.atomdashtimer >= 1 or p.mo.puatomdashtimer >= 1)
			and p.mo.chargesound == 0
				S_StartSound(p.mo, sfx_astp)
				p.mo.chargesound = 1
			end
			//Sound/Visual cues for each level
			//Dash mode/Super
			if (p.pflags & PF_THOKKED)
			and (p.pflags & PF_JUMPED)
			and (p.playerstate == PST_LIVE)
				if p.mo.puatomdash == 0
				and p.mo.atomdash == 0
					if (p.mo.puatomdashtimer == 26) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) and not (p.mo.eflags & MFE_JUSTHITFLOOR) then
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-16,16),nil,1)
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-24,24),nil,1)
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-32,32),nil,1)
						S_StartSound(p.mo,sfx_chrg)
					elseif (p.mo.puatomdashtimer == 13) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) and not (p.mo.eflags & MFE_JUSTHITFLOOR) then
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-16,16),nil,1)
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-24,24),nil,1)
						S_StartSound(p.mo,sfx_atwn)
					elseif (p.mo.puatomdashtimer == 1) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) and not (p.mo.eflags & MFE_JUSTHITFLOOR) then
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-16,16),nil,1)
						S_StartSound(p.mo,sfx_atwn)
					else
						p.mo.puatomdash = 0
					end
				end
				//No dash mode or Super
				if p.mo.atomdash == 0
				and p.mo.puatomdash == 0
					if (p.mo.atomdashtimer == 45) and not ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) and not (p.mo.eflags & MFE_JUSTHITFLOOR) then
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-16,16),nil,1)
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-24,24),nil,1)
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-32,32),nil,1)
						S_StartSound(p.mo,sfx_chrg)
					elseif (p.mo.atomdashtimer == 30) and not ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) and not (p.mo.eflags & MFE_JUSTHITFLOOR) then
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-16,16),nil,1)
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-24,24),nil,1)
						S_StartSound(p.mo,sfx_atwn)
					elseif (p.mo.atomdashtimer == 15) and not ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) and not (p.mo.eflags & MFE_JUSTHITFLOOR) then
						P_SpawnParaloop(p.mo.x,p.mo.y,p.mo.z+p.mo.height/2,256*p.mo.scale,16,MT_NIGHTSPARKLE,p.mo.angle*P_RandomRange(-16,16),nil,1)
						S_StartSound(p.mo,sfx_atwn)
					else
						p.mo.atomdash = 0
					end
				end
			end
			//Overcharge including Dash mode/Super
			if (p.pflags & PF_THOKKED)
			and not (p.powers[pw_carry] == CR_PLAYER)
			and not (p.powers[pw_carry] == CR_ROPEHANG)
			and not (p.powers[pw_carry] == CR_MACESPIN)
			and not (p.mo.state == S_PLAY_SPRING)
			and not (p.mo.eflags & MFE_JUSTHITFLOOR)
			and p.mo.chargefalling == false
			and (p.mo.puatomdashtimer >= 96)
			and not (p.pflags & PF_SHIELDABILITY)
			and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super]))
			and not p.althyper.transforming
				S_StartSound(p.mo,sfx_s3k51)
				p.dashmode = 0
				p.pflags = $ & ~PF_SPINNING
				p.pflags = $ & ~PF_JUMPED
				p.pflags = $1|PF_NOJUMPDAMAGE
				p.mo.state = S_PLAY_FALL
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.chargecancel = true
				p.mo.chargefalling = true
				p.mo.momy = 0
				p.mo.momx = 0
				p.mo.momz = 0
			elseif (p.pflags & PF_THOKKED)
			and not (p.powers[pw_carry] == CR_PLAYER)
			and not (p.powers[pw_carry] == CR_ROPEHANG)
			and not (p.powers[pw_carry] == CR_MACESPIN)
			and not (p.mo.state == S_PLAY_SPRING)
			and not (p.mo.eflags & MFE_JUSTHITFLOOR)
			and p.mo.chargefalling == false
			and (p.mo.puatomdashtimer >= 96)
			and not (p.pflags & PF_SHIELDABILITY)
			and p.althyper.transforming
				S_StartSound(p.mo,sfx_s3k51)
				p.pflags = $ & ~PF_SPINNING
				p.pflags = $ & ~PF_JUMPED
				p.pflags = $1|PF_NOJUMPDAMAGE
				p.mo.state = S_PLAY_FALL
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.chargecancel = true
				p.mo.chargefalling = true
				p.mo.momy = 0
				p.mo.momx = 0
				p.mo.momz = 0
			end
			//Overcharge
			if (p.pflags & PF_THOKKED)
			and not (p.powers[pw_carry] == CR_PLAYER)
			and not (p.powers[pw_carry] == CR_ROPEHANG)
			and not (p.powers[pw_carry] == CR_MACESPIN)
			and not (p.mo.state == S_PLAY_SPRING)
			and not (p.mo.eflags & MFE_JUSTHITFLOOR)
			and p.mo.chargefalling == false
			and (p.mo.atomdashtimer >= 115)
			and not (p.pflags & PF_SHIELDABILITY)
				S_StartSound(p.mo,sfx_s3k51)
				p.pflags = $ & ~PF_SPINNING
				p.pflags = $ & ~PF_JUMPED
				p.pflags = $1|PF_NOJUMPDAMAGE
				p.mo.state = S_PLAY_FALL
				p.mo.atomdashtimer = 0
				p.mo.puatomdashtimer = 0
				p.mo.chargecancel = true
				p.mo.chargefalling = true
				p.mo.momy = 0
				p.mo.momx = 0
				p.mo.momz = 0
			end
			//Level 3, ?
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.puatomdashtimer >= 26) and ((p.powers[pw_super]) and (p.althyper.transforming)) and p.mo.puatomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*4)
					S_StartSound(p.mo,sfx_adsh)
					S_StartSound(p.mo,sfx_abom)
					P_SpawnThokMobj(p)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.puatomdash = 1
				else
					p.mo.puatomdash = 0
				end
			end
			//Level 3, Dash mode/Super
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) then
				if (p.mo.puatomdashtimer >= 26) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and p.mo.puatomdash == 0 then
					if not p.isxmomentum --and not p.althyper.transforming	
						if (p.powers[pw_super])
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*4)
						else
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*2)
						end
					else
						if (p.powers[pw_super])
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*70/100*8)
						else
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*70/100*4)
						end
					end
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_adsh)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.puatomdash = 1
				else
					p.mo.puatomdash = 0
				end
			end
			//Level 3, No Dash mode or Super
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.atomdashtimer >= 45) and p.mo.atomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*2)
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_adsh)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.atomdash = 1
				else
					p.mo.atomdash = 0
				end
			end
			//Level 2, ?
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.puatomdashtimer >= 13) and ((p.powers[pw_super]) and (p.althyper.transforming)) and p.mo.puatomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*3)
					S_StartSound(p.mo,sfx_adsh)
					S_StartSound(p.mo,sfx_abom)
					P_SpawnThokMobj(p)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.puatomdash = 1
				else
					p.mo.puatomdash = 0
				end
			end
			//Level 2, Dash mode/Super
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) then
				if (p.mo.puatomdashtimer >= 13) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and p.mo.puatomdash == 0 then
					if not p.isxmomentum
						if (p.powers[pw_super])
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*3)
						else
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*3/2)
						end
					else
						if (p.powers[pw_super])
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*70/100*3)
						else
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*70/100*3/2)
						end
					end
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_adsh)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.puatomdash = 1
				else
					p.mo.puatomdash = 0
				end
			end
			//Level 2, No Dash mode or Super
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.atomdashtimer >= 30) and p.mo.atomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*3/2)
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_adsh)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.atomdash = 1
				else
					p.mo.atomdash = 0
				end
			end
			//Level 1, ?
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.puatomdashtimer >= 1) and ((p.powers[pw_super]) and (p.althyper.transforming)) and p.mo.puatomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*2)
					S_StartSound(p.mo,sfx_adsh)
					S_StartSound(p.mo,sfx_abom)
					P_SpawnThokMobj(p)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.puatomdash = 1
				else
					p.mo.puatomdash = 0
				end
			end
			//Level 1, Dash mode/Super
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and not (P_PlayerInPain(p)) then
				if (p.mo.puatomdashtimer >= 1) and ((p.dashmode >= 3*TICRATE) or (p.powers[pw_super])) and p.mo.puatomdash == 0 then
					if not p.isxmomentum
						if (p.powers[pw_super])
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed * 2)
						else
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed)
						end
					else
						if (p.powers[pw_super])
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*70/100 * 2)
						else
							P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*70/100)
						end
					end
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_adsh)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.puatomdash = 1
				else
					p.mo.puatomdash = 0
				end
			end
			//Level 1, No Dash mode or Super
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.atomdashtimer >= 15) and p.mo.atomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed)
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_adsh)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.atomdash = 1
				else
					p.mo.atomdash = 0
				end
			end
			//Level 0?
			if not (p.pflags & PF_JUMPDOWN or p.mo.chargecancel) and not (P_PlayerInPain(p)) then
				if (p.mo.atomdashtimer != 0) and (p.mo.atomdashtimer <= 14) and p.mo.atomdash == 0 then
					P_InstaThrust(p.mo, p.mo.angle, p.normalspeed*65/100)
					P_SpawnThokMobj(p)
					S_StartSound(p.mo,sfx_cdfm35)
					p.mo.state = S_PLAY_JUMP
					p.mo.chargecancel = true
					p.mo.atomdash = 1
				else
					p.mo.atomdash = 0
				end
			end
		end
		if p.mo and p.mo.valid and p.mo.skin != "altsonic"
		and p.althyper
		and p.althyper.transforming
			p.althyper.transforming = 0
		end
	end
end)

local function setReboundMomZ(mobj, bullet, mo)
	local orientation = 1
	
	if mobj and mobj.valid
	and mo and mo.valid
	
		if mo.althoming == false return end
		
		if (mo.eflags & MFE_VERTICALFLIP)
			orientation = -1
		else
			orientation = 1
		end

		if mo.skin == "altsonic"
		and mo.player.hominglockon
		and mobj.flags & (MF_ENEMY|MF_MONITOR|MF_BOSS)
		and mo.player.homingvar == true
			mo.player.homingdash = false
			mo.player.homingvar = false
			mo.player.pflags = $ & ~PF_THOKKED
			local buttons = mo.player.cmd.buttons //shortening this
			local speed = mo.player.speed
			if not (buttons & BT_JUMP)
				P_InstaThrust(mo,mo.angle,0)
				mo.momz = (25/2)*FRACUNIT*orientation
			else
				mo.momz = 10*FRACUNIT*orientation
				local altshockwave = P_SpawnMobjFromMobj(mo,0,0,10*FRACUNIT,MT_ALTSHOCKWAVE)
				altshockwave.color = mo.color
				altshockwave.angle = R_PointToAngle2(mo.x, mo.y, (mo.x+mo.momx), (mo.y+mo.momy)) + ANGLE_90
				S_StartSound(mo,sfx_s23c)
			end
		end
	end
end

addHook("MobjDeath", setReboundMomZ)
addHook("MobjDamage", setReboundMomZ)

addHook("ShieldSpecial", function(player)
	for player in players.iterate do
		if player and player.valid and player.mo.skin == "altsonic"
			if player.powers[pw_shield] == SH_WHIRLWIND
			or player.powers[pw_shield] == SH_ARMAGEDDON
			or player.powers[pw_shield] == SH_ATTRACT
			or player.powers[pw_shield] == SH_ELEMENTAL
			or player.powers[pw_shield] & SH_FORCE
			or player.powers[pw_shield] == SH_FLAMEAURA
			or player.powers[pw_shield] == SH_BUBBLEWRAP
			or player.powers[pw_shield] == SH_THUNDERCOIN
				player.mo.atomdashtimer = 0
				player.mo.puatomdashtimer = 0
				player.mo.chargecancel = true
				player.mo.atomdash = 1
				player.mo.puatomdash = 1
				player.homingdash = 1
				player.hominglockon = 0
			end
		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}

addHook("ThinkFrame", do
	for player in players.iterate do
		if player.mo and player.mo.valid and player.mo.skin == "altsonic"
			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.althyper.transforming
			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
			if not player.althyper.transforming -- Super Dash Mode ghosts. Because PlayerThink ghost spawning is stinky.
				if player.dashmode >= 106 -- For real though, why is there a difference.
				and player.mo.superdashtimer >= 175
				and not (player.mo.superdashtimer >= 200)
				and leveltime % 4 == 0
					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 = 2
					ghost1.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS60
					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
					local ghost2 = P_SpawnGhostMobj(player.mo)
					ghost2.color = player.mo.color
					if player.mo.colorized
						ghost2.colorized = true
					else
						ghost2.colorized = false
					end
					ghost2.rollangle = player.mo.rollangle
					ghost2.fuse = 3
					ghost2.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS50
					ghost2.eflags = player.mo.eflags & MFE_VERTICALFLIP
					ghost2.source = player.mo
					if ghost2.source.player == displayplayer
						local chasecam = CV_FindVar("chasecam")
						if (chasecam.value == 1)
							ghost2.flags2 = $ & ~MF2_DONTDRAW
						elseif (chasecam.value == 0)
							ghost2.flags2 = $ | MF2_DONTDRAW
						end
					end
					local ghost3 = P_SpawnGhostMobj(player.mo)
					ghost3.color = player.mo.color
					if player.mo.colorized
						ghost3.colorized = true
					else
						ghost3.colorized = false
					end
					ghost3.rollangle = player.mo.rollangle
					ghost3.fuse = 4
					ghost3.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS40
					ghost3.eflags = player.mo.eflags & MFE_VERTICALFLIP
					ghost3.source = player.mo
					if ghost3.source.player == displayplayer
						local chasecam = CV_FindVar("chasecam")
						if (chasecam.value == 1)
							ghost3.flags2 = $ & ~MF2_DONTDRAW
						elseif (chasecam.value == 0)
							ghost3.flags2 = $ | MF2_DONTDRAW
						end
					end
				end
				if player.mo.superdashtimer >= 200
					if player.powertrails
					and powertrailss
						SpawnTrail(player)
					else
						local ghost1 = P_SpawnGhostMobj(player.mo)
						ghost1.color = player.mo.color
						ghost1.colorized = true
						ghost1.rollangle = player.mo.rollangle
						ghost1.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS60|FF_FULLBRIGHT
						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
					local ghost1 = P_SpawnGhostMobj(player.mo)
					ghost1.color = player.mo.color
					ghost1.colorized = true
					ghost1.rollangle = player.mo.rollangle
					ghost1.fuse = 1
					ghost1.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS60|FF_FULLBRIGHT
					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
					local ghost2 = P_SpawnGhostMobj(player.mo)
					ghost2.color = player.mo.color
					ghost2.colorized = true
					ghost2.rollangle = player.mo.rollangle
					ghost2.fuse = 1
					ghost2.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS50|FF_FULLBRIGHT
					ghost2.eflags = player.mo.eflags & MFE_VERTICALFLIP
					ghost2.source = player.mo
					if ghost2.source.player == displayplayer
						local chasecam = CV_FindVar("chasecam")
						if (chasecam.value == 1)
							ghost2.flags2 = $ & ~MF2_DONTDRAW
						elseif (chasecam.value == 0)
							ghost2.flags2 = $ | MF2_DONTDRAW
						end
					end
					local ghost3 = P_SpawnGhostMobj(player.mo)
					ghost3.color = player.mo.color
					if player.mo.colorized
						ghost3.colorized = true
					else
						ghost3.colorized = false
					end
					ghost3.rollangle = player.mo.rollangle
					ghost3.fuse = 1
					ghost3.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS40|FF_FULLBRIGHT
					ghost3.eflags = player.mo.eflags & MFE_VERTICALFLIP
					ghost3.source = player.mo
					if ghost3.source.player == displayplayer
						local chasecam = CV_FindVar("chasecam")
						if (chasecam.value == 1)
							ghost3.flags2 = $ & ~MF2_DONTDRAW
						elseif (chasecam.value == 0)
							ghost3.flags2 = $ | MF2_DONTDRAW
						end
					end
				end
			end
			if player.powers[pw_super]
			and player.althyper.transforming
			and player.dashmode >= 3*TICRATE
				if player.powertrails
				and powertrailss
					SpawnTrail(player)
				else
					local ghost1 = P_SpawnGhostMobj(player.mo)
					ghost1.color = player.mo.color
					ghost1.colorized = true
					ghost1.rollangle = player.mo.rollangle
					ghost1.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS60|FF_FULLBRIGHT
					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
			end
			local ang = FixedAngle(FU*360/35)*leveltime
			local bajablast = FixedMul(player.mo.radius*2, sin(FixedAngle(FU*360/70)*leveltime))
			if player.mo.superdashtimer >= 200
			or player.althyper.transforming
				for j = 0, 1
					local h = j and 1 or -1
					for i = 0, 7
						local fuck = P_SpawnMobjFromMobj(player.mo, 
						(bajablast/FU)*cos((ang+(i*ANGLE_45))+player.drawangle),
						(bajablast/FU)*sin((ang+(i*ANGLE_45))+player.drawangle),
						(17*sin(ang+(i*ANGLE_45))*h)+(player.mo.height/2),
						MT_ALTSPARKLES
						)
						fuck.frame = abs(sin(FixedAngle(FU*360/TICRATE)*leveltime)*4/FU)|FF_FULLBRIGHT
						fuck.fuse = 1
						fuck.origin = player.mo
						if fuck.origin.player == displayplayer
							local chasecam = CV_FindVar("chasecam")
							if (chasecam.value == 1)
								fuck.flags2 = $ & ~MF2_DONTDRAW
							elseif (chasecam.value == 0)
								fuck.flags2 = $ | MF2_DONTDRAW
							end
						end
						if player.althyper.transforming
							fuck.color = (SKINCOLOR_SUPER_HYPER_1 + abs( ( (player.powers[pw_super] >> 1) % 9) - 4))
						else
							fuck.color = player.mo.color
						end
						fuck.colorized = true
						fuck.sussy = player.mo -- I'm going to kill whoever named this variable 'sussy'
						if fuck.sussy == displayplayer
							local chasecam = CV_FindVar("chasecam")
							if (chasecam.value == 1)
								fuck.flags2 = $ & ~MF2_DONTDRAW
							elseif (chasecam.value == 0)
								fuck.flags2 = $ | MF2_DONTDRAW
							end
						end
						local fuckghost = P_SpawnGhostMobj(fuck)
						fuckghost.flags2 = fuck.flags2
						//lach was here
						if j
							local hDist = FixedMul(bajablast, cos(ang+(i*ANGLE_45)))
							local xDist = P_ReturnThrustX(nil, player.drawangle, hDist)
							local yDist = P_ReturnThrustY(nil, player.drawangle, hDist)
							local zDist = FixedMul(bajablast, sin(ang+(i*ANGLE_45))) + FixedDiv(player.mo.height/2, player.mo.scale)
							local spark2 = P_SpawnMobjFromMobj(player.mo, xDist, yDist, zDist, MT_ALTSPARKLES)
							spark2.frame = abs(sin(FixedAngle(FU*360/TICRATE)*leveltime)*4/FU)|FF_FULLBRIGHT
							spark2.fuse = 1
							spark2.color = player.mo.color
							spark2.colorized = true
							spark2.origin = player.mo
							if spark2.origin.player == displayplayer
								local chasecam = CV_FindVar("chasecam")
								if (chasecam.value == 1)
									spark2.flags2 = $ & ~MF2_DONTDRAW
								elseif (chasecam.value == 0)
									spark2.flags2 = $ | MF2_DONTDRAW
								end
							end
							local fuckghost = P_SpawnGhostMobj(spark2)
							fuckghost.flags2 = spark2.flags2
						end
					end
				end
			end
		end
	end
end)

//Just wanna quickly mention that without SMS Alfredo's help this code would still be a mess.
addHook("PlayerCanDamage", function(player, mobj)
	if player.mo and player.mo.valid and player.mo.skin == "altsonic"
		if player.dashmode >= 3*TICRATE
		and player.mo.speedreached == 1
		and player.mo.superdashtimer >= 200
		or player.powers[pw_super]
			return true
		end
	end
end)

//This too.
addHook("ShouldDamage", function(target, inflictor, source, damage, damagetype)
    if target and target.valid and target.skin == "altsonic"
    and (target.player.dashmode >= 3*TICRATE)
    and (target.speedreached == 1)
	and (target.superdashtimer >= 200)
    and not (damagetype & DMG_DEATHMASK)
        return false
    end
end, MT_PLAYER)
	
//Credit to SMS Alfredo for the simple wallbreaker script. Without him it'd be a jumbled mess of inconsistent math :)
local superdashbuster = function(mobj, sectorthing)
	local sus = false
	for fof in sectorthing.ffloors()
		if fof.valid and (fof.flags & FF_BUSTUP) and (fof.flags & FF_EXISTS)
		and fof.topheight >= mobj.z+mobj.height and fof.bottomheight <= mobj.z
			EV_CrumbleChain(sectorthing, fof)
			sus = true
		end
	end
	return sus
end

addHook("MobjLineCollide", function(mobj, line)
	if mobj and mobj.valid and mobj.skin == "altsonic"
		if not ((mobj.player.dashmode >= 3*TICRATE and mobj.speedreached == 1 and mobj.superdashtimer >= 200) or (mobj.player.powers[pw_super])) return end
		local killone
		local killtwo
		if not (line and line.valid and mobj and mobj.valid) then return end
		if line.frontsector and line.frontsector.valid then killone = superdashbuster(mobj, line.frontsector) end
		if line.backsector and line.backsector.valid then killtwo = superdashbuster(mobj, line.backsector) end
	end
end, MT_PLAYER)
	
addHook("SpinSpecial", function(p)
    if p.mo.skin == "altsonic"
    and not p.exiting
    and not (P_PlayerInPain(p))
    and not (p.pflags & PF_SLIDING)
    and not (p.powers[pw_carry] == CR_NIGHTSMODE)
        if (p.speed > 5*FRACUNIT and p.pflags & PF_STARTDASH) then return true end
        if p.powers[pw_super]
        or p.mo.speedreached == 1
            //print("hi")
            p.mindash = 80*FRACUNIT
            p.maxdash = 110*FRACUNIT
        else
            p.mindash = 50*FRACUNIT
            p.maxdash = 80*FRACUNIT
        end

        if P_IsObjectOnGround(p.mo)
        and p.mo.state != S_PLAY_SPINDASH 
        and p.charability2 == CA2_SPINDASH
        and not (p.pflags & (PF_SPINDOWN|PF_SPINNING)) 
        and not (p.mo.eflags & MFE_SPRUNG) then
        
            p.mo.momy = p.mo.momy*3/10
            p.mo.momx = p.mo.momx*3/10
            p.dashspeed = p.mindash
            p.mo.state = S_PLAY_SPINDASH
            p.pflags = $ | (PF_SPINDOWN|PF_STARTDASH|PF_SPINNING)
            S_StartSound(p.mo, sfx_spndsh)
            return true
        end
        if P_IsObjectOnGround(p.mo)
        and p.pflags & PF_SPINNING 
        and p.mo.state == S_PLAY_ROLL 
        and not (p.pflags & (PF_SPINDOWN|PF_STARTDASH)) then
            p.mo.state = S_PLAY_RUN
            p.pflags = ($ & ~PF_SPINNING) | PF_SPINDOWN
            return true
        end
		if not P_IsObjectOnGround(p.mo)
		and p.mo.state == S_PLAY_SPINDASH
		and not (p.powers[pw_carry] == CR_NIGHTSMODE) then
			p.pflags = $ |(PF_SPINNING|PF_DRILLING)
			p.mo.state = S_PLAY_ROLL
		end
    end
end)
			
addHook("SpinSpecial", function(p)
	 if p.mo.skin == "altsonic"
	 and not p.exiting
	 and not (P_PlayerInPain(p))
	 and not (p.pflags & PF_SLIDING)
	 and not (p.powers[pw_carry] == CR_NIGHTSMODE)
	 if p.mo.state == S_PLAY_SPINDASH
	 and p.mo.eflags & MFE_SPRUNG
		p.pflags = $ | PF_SPINNING
		p.mo.state = S_PLAY_ROLL
		end
	end
end)

addHook("MobjCollide", function(spike, plmo)
    if not (plmo and plmo.valid and plmo.skin == "altsonic") then return end
    if plmo.type ~= MT_PLAYER then return end
    if plmo.z + plmo.height < spike.z or spike.z + spike.height < plmo.z then return end
    local player = plmo.player
    if player.dashmode >= 3*TICRATE
	or player.powers[pw_super] then
        P_KillMobj(spike, plmo, plmo)
    end
end, MT_SPIKE)

addHook("MobjCollide", function(spike, plmo)
    if not (plmo and plmo.valid and plmo.skin == "altsonic") then return end
    if plmo.type ~= MT_PLAYER then return end
    if (plmo.z > spike.z+spike.height*4) or (spike.z > plmo.z+plmo.height*2) then return end
    local player = plmo.player
	if player.dashmode >= 3*TICRATE
	or player.powers[pw_super] then
        P_KillMobj(spike, plmo, plmo)
    end
end, MT_WALLSPIKE)

addHook("PlayerSpawn", function(p)
	if io and p == consoleplayer and p.althoming == nil and p.altquakes == nil
		local file = io.openlocal("client/altsonic/legacymode.dat")
		if file
			local string = file:read("*a")
			if string == "1" or string == "true" or string == "on"
				COM_BufInsertText(p, "legacymode on")
			elseif string == "0" or string == "false" or string == "off" or string == nil
				COM_BufInsertText(p, "legacymode off")
			end
			file:close()
		end
		local file = io.openlocal("client/altsonic/altquakes.dat")
		if file
			local string = file:read("*a")
			if string == "1" or string == "true" or string == "on" or string == nil
				COM_BufInsertText(p, "altquakes on")
			elseif string == "0" or string == "false" or string == "off"
				COM_BufInsertText(p, "altquakes off")
			end
			file:close()
		end
		local file = io.openlocal("client/altsonic/powertrails.dat")
		if file
			local string = file:read("*a")
			if string == "1" or string == "true" or string == "on" or string == nil
				COM_BufInsertText(p, "powertrails on")
			elseif string == "0" or string == "false" or string == "off"
				COM_BufInsertText(p, "powertrails off")
			end
			file:close()
		end
		local file = io.openlocal("client/altsonic/altmusic.dat")
		if file
			local string = file:read("*a")
			if string == "default" or string == "speedy"
				COM_BufInsertText(p, "hypermusic speedy")
			elseif string == "adventurous"
				COM_BufInsertText(p, "hypermusic adventurous")
			elseif string == "boundless"
				COM_BufInsertText(p, "hypermusic boundless")
			elseif string == "olympic"
				COM_BufInsertText(p, "hypermusic olympic")
			elseif string == "nights"
				COM_BufInsertText(p, "hypermusic nights")
			elseif string == "radiant"
				COM_BufInsertText(p, "hypermusic radiant")
			elseif string == "unstoppable"
				COM_BufInsertText(p, "hypermusic unstoppable")
			end
			file:close()
		end
	end
end)

addHook("MobjMoveCollide", function(h, v)
	if not (h or h.player) return end
	local p = h.player
	if h.skin == "altsonic"
	and (v.valid and v.health and h.player and ((h.speedreached) or (h.player.althyper.transforming)))
	local px = h.x
	local py = h.y
	local br = 250*h.scale
		searchBlockmap("objects", function(mo, found)
			if found.valid
			and (found.type == MT_SALOONDOOR or found.type == MT_SALOONDOORCENTER) //the fuck
			and not found.deadlol
				found.flags = $ | MF_NOCLIP
				if found.type == MT_SALOONDOOR
					P_KillMobj(found)
					S_StartSound(h,sfx_wbreak)
					S_StartSound(h,sfx_s3k59)
				else
					Thoksplosion(found)
					found.deadlol = true
				end
			end
		end, h, px-br, px+br, py-br, py+br)
	end
end, MT_PLAYER)

addHook("MobjThinker", function(marker)
	if marker.state == S_LOCKON1
		for i, player in ipairs({consoleplayer, secondarydisplayplayer})
			local mo = player.mo
			if player.powers[pw_shield] & SH_NOSTACK == SH_ATTRACT
			and not (player.pflags & PF_THOKKED)
			and not player.powers[pw_super]
			and mo and mo.skin == "altsonic"
				marker.state = S_LOCKON2
				break
			end
		end
	end
end, MT_LOCKON)

addHook("MobjDeath", function(mobj, inflictor, source)
	if not (mobj.badnikpop) return end
	if mobj and mobj.valid and mobj.flags & MF_ENEMY
		for scraps = 1, 5
			local scrap = P_SpawnMobj(mobj.x, mobj.y, mobj.z+2*FRACUNIT, MT_RING)
			scrap.storedmomz = 1 //stinky
			scrap.sprite = SPR_BRKN
			scrap.frame = P_RandomRange(0, 23)
			scrap.angle = FixedAngle(P_RandomRange(1, 359)*FRACUNIT)
			P_InstaThrust(scrap, scrap.angle, P_RandomRange(5, 30)*FRACUNIT)
			P_SetObjectMomZ(scrap, P_RandomRange(5, 20)*FRACUNIT, false)
			scrap.colorized = true
			scrap.color = P_RandomRange(1, #skincolors-1)
			scrap.fuse = 10*TICRATE
			scrap.scrapped = true
			scrap.flags = MF_SOLID|MF_NOCLIPTHING|MF_PUSHABLE|MF_BOUNCE
		end
		S_StartSound(mobj,sfx_kc40)
	end
end)

addHook("MobjThinker", function(mobj)
	if mobj and mobj.valid and mobj.scrapped
		mobj.rollangle = $ + AngleFixed(FixedHypot(mobj.momx, mobj.momy)*FixedMul(314159*FU,100000*FU))
		if not P_IsObjectOnGround(mobj)
			mobj.storedmomz = (abs(mobj.momz) > 0) and mobj.momz or $
		else
			mobj.momz = (abs(mobj.storedmomz) > FU ) and -(mobj.storedmomz/2) or 0
		end
		if mobj.fuse == 1
			P_SpawnGhostMobj(mobj)
			P_RemoveMobj(mobj)
		end
	end
end, MT_RING)