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"
)

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
}

//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)

//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
			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
			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
			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
			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
			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
			CONS_Printf(player, "Hyper music set to 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'")
		elseif player.altmusic1
			CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Beyond the Speed Of (Sonic Runners)'")
		elseif player.altmusic2
			CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'It Doesn't Matter (Sonic Adventure 2)'")
		elseif player.altmusic3
			CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Endless Possibilities (Sonic Unleashed)'")
		elseif player.altmusic4
			CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'")
		elseif player.altmusic5
			CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Reach For The Stars (Sonic Colors)'")
		elseif player.altmusic6
			CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'")
		else
			CONS_Printf(player, "how tf did you get here")
		end
	elseif player.altmusic1
		CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Beyond the Speed Of (Sonic Runners)'")
	elseif player.altmusic2
		CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'It Doesn't Matter (Sonic Adventure 2)'")
	elseif player.altmusic3
		CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Endless Possibilities (Sonic Unleashed)'")
	elseif player.altmusic4
		CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Beyond the Speed Of (Sonic at the Olympic Games Tokyo 2020)'")
	elseif player.altmusic5
		CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'Reach For The Stars (Sonic Colors)'")
	elseif player.altmusic6
		CONS_Printf(player, "hypermusic [speedy/adventurous/boundless/olympic/radiant/nights] - Changes what music plays for hyper form. Currently 'NiGHTS Attack Menu Theme (Sonic Robo Blast 2)'")
	else
		CONS_Printf(player, "how tf did you get here")
	end
end, 0)

local function FixedLerp(a, b, w)
    return FixedMul((FRACUNIT - w), a) + FixedMul(w, b)
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.previousx == nil) or (mo.previousy == nil) or (mo.previousz == nil)
				mo.previousx = mo.x
				mo.previousy = mo.y
				mo.previousz = 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.previousx,percent)
					local ty = FixedLerp(mo.y,mo.previousy,percent)
					local tz = FixedLerp(mo.z + 3*FRACUNIT,mo.previousz + 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
				end
			end
			mo.previousx = mo.x
			mo.previousy = mo.y
			mo.previousz = 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, false)
			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 and 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.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.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
				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
				end
				if P_InSpaceSector(p.mo)
					p.powers[pw_spacetime] = 100*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 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
					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.speed > 1*FRACUNIT or p.mo.momz > 1*FRACUNIT or p.mo.momz < -1*FRACUNIT
					local AfterImageSpawn =
					P_SpawnGhostMobj(p.mo)
					AfterImageSpawn.color = p.mo.color
					AfterImageSpawn.colorized = true
					AfterImageSpawn.rollangle = p.mo.rollangle
				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
				end
			end
			if (p.powers[pw_super])
			and (p.althyper.transforming)
				p.charflags = SF_SUPER|SF_DASHMODE
			elseif (p.powers[pw_super])
			and not p.althyper.transforming
				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
			if p.althyper.transforming
			and p.dashmode >= 3*TICRATE
			and not p.exiting
				p.mo.colorized = true
			else
				p.mo.colorized = false
			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.mo.superdashtimer == nil
			p.mo.superdashtimer = 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)
			if leveltime % 5 == 0
			and not (p.powers[pw_super])
				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
			end
		end
		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])
			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.state == S_PLAY_SUPERDASH or (p.mo.state == S_PLAY_RUN and p.powers[pw_super]) or (p.althyper.transforming and p.mo.state == S_PLAY_DASH)
				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
		//Homing attack. Why is it here, you ask? Blame order of operations.
		if p.althoming == true
			//*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, false)
			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
		//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)
			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.transforming
		p.althyper.transforming = 0
	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
				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)

//Super Dash ghosts. Because PlayerThink ghost spawning is sus.
//For real though, why is there a difference.
addHook("ThinkFrame", do
	for player in players.iterate do
		if player.mo and player.mo.valid and player.mo.skin == "altsonic"
			if not player.althyper.transforming
				if player.dashmode >= 106
				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
					ghost1.colorized = false
					ghost1.rollangle = player.mo.rollangle
					ghost1.fuse = 2
					ghost1.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS60
					ghost1.eflags = player.mo.eflags & MFE_VERTICALFLIP
					local ghost2 = P_SpawnGhostMobj(player.mo)
					ghost2.color = player.mo.color
					ghost2.colorized = false
					ghost2.rollangle = player.mo.rollangle
					ghost2.fuse = 3
					ghost2.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS50
					ghost2.eflags = player.mo.eflags & MFE_VERTICALFLIP
					local ghost3 = P_SpawnGhostMobj(player.mo)
					ghost3.color = player.mo.color
					ghost3.colorized = false
					ghost3.rollangle = player.mo.rollangle
					ghost3.fuse = 4
					ghost3.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS40
					ghost3.eflags = player.mo.eflags & MFE_VERTICALFLIP
				end
				if player.mo.superdashtimer >= 200
					local ghost1 = P_SpawnGhostMobj(player.mo)
					ghost1.color = player.mo.color
					ghost1.colorized = true
					ghost1.rollangle = player.mo.rollangle
					ghost1.fuse = 2
					ghost1.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS60
					ghost1.eflags = player.mo.eflags & MFE_VERTICALFLIP
					local ghost2 = P_SpawnGhostMobj(player.mo)
					ghost2.color = player.mo.color
					ghost2.colorized = true
					ghost2.rollangle = player.mo.rollangle
					ghost2.fuse = 3
					ghost2.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS50
					ghost2.eflags = player.mo.eflags & MFE_VERTICALFLIP
					local ghost3 = P_SpawnGhostMobj(player.mo)
					ghost3.color = player.mo.color
					ghost3.colorized = false
					ghost3.rollangle = player.mo.rollangle
					ghost3.fuse = 4
					ghost3.frame = ($1 & ~FF_TRANSMASK)|FF_TRANS40
					ghost3.eflags = player.mo.eflags & MFE_VERTICALFLIP
				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/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")
			end
			file:close()
		end
	end
end)

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)