--=============================MAIN THINKER 1=======================================
--Since I didn't feel confident redirecting to other functions when I first made this project,
--I organized SMS' main thinkers into 3 parts. This is part 1, the main Lua script.
--SMS' most basic moves and attributes are set up here.
--==================================================================================

//2014: I have no idea what I'm doing - Let's Lua!
//EDIT-2019: Hey dataminer! Incase you're reading this to try and learn Lua, I suggest looking elsewhere first.
//I learned how to script WHILE making this, so alot of this is redundant, excessive, and/or terribly inefficient.
//Even the comments may be outdated and have no context anymore. Venture at your own risk!
-- GoldenShine AKA Super Mystic Sonic

--Which of these five billion gamemodes shall count as "Battlemod" today?
local function BattleModCheck(s)
	if not CBW_Battle return false end --It's not even added... nvm then.
	
	if gametype == GT_BATTLE or gametype == GT_CP 
	or gametype == GT_ARENA or gametype == GT_SURVIVAL
	or gametype == GT_TEAMBATTLE or gametype == GT_TEAMCP or gametype == GT_BATTLECTF  or gametype == GT_TEAMARENA or gametype == GT_TEAMSURVIVAL
	or gametype == GT_DIAMOND or gametype == GT_TEAMDIAMOND or gametype == GT_EGGROBOTAG
		return true
	else
		return false
	end
end

--Because the two hooks work SLIGHTLY different, I have PlayerSpawn+MobjSpawn.
addHook("MobjSpawn", function(s)
	if BattleModCheck(s)
		s.battlemodsms = true  --Just set this here so we don't have to check every frame
	elseif s.player
		s.player.smssonicbattle = nil
		s.battlemodsms = nil
	end
	s.sprst = true
	s.mssprst = true
	if s.player
		local p = s.player
		if p.hypermysticsonic
			SMS_SkinSwap(p.mo, p)
		end	
		if p.mysticsuper
			A_ENDMYSTICSUPER(s)
		end
	end
end, MT_PLAYER)

--Never spawn in custom transformations!
addHook("PlayerSpawn", function(p)
	if p.sweepangle == nil
		SetUpSMSreborn(p) -- ♫ You will know our variables ♫ 
	end
	if p.hypermysticsonic
		if p.mo --Set it all RIGHT now!
			SMS_SkinSwap(p.mo, p) --SkinSwap also performs HMSstats.
		else
			p.wasHMS = true --Do it later, I guess...
			p.hypermysticsonic = 0
		end
	end	
	if p.mysticsuper and p.mo
		A_ENDMYSTICSUPER(p.mo)
	end	
end)

--When players join a netgame, set this up!
local function SetUpSMSrebornJoin(p)
	local DONTSYNC = false
	local SYNCLEVEL
	
	if splitscreen --Cases where syncing is unnecessary.
	or not netgame
	or SMS_Admin(p) == 3
		DONTSYNC = true
		SYNCLEVEL = 7 --Always perfect.
	end

		if not DONTSYNC
		and p.sms_joinsync != 1

			local AUTO = false
			local TOTALPLAYERS = 0

			for z in players.iterate
				if z.hypermysticsonic --Treat every HMS in the game like 4 players worth of performance.
					TOTALPLAYERS = $+4
				else
					TOTALPLAYERS = $+1
				end
				if z.smsautographix
					AUTO = true
				end
			end
			local CURRENT = SMS_Graphix(s) --Change graphics automatically depending on playercount.
			if AUTO and TOTALPLAYERS
				if (TOTALPLAYERS < 12)			
					if (TOTALPLAYERS < 8)
						for z in players.iterate //Full steam ahead!
							if CURRENT != 0
								CONS_Printf(z, "SMS graphics auto-adjusted to\x83 full")
							end
							z.smsgraphix = 0
						end
					else
						for z in players.iterate //Slow it down a bit....
							if CURRENT != 1
								CONS_Printf(z, "SMS graphics auto-adjusted to\x84 medium")
							end
							z.smsgraphix = 1
						end
					end
				else
					for z in players.iterate //Busy netgame, minimum graphics!			
						if CURRENT != 2
							CONS_Printf(z, "SMS graphics auto-adjusted to\x85 minimum")	
						end
						z.smsgraphix = 2
					end
				end
			end
		end
		if not p.didsmsautoconfig
			if netgame
				if not SMS_Admin(p) == 3
					SMS_LoadGame(p)
					if not p.didsmsautoconfig
						p.didsmsautoconfig = 1
					end
				end
				if (gametype != GT_COOP) and not p.smsfirstcolor
					if (A_setSMSspecialcolors(p, P_RandomRange(1,33)))
						p.smsfirstcolor = true
						CONS_Printf(p, "\x85"+"No saved SMSreborn options present! Picking random colorscheme for SMS...")
					end
				end
			end
		end
		
		--Now that our save is loaded, sync up with all admin values!
		if not DONTSYNC
		and p.sms_joinsync != 1
			for z in players.iterate --Find a player to sync with!
				if z.valid and z != p and not p.sms_joinsync
					p.smsautographix = z.smsautographix
					p.hmsmlimit = z.hmsmlimit
					p.smstransformonly = z.smstransformonly
					p.hmsmlimit = z.hmsmlimit
					p.hmstransformdisable = z.hmstransformdisable		
					p.powersharerestrict =  z.powersharerestrict		
					p.smsgraphix = z.smsgraphix
					p.smsnoracegame = z.smsnoracegame	
					p.smsnomatchgame = z.smsnomatchgame		
					p.smsnobmgame = z.smsnobmgame		
					p.smsnomsspawn = z.smsnomsspawn
					p.nosmscolorspls = z.nosmscolorspls
					p.glitchydebugthrow = z.glitchydebugthrow
					SYNCLEVEL = 1
					break --We synced, so stop!
				end
			end
		end
		
		p.sms_joinsync = SYNCLEVEL --7 is perfect.
		
		CONS_Printf(p, "\x82"+"----------"+"\x85"+"==============="+"\x82"+"------------"+"\n")
	--	COM_BufInsertText(p, "exec SMSreborn.cfg") --Can't do this anymore in 2.2.11+ for security reasons or whatever.
		CONS_Printf(p, "\n"+"\x82"+"Super Mystic Sonic Reborn\x80 [SRB2 2.2.11+] - By\x82 Golden Shine"+"\n")	
		
		if p.bot
			p.smsdontgrabme = 2
		end		
		if p.mo and p.mo.valid
			local s = p.mo
			if BattleModCheck(s) --Set this here too.
				s.battlemodsms = true
			else
				p.smssonicbattle = nil
			end
			p.sms_joinsync = 7 --Full sync!
			if p.smstransformonly and (s.skin == "sms") and not p.sms_transformstate
				A_SMSTOSONIC(s, nil, true, true) //Cancel the mobjthinker if switching to Sonic or your stats will mess up.
				return true --
			end
		end
end

--Second Mobj Spawn specifically for the Mystic Emerald appearing.
local function SetUpSMSrebornmo2(s, p)

	if s.mssprst == false --If not nil or true, then a player somewhere already did this check.
	or s.smshudgimmick
		return --
	end
	
	if (gametype == GT_TAG) 
	or (gametype == GT_HIDEANDSEEK)
	or (p.powers[pw_carry] == CR_NIGHTSMODE) --Never in these gamemodes!	
	
		for z in players.iterate
			z.spawnSMSship = false
			if z.mo z.mo.mssprst = false end
		end
		return --
		
	else --Okay, go ahead!
		
		--Are we in a special HUD-gimmick level, like the Puyo Puyo stage?
		if (gamemap == 103 or gamemap == 40)
		and not s.smshudgimmick
			if s.subsector and s.subsector.sector
				local SEC = s.subsector.sector --Player's spawn sector.
				if SEC.ceilingpic == "PIT" and SEC.floorpic == "PIT"
					if SEC.lightlevel == 0 
					or SEC.floorheight == -1024*FRACUNIT and (SEC.lightlevel < 64)
						for z in players.iterate
							z.spawnSMSship = false					
							if z.mo
								z.mo.smshudgimmick = true --We spawned in a gimmick level, don't spawn Mystic Emerald!
								z.mo.mssprst = false
							end
						end
						return --
					end
				end
			end
		end
		
		if p.smsnomsspawn
			return --Can't spawn Emerald with this setting.
		end

		p.spawnSMSship = true	
		for m in mobjs.iterate(mobjs) --Look for a nearby boss. If it's there, don't spawn the emerald!
			if m.valid and m.flags
				if (m.flags & MF_BOSS)
				or (m.type == MT_METALSONIC_RACE)
					if m.health and (FixedHypot(m.x-s.x, m.y-s.y) <= 6000*s.scale)
						for z in players.iterate
							z.spawnSMSship = false
							if z.mo z.mo.mssprst = false end
						end
						return --
					end
				end
			end
		end
		
		--Assign the Mystic Emerald object to someone.
		if not p.smsnomsspawn and p.spawnSMSship and multiplayer	
		
		or p.spawnSMSship and (s.skin == "sms" or A_SMScompatibleskin(s))
		
			if not s.smshudgimmick and not p.powers[pw_carry]
			
				local SPAWNEDGEM
				
				for z in players.iterate
					if not (z.smsssp and z.smsssp.valid)
						if SPAWNEDGEM
							z.smsssp = SPAWNEDGEM
						else
							z.smsssp = P_SpawnMobjFromMobj(z.mo, 0,0, 24*z.mo.scale, MT_THEMYSTICEMERALD)
							z.smsssp.tracer = s
							SPAWNEDGEM = z.smsssp
						end
					end			
				end			
			end
		end
		for z in players.iterate
			z.spawnSMSship = false
			if z.mo z.mo.mssprst = false end
		end
	end
end

--Extra instant setup.
for z in players.iterate
	if z and z.valid
		if z.sweepangle == nil SetUpSMSreborn(z) end
		if z.mo and z.mo.sprst == nil SetUpSMSrebornmo(z) end
	end
end

//Let's go into the meat of things, the player's MobjThinker! Because who needs PlayerThink? (Which didn't exist in early 2.1)
addHook("MobjThinker", function(s) if not s.player return end --
	local p = s.player
	local yu = p.smsrtable --Yuji Uekawa, here?? More likely than you think.
		if p.sms_joinsync != 7
			if SetUpSMSrebornJoin(p) --Whenever a player starts a game, joining netgame or not.
				return --If it's true, you were switched to Sonic, so stop the mobjthinker here.
			end
		end		
		--We just spawned!
		if s.sprst		
			SetUpSMSrebornmo(p) --Whenever a player's mo spawns.
		end			
		--Second spawn function! It spawns the Mystic Emerald where applicable.
		if s.mssprst 
			SetUpSMSrebornmo2(s, p)
			s.mssprst = false
		end
		
		 --Squash and stretch animation features. Hopefully I didn't overdo it, feel free to bitch at me if I did!
		if s.SMS_squashtable
			SMS_SquashAndStretch(s)
		end			
		if s.SMSclosest
			s.SMSclosest = nil
		end
		--Timers that apply to all skins
		if s.smslsaret --LSA = Light Speed Attack
			s.smslsaret = $-1
		end
		if s.smsldret --LD = Light Dash
			s.smsldret = $-1
		end
		if s.smslsacheck //Here starts the era of the thousand timers!
			s.smslsacheck = $-1
			if not s.smslsacheck
				s.lsatarget = nil
			end
		end
		if s.lsaringdebt
			s.lsaringdebt = $-1
		end
		if s.SMS_WallBounce --We've hit a wall recently.
			s.SMS_WallBounce = $-1
		end		
		if s.smsldcheck
		s.smsldcheck = $-1
			if not s.smsldcheck and (s.state != S_SMS_LIGHTDASH)
				s.smsrdash = nil
				s.lastldrx = 0
				s.lastldry = 0
			end
		end
		if s.hmsmwh --Wind sound timer+object.
			if not (s.smssoundobj2 and s.smssoundobj2.valid and s.smssoundobj2.health)
				if (s.smssoundobj3 and s.smssoundobj3.valid and s.smssoundobj3.smsmwtim)			
					s.smssoundobj3.state = S_NULL
				end
				s.smssoundobj2 = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_SMSSOUNDOBJ)
				s.smssoundobj2.master = s
				s.smssoundobj2.health = 1
				S_StartSound(s.smssoundobj2, sfx_machwh)
				s.smssoundobj2.smsmwhtim = 51 //74 for normal
			end
			s.hmsmwh = $-1
		end
		if s.hudboost --Machspeed HUD effect scaler.
			s.hudboost = $+1
			if (s.hudboost > 7)
				s.hudboost = 0
			end
		end
		if s.SMS_FireHUD --Table that adds flamewalls to the HUD.
			SMS_FireHUD(s, p, s.SMS_FireHUD)
		end
		if s.hmscarryspinpass --For HMS passengers
			s.hmscarryspinpass = $-1
		end
		if s.SMS_lemmego --Escape from SMS' pickup grab.
			s.SMS_lemmego = $-1
		end
		if s.iampickedupbysmshelp --Currently picked up by SMS.
			s.iampickedupbysmshelp = $-1
		end
		if s.ibethrownbysmshelp --Currently in a thrown-by-SMS state.
		s.ibethrownbysmshelp = $-1
			if not s.ibethrownbysmshelp
				s.spritexscale = FRACUNIT+16000
				s.spriteyscale = FRACUNIT-14000
				s.SMS_squashtable = {timer = 4}
				s.rollangle = 0
			end
		end
		if s.sms_auradelay
			s.sms_auradelay = $-1
		end
		if s.hmspickedup
		s.hmspickedup = $-1
			if not s.hmspickedup
				if s.hmspickuptarget != nil and s.hmspickuptarget.valid
					s.hmspickuptarget.occupiedcarrying = nil
				end
				s.occupiedcarrying = nil
			end
		end
		if s.sdodgeoh
			s.sdodgeoh = $-1
			if not s.sdodgeoh
				s.dodgespinslide = false			
			elseif P_IsObjectOnGround(s) and not p.sms_dodging
				s.dodgespinslide = true
			end
		end
		if p.srgorelvl --Only spawn so many robot gibs at once, will you?
			p.srgorelvl = max($-1, 0)
			if (p.srgorelvl > 170)
				p.srgorelvl = min(250, $-2)
			end
		end
		if s.hmsshieldconsume --Used for misc purposes too, not just HMS shields ring boosts.
			s.hmsshieldconsume = $-1
		end
		if s.hmsshieldconsumecd
			s.hmsshieldconsumecd = $-1
		end		
		if p.smsgriefw --Anti-griefing message.
			p.smsgriefw = $-1
		end
		--Rag Doll through the air after a particularly nasty hit!
		if s.SMS_CrashRoll
			SMS_RagDoll(s)
		end
		--Leave behind your chosen trail types!
		if s.SMS_DLtrail
			SMS_ContinuousTrail(s, s.SMS_DLtrail)
		end
		if s.forcesmsangletimer
			if (p.pflags & (PF_DIRECTIONCHAR|PF_ANALOGMODE)) and s.forcesmsangle != nil
				p.drawangle = s.forcesmsangle
			end
			s.forcesmsangletimer = $-1
		end
		if s.hmstorvictim --Caught in HMS' tornado.
			s.hmstorvictim = $-1
			s.hmstorvictimang = (s.hmstorvictimang != nil) and s.hmstorvictimang+FixedAngle(8*FRACUNIT) or p.drawangle
			if (s.state == S_PLAY_ROLL) or (p.panim == PA_ROLL) or (p.panim == PA_JUMP)
				if leveltime % 77 == 0
					p.pflags = $|PF_JUMPED & ~(PF_THOKKED|PF_SPINNING)
				end
			end
			p.drawangle = s.hmstorvictimang
			s.rollangle = s.hmstorvictimang
			if not s.hmstorvictim and s.rollangle
				s.rollangle = 0
			end
		end
		--Stand still for a while and you can be grabbed.
		if p.smsdontgrabme != 1
		and (not p.cmd.buttons and (abs(p.cmd.sidemove) < 3) and (abs(p.cmd.forwardmove) < 3))
			if p.smsdontgrabme == 2
				s.iasmsp = 140
			end		
			s.iasmsp = s.iasmsp and $+1 or 1
			if s.iasmsp < 55
				s.iasmsp = $+1
			end
		else
			s.iasmsp = 0
		end
		
		//Debug code to test Mystic Supers/Spawn Mystic Emeralds.
	/*	if (s.skin != "sms")
			if p.rings and not p.mysticsuper 
			and (p.cmd.buttons & BT_CUSTOM2) and (p.cmd.buttons & BT_CUSTOM1) and (p.cmd.buttons & BT_CUSTOM3)
				A_STARTMYSTICSUPER(s)
			end
		else
			if (p.cmd.buttons & BT_CUSTOM2) and (p.cmd.buttons & BT_CUSTOM1) and (p.cmd.buttons & BT_CUSTOM3) and p.speed == 0 and not p.sms_flamedelay
			P_SpawnMobjFromMobj(s, 0, 0, 0, MT_THEMYSTICEMERALD) p.sms_flamedelay = 105
			end
		end */
		
		if s.supersmsrecoil2
			s.recoilthrust = nil
			p.powers[pw_nocontrol] = 0
					if s.supersmsrecoil2 == 17
						s.rollangle = 0
						s.supersmsrecoil2 = 16
						if s.supersmsrecoil2ang != nil
						P_InstaThrust(s, s.supersmsrecoil2ang, -65*s.scale)
						end
					elseif (s.eflags & MFE_JUSTHITFLOOR)
						s.rollangle = 0
						s.supersmsrecoil2 = 0
						s.supersmsrecoil = false						
						if CBW_Battle and CBW_Battle.DoDebris
							S_StartSound(s, sfx_cdfm42)
							for d = 0,08
							CBW_Battle.DoDebris(s,P_RandomChance(FRACUNIT/2),P_RandomRange(5,20))
							end
						end
					elseif s.supersmsrecoil2 == 16
					s.supersmsrecoil = false
					s.rollangle = $-FixedAngle(35*FRACUNIT)
						if ((s.momx < 699355 and s.momx > -699355) and (s.momy < 699355 and s.momy > -699355))
						s.state = S_PLAY_DRWN
						P_SetObjectMomZ(s, 3*FRACUNIT) s.momx = 0 s.momy = 0
						s.supersmsrecoil2 = $-1
						S_StartSound(s, sfx_cdfm42)
						S_StartSound(s, sfx_kc40)
						S_StartSound(s, sfx_s3k9b)						
						A_SMSquake(s, 60*FRACUNIT, 8, 901)
						P_SpawnMobjFromMobj(s, 0, 0, 0, MT_BURSTWAVE)
						S_StartSound(s, sfx_altow1)
						p.rings = 10
						P_PlayerRingBurst(p, 10)
						p.rings = 0
						local bsl = P_SpawnMobj(s.x, s.y, s.z-12*FRACUNIT, MT_BURSTLIGHT)
						bsl.color = SKINCOLOR_WHITE
							for d = 0,15
							CBW_Battle.DoDebris(s,P_RandomChance(FRACUNIT/2),P_RandomRange(5,20))
							end	
						end
					elseif (s.supersmsrecoil2 > 1)
						s.rollangle = 0
						s.supersmsrecoil = false
						s.supersmsrecoil2 = $-1
						s.state = S_PLAY_DRWN
						s.momz = $/99 s.momx = 0 s.momy = 0
					else
						s.rollangle = 0
						s.state = S_PLAY_PAIN					
						s.supersmsrecoil2 = 0
					end
		end

		--First, things that affect everyone but SMS!
		if (s.skin != "sms")
			if s.AmSuperMysticSonic
				SMS_SkinSwap(s, p) --We just swapped! Keep this in mind, it'll be important!
			end
			if s.battlemodsms --Battlemod behaviour.
		  		if s.ssittcpls2
				
					s.ssittcpls2 = $-1
					p.skincolor = s.ssittcpls
					s.color = s.ssittcpls
					p.sms_originalcolor = s.ssittcpls
					
					if not s.ssittcpls2
						s.ssittcpls = nil
					end
				end
		  		if s.lastbmrings --Refund rings and maybe spawn a shield to make it easier to re-transform
		  			if not s.supersmsrecoil2
						if not (CBW_Battle and CBW_Battle.SkinVars)
							p.shieldstock = 1 --Extra reserve pity shield
						end
						if (s.lastbmrings > 10)
							P_GivePlayerRings(p, 10)
							if not p.powers[pw_shield]
								if (s.lastbmrings > 59)
									p.powers[pw_shield] = SH_FORCE|1
								elseif (s.lastbmrings > 29)
									p.powers[pw_shield] = SH_PITY
								end
								S_StartSound(s, sfx_shield)
								P_NukeEnemies(s, s, 0)
								P_SpawnShieldOrb(p)
							end
						else
							P_GivePlayerRings(p, s.lastbmrings)
						end
					end
					s.lastbmrings = 0
				end
			end
			
		--=====================SMS skin check!===========================
		else //if (s.skin == "sms") --BEGIN!!
		--===============================================================
			if s.AmSuperMysticSonic == false --PS: only activate when false, not when nil!
				SMS_SkinSwap(s, p)
			end
			s.AmSuperMysticSonic = true 
			
			--Update our controls every frame. yu = p.SMSrtable		
			local forwardmove = abs(p.cmd.forwardmove)
			local sidemove = abs(p.cmd.sidemove)
			if forwardmove > sidemove
				yu.direct = forwardmove
			else
				yu.direct = sidemove --Decide how hard we're pressing the stick! From 0 to 50!
			end
			yu.turnang = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
			
			--S timers for SMS specifically!
			if s.atomdiveusebuffer
				if not (s.state == S_SMS_ATOMDIVE)
					s.atomdiveusebuffer	= $-1
				end
				if not ((p.cmd.buttons == 0) or (p.cmd.buttons & BT_SPIN))
				and not p.homing and not (p.cmd.forwardmove > 0)
				and not ((abs(p.cmd.forwardmove) > 8 or abs(p.cmd.sidemove) > 8) and (p.pflags & PF_ANALOGMODE))
			
				or p.hypermysticsonic
					s.atomdiveusebuffer = 0
					s.useatommethod = false
				end
			end
			if s.smsabsfx
				s.smsabsfx = $-1
			end
			if s.SMS_walltwitch
				s.SMS_walltwitch = nil
			end			
			if s.sms_spintrickspeed
				if not ((s.state >= S_SMS_PREHOMET1) and (s.state <= S_SMS_HOMET7))
					s.sms_spintrickspeed = nil
				else
					local MINUS = (abs(s.momz) > 7*s.scale or p.speed > 28*s.scale) and 1 or 2
					s.sms_spintrickspeed = max($-MINUS,0)
					if (s.sms_spintrickspeed > 10)
						if s.tics > 1
							s.tics = max($-2,1)
						end
					elseif s.tics > 1
						s.tics = $-1
					end
				end
			end			
			if s.sms_superspin
				s.sms_superspin = $-1
			end
			if s.haltthespam --For stomp/hyperrise/mobile charge graphics CD.
				s.haltthespam = $-1
			end			
			if s.SMS_oldspeed --Restore old pre- spring/booster speed!
				if (p.speed <= s.SMS_oldspeed-9*s.scale)
				and (yu.direct > 9)
				and (p.sms_boostlevel > 64 or (p.cmd.buttons & BT_CUSTOM1) or p.sms_autoboosthold)
				and ((abs(s.momx) > 3*s.scale) or (abs(s.momy) > 3*s.scale))
					if not (s.eflags & MFE_UNDERWATER)
					and not SMS_Locked(s,p, true)
						P_InstaThrust(s, R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy), s.SMS_oldspeed-9*s.scale)
					end
				end
				s.SMS_oldspeed = nil
			end
			if s.smsaurablastivatecd
				s.smsaurablastivatecd = $-1
			end	
			--Fine, p timers too.....
			if p.sms_aerialfirerestrict 
				if (P_IsObjectOnGround(s) or (p.pflags & PF_JUMPED))
					p.sms_aerialfirerestrict = nil
				end
			end
			
			--Many other button timers are in LUA_SMS2.
			p.weaponprevhold = (p.cmd.buttons & BT_WEAPONPREV) and $+1 or 0
			p.sms_flamebuttonhold = (p.cmd.buttons & BT_ATTACK) and $+1 or 0
			p.sms_nflamehold = (p.cmd.buttons & BT_FIRENORMAL) and $+1 or 0
			p.sms_c1 = (p.cmd.buttons & BT_CUSTOM1) and $+1 or 0
					
			if s.SMS_MineCarting
				s.SMS_MineCarting = $-1
				if p.powers[pw_flashing] --Lets you ragdoll of ramps after getting hurt!
				and (s.momz*P_MobjFlip(s) > 0)
				and not (p.pflags & (PF_SPINNING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_STARTJUMP|PF_STARTDASH))
				and not p.hypermysticsonic
				and not p.hometrickanim
				and not p.powers[pw_carry]				
					P_SetObjectMomZ(s, FRACUNIT, true)
					P_Thrust(s, R_PointToAngle(s.x, s.y, s.x+s.momy, s.y+s.momy) or s.angle+ANGLE_180, 24*s.scale)
					A_SMSquake(s, 65*FRACUNIT, 4, 500)
					SMS_RagDoll(s, 2)
				end
			end
			if s.smsframejump
				s.smsframejump = $-1
			end
			if s.smshmcheck --HayMaker check timer.
				s.smshmcheck = $-1
				if not s.smshmcheck 
					s.cmphtarget = nil
				end
			end
			if s.smspkuret --Ready to pick up an item?
				s.smspkuret = $-1
			end	
			if s.hmsrunquake
				if not (s.smssoundobj5 and s.smssoundobj5.valid and s.smssoundobj5.health)
					s.smssoundobj5 = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_SMSSOUNDOBJ)
					s.smssoundobj5.master = s
					s.smssoundobj5.health = 1
					S_StartSound(s.smssoundobj5, sfx_cdfm42)
					s.smssoundobj5.smsquaketim = 4
				elseif (s.smssoundobj5 and s.smssoundobj5.valid and s.smssoundobj5.health and s.smssoundobj5.smsquaketim)
					s.smssoundobj5.smsquakerefresh = true
				end	
				s.hmsrunquake = $-1
			end		
			if s.SMS_WallJumpTable --Walljumping! Wall Jumping. Wall Jump Table...WJ.timer?
				if not s.SMS_WallJumpTable.timer --That's not right...!
				or s.skin != "sms"
					s.SMS_WallJumpTable = nil
					s.spriteyscale = FRACUNIT
					s.spritexscale = FRACUNIT
					s.rollangle = 0
				else
					if P_IsObjectOnGround(s) and not (s.momz*P_MobjFlip(s) > 0) --Instantly skip in this case.
					or p.hypermysticsonic
					or (s.SMS_WallJumpTable.timer != 22) and ((s.eflags & MFE_SPRUNG) or SMS_Locked(s, p, true))
						s.SMS_WallJumpTable.timer = 1 --The hook will finish things if it's set to 1.
					end
					s.smspickupCD = 2
					--Do Wall Jump Behaviour!
					SMS_WallJumping(s, p, s.SMS_WallJumpTable, p.smsrtable)	
				end
			elseif s.hmsspinpass
				if p.sms_stompanim and s.stompanimburst and (s.stompanimburst > 8)
					--
				elseif (p.hypermysticsonic < 5)
				or SMS_Locked(s, p)
				or P_IsObjectOnGround(s)
				or p.hmsdash and (p.speed > 230*s.scale)
				or (p.pflags & (PF_STARTDASH))
				or s.momz == 0
					s.hmsspinpass = 0
				end
			end		
			if s.hmsroflstomped and (s.rollangle == ANGLE_180)
				if not p.hms_stompbreak or not (p.cmd.buttons & BT_CUSTOM2)
					if s.hmsroflstompcd == nil
						s.hmsroflstompcd = 1				
					else
						s.hmsroflstompcd = $+1
					end
				end
				if (p.hypermysticsonic < 5)
				or P_IsObjectOnGround(s) 
				or (s.hmsroflstompcd and (s.hmsroflstompcd > 7))
				or s.airboostroll
				or p.hmsdash and (p.speed > 230*s.scale)
				or s.hms_jumprisen
				or (p.pflags & (PF_STARTDASH))
				or SMS_Locked(s, p)
				or s.momz == 0
				or (s.state == S_PLAY_PAIN and p.powers[pw_nocontrol] == 2)
					s.hmsroflstomped = false
					s.rollangle = 0
					s.hmsspinpass = 0
				end
			elseif s.hmsroflstompcd
				s.hmsroflstompcd = 0
			end
			if s.smspickupCD --Cooldown for pickup.
				s.smspickupCD = $-1
			end			
			if s.smsstompcd
				s.smsstompcd = $-1
			end
			if s.SMS_WJpenalty
				if p.powers[pw_carry]
				or P_PlayerInPain(p)				
					s.SMS_WJpenalty = 0
					s.SMS_lastwallANG = nil
					s.SMS_lastwallNUM = nil
				else
					s.SMS_WJpenalty = min($-1, 260)
					s.SMS_HUDorb = s.SMS_HUDorb and min($+1,5) or 1
					for i = 1,7
						if (s.SMS_WJpenalty > 180)
							s.SMS_WJpenalty = $-1
						else
							break
						end
					end
					if (s.eflags & MFE_UNDERWATER) or (s.momz*P_MobjFlip(s) <= -5*s.scale) --Regain it faster if you're losing height.
						s.SMS_WJpenalty = max($-2, 0)
						if (s.eflags & MFE_GOOWATER)
							s.SMS_WJpenalty = min($, 30)
						end
					end
				end
			else
				if s.SMS_HUDorb 
					s.SMS_HUDorb = $-1
				end
				if s.SMS_WJpenalty == nil --Special treatment.
					s.SMS_WJpenalty = 0
				end
			end
			if s.suddenquickspeed
				s.suddenquickspeed = $-1
				if s.suddenquickspeed <= 1
					s.flags2 = $ & ~MF2_DONTDRAW
				else
					if p.hypermysticsonic
						s.flags2 = $|MF2_DONTDRAW
					else
						s.suddenquickspeed = 0
						s.flags2 = $ & ~MF2_DONTDRAW
					end
				end
			end			
			if s.DeyCURollin
				s.DeyCURollin = $-1
				if not s.DeyCURollin and p.powers[pw_carry] == CR_ROLLOUT
					p.powers[pw_carry] = 0 //Get lost, rock.
				end
			end
			if s.sms_boostloss --.lostboost?
				if not (p.sms_boostlevel >= 65)
					if s.sms_boostloss == 12
						if p.hypermysticsonic
						or p.sms_ringburstfly
						or p.sms_ringburst
						or p.sms_comethaymaker
						or p.mslightspeedattack
						or p.sms_hugeflametoss
						or p.footsweepanim

							s.sms_boostloss = 0
							
						else
							local ghs = SMSRSpawnGhost(s, 9, true)
							ghs.color = SKINCOLOR_SMSROVERGLOWRED
							ghs.colorized = true
							ghs.destscale = $*99
							for i = 3,7,2
								ghs = SMS_WallJumpGFX(s, true)
								ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS & ~RF_PAPERSPRITE
								ghs.spriteyscale = $/(i-1)
								ghs.spritexscale = $/(i-1)
								ghs.color = SKINCOLOR_RED-3+i
								ghs.colorized = true
								ghs.frame = ($ & ~FF_TRANSMASK)|FF_TRANS30
							end
							ghs = P_SpawnMobjFromMobj(s,s.momx,s.momy,0, MT_THOK)
							ghs.flags2 = MF2_DONTDRAW ghs.tics = 99
							S_StartSoundAtVolume(ghs, sfx_smsfx9, 140)
						end	
					end
					if s.sms_boostloss > 8
						SMS_DiffusionChargeSparkles(s, p, SKINCOLOR_CRIMSON)				
					end
					s.sms_boostloss = max($-1,0)
				end
			end			
			if s.smsbdsfx --Blind dash voiceclip cooldown
				s.smsbdsfx = $-1
			end
			if s.airboostroll 
			
				if (((s.state == S_SMS_AIRBOOST) or (s.state == S_PLAY_PAIN) or (s.state == S_SMS_LIGHTDASH)) or p.hypermysticsonic)
				
				and not P_IsObjectOnGround(s)
			
				and not ((p.speed < 30*s.scale) and (s.state != S_PLAY_PAIN) and (s.state != S_SMS_LIGHTDASH))
				
				and not (s.flags2 & MF2_TWOD)
				
					if (s.airboostroll == 1)
						s.airboostroll = 0
						s.rollangle = 0
					else
						s.airboostroll = $-1
						if s.hmsrotateright
							s.rollangle = $-FixedAngle(53*FRACUNIT)
						else
							s.rollangle = $+FixedAngle(53*FRACUNIT)
						end
					end
				else
					s.airboostroll = 0
					s.rollangle = 0
				end
			elseif s.hmscchange and not s.smstrickroll 
				p.viewrollangle = 0
				s.hmscchange = false
			end
			if s.useatommethod
				if not (p.cmd.buttons & BT_SPIN) or not (s.state == S_SMS_ATOMDIVE)
					s.useatommethod = false
				end
			end	
			if s.SMS_wallready
				s.SMS_wallready = $-1 
			end
			if s.SMS_wallwait
				s.SMS_wallwait = $-1 
				if P_IsObjectOnGround(s)
				or p.powers[pw_carry]
					s.SMS_wallwait = 0
					s.SMS_lastwallANG = nil
					s.SMS_lastwallNUM = nil
				end
			end		
			if s.SMS_removeWD
				if (s.SMS_removeWD > 1)
					s.SMS_removeWD = $-1
				elseif not s.SMS_wallready
					s.SMS_removeWD = $-1
					if not s.SMS_removeWD
						SMS_WallJumpDelete(s)
					end
				end
			end
			if s.smsboostimmune --Can't lose boostmode easily with this on.
				s.smsboostimmune = $-1
			end
			--Your Comet Haymaker target will glow!
			if s.smscmphret
				s.smscmphret = $-1
				--Make target glow!
				if s.cmphtarget2
					if s.cmphtarget2.valid
						local t = s.cmphtarget2
						if t.sprite and not (t.flags2 & MF2_DONTDRAW)
							local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_SMSAUTOFRAME)
							ghs.sprite = t.sprite
							ghs.frame = (t.frame & ~FF_TRANSMASK)|TR_TRANS30
							ghs.blendmode = AST_ADD
							ghs.renderflags = t.renderflags
							ghs.angle = t.angle
							ghs.scale = t.scale
							ghs.momx = t.momx
							ghs.momy = t.momy
							ghs.momz = t.momz
							ghs.rollangle = t.rollangle
						ghs.spritexscale = t.spritexscale
							ghs.spriteyscale = t.spriteyscale
							ghs.mirrored = t.mirrored
							ghs.colorized = true
							ghs.tics = 2 ghs.fuse = 9
							if leveltime % 2 == 0
								ghs.color = SKINCOLOR_ORANGE
							else
								ghs.color = SKINCOLOR_SUPERGOLD5
							end
						end
					else
						s.cmphtarget2 = nil
					end
				end
			end
			if s.readyforonemoreplant
				s.readyforonemoreplant = $-1
			end			
			
			--Lightning Homing Bolt Ability, rocket skywards after hitting an enemy!
		/*	if s.SMS_HomingBolt
				SMS_HomingBolt(s,p, s.SMS_HomingBolt)
			end */
			if s.sms_jumpbuffer 
				s.sms_jumpbuffer = $-1
			end
			if (p.cmd.buttons & BT_JUMP)
				p.sms_jumphold = $+1
							
				--Jump button buffering system!
				
				if (p.sms_jumphold == 1 or s.sms_jumpbuffer)
				and not p.hypermysticsonic 
				and not (p.smsdivetimer and not s.smsdropdash)
				and not P_PlayerInPain(p)
				and not SMS_Locked(s, p)
				
					local anim = 0						

					if (p.pflags & PF_STARTJUMP) and (s.momz >= 3*s.scale*P_MobjFlip(s)) and (p.pflags & PF_JUMPED)
						s.sms_jumpbuffer = 0 --Abort.
					elseif ((p.panim >= PA_WALK) and (p.panim <= PA_PAIN))
					or ((s.state >= S_SMS_BOOST01) and (s.state <= S_SMS_BOOST04))
					or (p.pflags & PF_SPINNING) and not (p.pflags & (PF_STARTDASH|PF_JUMPED|PF_SLIDING|PF_STARTJUMP)) and (p.panim == PA_ROLL)
						anim = 1 --Ideal conditions!
					elseif ((p.panim >= PA_SPRING) and (p.panim <= PA_ABILITY)) and (s.momz < 3*s.scale*P_MobjFlip(s))
					or (s.state == S_SMS_ADVFALL2)
					or (s.state == S_SMS_ADVFALL1)
					or (s.state == S_SMS_AIRBOOST)
					or ((s.state == S_SMSWATERGRIND1) or (s.state == S_SMSWATERGRIND2)) and not (s.eflags & MFE_TOUCHWATER)
					or (p.panim == PA_ROLL) and (((p.pflags & PF_THOKKED) and (p.pflags & PF_JUMPED)) or s.smsdropdash)
						anim = 2 --Good enough for activating the buffer, at least!
					end
					if anim != 0		
						if p.sms_jumphold == 1
							if not P_IsObjectOnGround(s)
							and not (p.pflags & (PF_STARTJUMP|PF_JUMPSTASIS))
								s.sms_jumpbuffer = 8 --You get 8 frames of buffer!
							end	
						end
						if s.sms_jumpbuffer		
							if anim == 1
							and (p.pflags & PF_JUMPDOWN) 
							and not (p.pflags & (PF_STARTJUMP|PF_JUMPSTASIS|PF_JUMPED))
							and (p.sms_jumphold < 14)
								if P_IsObjectOnGround(s)
									p.pflags = $ & ~PF_JUMPDOWN
								elseif s.smsframejump
									s.bufferframejump = true
								end
							end
						end
					end				
				end				
			else
				p.sms_jumphold = 0
				if s.sms_jumpbuffer and P_IsObjectOnGround(s)
					s.sms_jumpbuffer = 0
				end
			end
			
			if p.bot
				if (p.speed < 10*FRACUNIT) and P_IsObjectOnGround(s)
					s.smsbottf = s.smsbottf and $+1 or 1
				else
					s.smsbottf = 0
				end
				if p.dobotpowershare
					p.dobotpowershare = $-1
				end
			end
			if s.battlemodsms
				SMS_BattleModThinker(s, p)
			elseif G_GametypeHasSpectators()
				if p.smsnomatchgame
					P_FlashPal(p, PAL_NUKE, 4)
		 			S_StartSound(s, sfx_lose)
					CONS_Printf(p, "\x85"+"SMS is not allowed in Matches right now!")	  
					A_SMSTOSONIC(s, nil, true, true)
					return --
				end
			elseif p.smstransformonly and not p.sms_transformstate
		  		P_FlashPal(p, PAL_NUKE, 4)
		 		S_StartSound(s, sfx_lose)
				CONS_Printf(p, "\x85"+"SMS is available only as transformation now!")	  
				A_SMSTOSONIC(s, nil, true, true) --Don't continue any further in this case.
				return --
			end
			
		//SMS' strong spring code. Mimmicks the way Amy interacts with springs, but is tweaked for horizontal springs.
		
		  if s.vertstrongspring
		  	if not P_PlayerInPain(p)
		  			if s.horstrongspring2 --Horizontal boost from a strictly horizontal spring.
						s.momx = $*7/4
						s.momy = $*7/4
					else
						if s.vertstrongspring --Vertical boost.
							s.momz = $*40/33
						end
						if s.horstrongspring --Horizontal boost from a diagional spring.
							s.momx = $*5/4
							s.momy = $*5/4
						end
					end
				s.vertstrongspring = false
				s.horstrongspring = false
				s.horstrongspring2 = false
			end
		  end		
		  if (p.powers[pw_sneakers] and (s.battlemodsms or not G_PlatformGametype()))
				p.mxscap = 2
				if p.powers[pw_sneakers] == 699
					p.powers[pw_sneakers] = 698
					P_FlashPal(p, PAL_RECYCLE, 3)
					CONS_Printf(p, "\x82"+"Combat shoes powerup! Combat moves drain no rings for a while!")
					S_StartSound(s, sfx_steam2)
				end
		  else
				p.mxscap = 1
		  end
		  
		if p.sms_boostlevel
			if p.hypermysticsonic
			or not s.health --Can't do that, chief.
			or p.knucklewaving
				p.sms_boostlevel = 0
				s.sms_boostloss = 0
			elseif (p.sms_boostlevel > 32) and (p.sms_boostlevel < 66) --Almost there...!
			and (p.panim == PA_RUN)
			and P_IsObjectOnGround(s)
				local ghs = P_SpawnMobjFromMobj(s, FixedMul(24*s.scale, cos(s.angle+ANGLE_90)),FixedMul(24*s.scale, sin(s.angle+ANGLE_90)), 0, MT_SPINDUST)
				ghs.frame = SMSLocalRNG(4,2,s)-2|FF_TRANS10
				ghs = P_SpawnMobjFromMobj(s, FixedMul(24*s.scale, cos(s.angle-ANGLE_90)), FixedMul(24*s.scale, sin(s.angle-ANGLE_90)), 0, MT_SPINDUST)
				ghs.frame = SMSLocalRNG(0,2,s)|FF_TRANS10
			end
		end
		
		if ((p.cmd.buttons & BT_CUSTOM1) or p.sms_autoboosthold)
		and not (p.smsblastboost and not p.hypermysticsonic)
		and not (p.sms_ringburstfly == 1)
			
			//Super Sonic X Aura! ...or Ultra Instinct. Your pick!
				if p.panim == PA_IDLE
					if s.state == S_PLAY_STND
						if (s.tics == 1)
							s.tics = 9
						end
					elseif s.state == S_PLAY_WAIT			
						s.state = S_PLAY_STND
					end
				end
				if s.health
					s.smsglowticket = 2 --Are you not usually a glowing color? Well, you get to glow today!
				end	
				if (p.speed < 99*s.scale) and not (p.sms_boostlevel > 64) and s.health
					s.ssxaticket = true
				end		

				if G_GametypeHasSpectators()
							
					if p.rings
					and (p.sms_boostlevel < 65)
					and not p.gotflag
					and not p.smsblastboost
					and not (p.pflags & PF_STASIS)
					and not p.sms_dodging
					and not (s.eflags & MFE_UNDERWATER and not p.hypermysticsonic)
						if p.hypermysticsonic
							s.hmgodticket = true
							p.normalspeed = (242*FRACUNIT)
						else
							p.normalspeed = (121*FRACUNIT)/p.mxscap
						end

					elseif (((p.normalspeed != (60*FRACUNIT)/p.mxscap) and not p.hypermysticsonic)
					or (p.hypermysticsonic and (p.normalspeed != (120*FRACUNIT))))
					and not (p.sms_boostlevel >= 65)
					and not p.gotflag
						if p.hypermysticsonic
							p.normalspeed = (120*FRACUNIT)
						else
							p.normalspeed = (60*FRACUNIT)/p.mxscap
						end
						p.thrustfactor = 7
						p.sms_boostlevel = 0
					end				
					
				elseif s.health --NOT match modes.
				
					if (p.sms_boostlevel < 65)
					and not s.SMS_locked 
						if not ((s.eflags & MFE_UNDERWATER) and not p.hypermysticsonic)
						and not p.smsblastboost
							if p.hypermysticsonic
								s.hmgodticket = true
								p.normalspeed = (242*FRACUNIT)
							else
								p.normalspeed = (121*FRACUNIT)/p.mxscap
							end
						elseif ((p.normalspeed != (60*FRACUNIT)/p.mxscap) and not p.hypermysticsonic)
						or (p.hypermysticsonic and (p.normalspeed != (120*FRACUNIT)))
							if not (p.pflags & PF_STASIS) //No control? Wait a little bit!
								if p.hypermysticsonic
									p.normalspeed = (120*FRACUNIT)
								else
									p.normalspeed = (60*FRACUNIT)/p.mxscap //Normal speed. Still pretty speedy, though!
								end
							end
						end
					end
				end
				
		elseif p.smsblastboost --Base speed is barely over Sonic's in Legacy mode.
			p.normalspeed = (45*FRACUNIT)/p.mxscap
		end
		
		
		
			--last speed was...?	
			if not s.smsspeedticket and (p.speed > 78*s.scale)
				s.smsspeedticket = true
			end
			--Speed stats!
			if p.smsblastboost and not p.hypermysticsonic
			and not p.gotflag
			
				p.normalspeed = (45*FRACUNIT)/p.mxscap	
				p.runspeed = 26*FRACUNIT
				s.changedmyrsd = true
				
			elseif (((p.normalspeed != (60*FRACUNIT)/p.mxscap) and not p.hypermysticsonic) or (p.hypermysticsonic and (p.normalspeed != (120*FRACUNIT))))
			and (p.sms_boostlevel < 65)
			and not ((p.cmd.buttons & BT_CUSTOM1) or p.sms_autoboosthold) //Failsafe!
			and not p.gotflag
			
				if p.hypermysticsonic
					p.normalspeed = 120*FRACUNIT
				else
					p.normalspeed = (60*FRACUNIT)/p.mxscap
				end
			end 

			//When SMS holds a flag, nerf him please for the love of god!

			if (p.gotflag or (s.eflags & MFE_UNDERWATER))
			and not p.hypermysticsonic
				if p.gotflag
					p.normalspeed = 1965000/p.mxscap
					p.mindash = 40*FRACUNIT
					p.maxdash = 71*FRACUNIT
					p.sms_boostlevel = 0
					if (p.speed >= 88*s.scale) --No carrying over stupid amounts of momentum with the flag, pls...
					and not p.powers[pw_carry]
					and not (s.eflags & MFE_SPRUNG)
						P_InstaThrust(s, s.angle, 60*s.scale)
					end
				elseif (s.eflags & MFE_UNDERWATER)
					p.mindash = 64*FRACUNIT //Blinddash needs to be nerfed too.
				end
			elseif p.mindash == 40*FRACUNIT or p.mindash == 64*FRACUNIT
				p.mindash = 101*FRACUNIT
				if not p.hypermysticsonic
					p.maxdash = 147*FRACUNIT
				end
			end

			if not p.hypermysticsonic		
				if p.secondjump == 167 -- SMSblast springjump!
					if p.smsblastboost
						if (s.state == S_PLAY_ROLL) or (p.pflags & PF_JUMPED)
							s.state = S_PLAY_SPRING
							s.eflags = $|MFE_SPRUNG
							p.pflags = $ & ~PF_JUMPED
						elseif (s.state == S_PLAY_SPRING) and (s.momz*P_MobjFlip(s) > 5*s.scale)
							SMSRSpawnGhost(s, SMSLocalRNG(3,4,s))
						end
					else
						p.secondjump = 0
					end
				end
				--Speed Thok animation!
			  	if s.smsthokanim
		  			if p.panim == PA_ROLL or p.panim == PA_JUMP or p.panim == PA_FALL
		  	 			s.state = S_SMSTHOKANIM
						if not p.sms_oldhoming
							if not p.homing and (p.pflags & PF_THOKKED)
								local ghs = SMS_FollowCircle(s, SKINCOLOR_WHITE, 3)
								ghs.scalespeed = $*2 ghs.fuse = 9 ghs.frame = $-FRACUNIT
								if not (s.SMS_squashtable and s.SMS_squashtable.timer > 2)
									S_StartSoundAtVolume(s, sfx_s1b8, 76)
								end
							end
							if not (s.SMS_squashtable and s.SMS_squashtable.timer > 2)
								s.spritexscale = FRACUNIT-5100
								s.spriteyscale = FRACUNIT+9100
								s.spriteyoffset = 0
								s.SMS_squashtable = {timer = 3, Xspeed = 2200, Yspeed = 3500, air = true}
							end
						end
						if (p.cmd.buttons & BT_SPIN) and not p.smsblastboost
							s.tics = 2
						end
						p.pflags = $|PF_JUMPED
					end
		  		 	s.smsthokanim = false
		 	 	end
				--Speed Shoes mode! Go into SMS' All Out mode once you collect runshoes!
				if G_PlatformGametype() and not s.battlemodsms
					SMS_AllOutMode(s, p)
				end
		  end

			//When sprinting across the ground for an extended periods of time, you can break your
			//"speed limit". We'll call it "Speed Break" for now, after Sonic and the Secret Rings' boost move. 
			
			local fail = false
				
			--Conditions to lose boostlvl.
			
			if P_IsObjectOnGround(s) --Can only lose boostmode on the ground.
			and (p.panim != PA_ROLL) and (s.state != S_SMS_AIRBOOST) --You're exempt when rolling!
				if ( (p.speed < 27*s.scale) and (twodlevel or (s.flags2 & MF2_TWOD)) ) --2D fall-off limit is lower.
				or (p.speed < 63*s.scale)
					fail = true
				end
			end
			if fail != true		
				if (p.panim == PA_PAIN)
				or (p.panim == PA_RIDE) --Instantly lose boostlevel in these conditions.
				or p.smsblastboost
					fail = true
				end
			end
					
			if fail == true --Lose boostmode when going too slow!	
			
				if not s.smsboostimmune --Can't lose boostmode with this active!
					p.sms_boostlevel = 1 --Set to 1, not 0.	p.sms_boostlevel = 0
				end
				
				--Calculate if we can gain boostlvl!				
			else
				if (p.speed >= 26*s.scale)
					if (p.cmd.buttons & BT_CUSTOM1) or p.sms_autoboosthold --Correct input present?
						if (s.flags2 & MF2_TWOD) or twodlevel or (p.speed >= 78*s.scale) --Speed limit
							
							if (p.panim == PA_RUN) --Usually can only gain boostlvl on the ground.								
							or P_IsObjectOnGround(s) --The run animation makes you exempt, though.

							or (leveltime % 3 == 0) --And you can always get a passive gain up to a certain point!
							and (p.sms_boostlevel < 60) --But it won't break you over the edge.
							and not p.sms_ringburstfly
								
								s.sms_addboostlevel = 1
									
								--Really fast speed gains you superlvl!
									
								if (p.speed > 105*s.scale)
								or ((s.flags2 & MF2_TWOD) or twodlevel) and (p.speed >= 39*s.scale)
									s.sms_addboostlevel = 3
								end									
							end
						end
					end
				end
			end	
			
			--Main Boost code!
			if (p.sms_boostlevel >= 65) //If the "timer" hits 65, Speed Break!
			and not p.hypermysticsonic //HMS doesn't use boostlevel, but just incase.
			and s.health
			
				s.sms_boostloss = 12
				
				if (p.pflags & PF_STARTDASH) and (p.dashspeed < p.maxdash)
					p.dashspeed = p.maxdash //Instant maxdash
					S_StartSound(s, sfx_spndsh)
					A_SMSquake(s, 65*FRACUNIT, 3, 500, true)
				end
			
				p.thrustfactor = 10	--Super acceleration for improved turning speed!
				
				//Haymaker check.
			
				local ghs = P_SpawnMobj(s.x+FixedMul(570*FRACUNIT,cos(s.angle)), s.y+FixedMul(570*FRACUNIT,sin(s.angle)), s.z-600*FRACUNIT, MT_SMSECHECK)
				if ghs and ghs.valid
					ghs.cmphsms = true
					ghs.justcheckin = true
					ghs.target = s
					ghs.height = 1200*FRACUNIT
					ghs.radius = 660*FRACUNIT
				end
				
				--Drifting, kicking up smoke and debris from the turning speed!
				if p.hypermysticsonic
				
					p.normalspeed = 310*FRACUNIT --HMS doesn't use the boost mechanic, but just incase....
					
				elseif (s.state != S_SMS_ATOMDIVE)
				
					if P_IsObjectOnGround(s)
					and ((s.state >= S_SMS_BOOST01) and (s.state <= S_SMS_BOOST04))
					
					local drifting = false
					local momangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
					local turnang = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
					local trueturn = abs(((momangle-turnang) or 1)/ANG1)			
						if (trueturn > 17) --Turning sharply at Speed Break? Drift!
							if not s.driftsens
								s.driftsens = 2
							else
								s.driftsens = min($+2, 8)
							end
							
							drifting = true
							
							if (s.driftsens > 2) //Spam drifting sounds and smoke!
						
								local ghs = P_SpawnMobjFromMobj(s, SMSLocalRNG(-67, 67,s)*s.scale, SMSLocalRNG(68, -67,s)*s.scale, 0, MT_TNTDUST)
								if ghs and ghs.valid
									P_Thrust(ghs, s.angle+ANGLE_90, 30*s.scale*SMSLocalRNG(-1,1,s)) 
									ghs.scale = $/SMSLocalRNG(1,4,s)
									ghs.destscale = $*5
									ghs.fuse = 42
									
									local ths = P_SpawnMobjFromMobj(s, SMSLocalRNG(-67, 67,ghs)*s.scale, SMSLocalRNG(-68, 67,ghs)*s.scale, 0, MT_SPINDUST)
									if ths and ths.valid
										P_Thrust(ths, s.angle+ANGLE_90, 30*s.scale*SMSLocalRNG(-1, 1, ghs)) 
										ths.scale = $*SMSLocalRNG(1,3,s)
										ths.frame = $+SMSLocalRNG(0,2,ths)
										ths.destscale = $*5
										ths.tics = 8
									end									
								end
							
								--Sound object!
								if not (s.smssoundobj and s.smssoundobj.valid)
								and not (s.eflags & MFE_UNDERWATER)
									s.smssoundobj = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_SMSSOUNDOBJ)
									s.smssoundobj.master = s
									s.smssoundobj.health = 1
									S_StartSound(s.smssoundobj, sfx_smsdr)
									s.smssoundobj.smsdrtim = 65
								end
							end
						end
					end
					
					p.normalspeed = (155*FRACUNIT)/p.mxscap
					
					SMSRSpawnGhost(s, 8) --Boostmode-specific afterimage ghosts.
					
					if (p.panim == PA_RUN)
						s.state = S_SMS_BOOST01
					end	
				end
			elseif (p.thrustfactor != 7)
			and not (p.powers[pw_sneakers] and (G_PlatformGametype() and not s.battlemodsms))
				p.thrustfactor = 7			
			end
			if s.driftsens
				s.driftsens = $-1
				if (p.pflags & (PF_JUMPED|PF_SPINNING))
				or not s.driftsens
					s.driftsens = 0
					if (s.smssoundobj and s.smssoundobj.valid and s.smssoundobj.health)
						s.smssoundobj.state = S_NULL --Delete sound object.
					end
				end
			end
			if (s.state >= S_SMS_BOOST01) and (s.state <= S_SMS_BOOST04)
				if (p.speed < 69*s.scale)
					s.state = S_PLAY_RUN
					s.driftsens = 0
					if s.smssoundobj and s.smssoundobj.valid
						s.smssoundobj.state = S_NULL --Delete sound object.
					end
				end
			elseif (p.sms_boostlevel >= 65)
				if (s.eflags & MFE_UNDERWATER) or p.smsblastboost //No speed break underwater!
					p.sms_boostlevel = 0
				else
					if (p.pflags & PF_STARTDASH)
						if (p.speed < s.scale*8)
							s.SMS_BDboostloss = true --Can't haymaker with this!
						end
					elseif s.SMS_BDboostloss --Jumping out of a charge dash will lose you boostmode.
						if (p.pflags & PF_JUMPED)
						and (p.cmd.buttons & BT_SPIN)
						and (p.speed < s.scale*55)
						and not (p.sms_dodging > 12)
							p.sms_boostlevel = 43 //But retain some	boostlvl
							s.sms_boostloss = 12
						end
						s.SMS_BDboostloss = nil
					end
				end
			end

			//Forces afterimages when at extreme speeds regardless of what.
			//Also, if you have the flag and go beyond a certain speed, slow dooown!
			--Spawn windlines?
			local GOTSPEED
			
			if (p.speed >= 52*s.scale)
			and not (p.pflags & (PF_SPINNING|PF_SLIDING))	
			and not p.powers[pw_carry]
			and not (s.eflags & MFE_GOOWATER)
			and not p.homing
			and not p.smsblastboost
			and not p.sms_comethaymaker
			
				if (p.cmd.buttons & BT_CUSTOM1) or p.sms_autoboosthold
					s.smsspeedticket = true --This spawns windlines later.
					if not (p.sms_boostlevel > 65) and not (s.hmsspinpass and p.hypermysticsonic)
						SMSRSpawnGhost(s, 2, true) --Minor ghost!
					end	
				end
				
				if (p.speed >= 140*s.scale)
				and P_IsObjectOnGround(s)
					SMSRSpawnGhost(s, 5) --Strong afterimage!
					GOTSPEED = true
					s.smsspeedticket = true
					if (p.sms_boostlevel >= 65)
						A_SMSSpinFire(s, MT_SMSSPINFIRE, FRACUNIT/2)
						if not (s.scale < FRACUNIT/2) --If we're not tiny, play speeding sounds.
							s.smsgbs = s.smsgbs and $+1 or 1
							if not (s.smsgbs > 14)
								if s.smsgbs == 1
									if not ((s.smssoundobj4 and s.smssoundobj4.valid and s.smssoundobj4.health)
									and s.smssoundobj4.machwbtol2 and (s.smssoundobj4.machwbtol2 < 50))
									and not (s.eflags & MFE_UNDERWATER)
										s.smssoundobj4 = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_SMSSOUNDOBJ)
										s.smssoundobj4.master = s
										s.smssoundobj4.health = 1
										S_StartSound(s.smssoundobj4, sfx_machwb)
										s.smssoundobj4.smsmachwb = 1
									end
									for i = 1,2
										if (p.sms_boostlevel < 106)
											local ghs = SMS_FollowCircle(s, SKINCOLOR_RED, 1+i)
											ghs.scalespeed = FRACUNIT-9900
											ghs.frame = $ & ~FF_TRANSMASK
											ghs.fuse = 10
											ghs.dispoffset = 35
											if i == 1
												SMS_QuickDustGFX(s, SKINCOLOR_EMERALD)
											else
												SMS_MediumDustGFX(s)	
											end	
										end
									
										local ghs = HMS_BigBangVortex(s, 10, nil, nil, T|(FF_TRANS50+(i*FRACUNIT)), s.color) --Subtle vortex?
										ghs.tracer = s
										ghs.dispoffset = -20
										if i == 2
											ghs.ditchtracer = 1
											ghs.momx = s.momx/2
											ghs.momy = s.momy/2
											ghs.spritexscale = $-12000
											ghs.spriteyscale = $-12000
										end
										ghs.color = SMSisyellow(s) and SKINCOLOR_MYSTICAL1 or s.color
									end
								end
								local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_SMSGROUNDBOOST)
								ghs.tracer = s
								ghs.blendmode = AST_ADD
								ghs.smsgbs = s.smsgbs
							end
						end
					end
				end
			end
			if s.smsgbs
				if not GOTSPEED
					s.smsgbs = 0
				end
			end

			//It's a bird, it's a plane, it's SUUUUPER SONIC! ...huh?
			//Actually, SMS can't fly. But he can definitly use the Air Boost. 

			if p.sms_readyairboost		
				if P_IsObjectOnGround(s)
					p.sms_readyairboost = 0
				elseif not p.sms_instantairboost
				and not ( p.sms_c1
				or (p.sms_jumphold >= 1 and (p.pflags & PF_THOKKED)) )
					p.sms_readyairboost = $-1 //Not holding dash? Then count down!
					s.readyairboostdelay = false
				end
			end
			if p.sms_didairboost
				if P_IsObjectOnGround(s)
					p.sms_didairboost = 0 
				else
					if (p.sms_didairboost > 0)
						if (p.pflags & PF_JUMPED)
						or (s.state ~= S_SMS_AIRBOOST) and not ((s.state == S_PLAY_FALL) and (s.momz*P_MobjFlip(s) < s.scale/5))
							p.sms_didairboost = 0 --Reset the SMS_didairboost state!
						else
							p.sms_didairboost = max($-1, 1)  --keep it edged at 1
							if (p.sms_didairboost > 5) and (s.state == S_SMS_AIRBOOST)
								if (yu.direct > 20) --Allow a bit of supercontrol!
								and (abs(p.cmd.sidemove) > 7)
								and not (p.cmd.forwardmove < -32)
									local FLYANGLE = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
									local ANGSHIFT,PLUS = SMS_AngleDifference(FLYANGLE, yu.turnang, 2, ANGLE_45, 2)
									FLYANGLE = $-(ANGSHIFT*PLUS)
									local MOMENTUM = p.speed/4
									s.momx = FixedDiv(FixedMul($, 100), 127)
									s.momy = FixedDiv(FixedMul($, 100), 127)
									P_Thrust(s, FLYANGLE, MOMENTUM)
								end
							end
							if (p.cmd.buttons & BT_JUMP) and (p.sms_jumphold <= 2)
							and not (p.sms_oldhoming and not (p.cmd.buttons & BT_USE))
								if SMS_TryForcedHomingAttack(s, p)
									s.SMS_DLtrail = {timer = 5, colorized = true,
									spriteyscale = FRACUNIT-19000,
									spritexscale = FRACUNIT-16000,
									spriteyoffset = 4*FRACUNIT,
									scalespeed = FRACUNIT/30,
									fuse = 12,
									COLORT_trail = {SKINCOLOR_MYSTICAL4, SKINCOLOR_MYSTICAL4, SKINCOLOR_ORANGE, SKINCOLOR_RED, SKINCOLOR_EMERALD, SKINCOLOR_LIME},
									COLORT_trailmax = 5} 
									
									s.spritexscale = FRACUNIT-11500
									s.spriteyscale = FRACUNIT+14000
									s.SMS_squashtable = {timer = 5, Xspeed = 4500, Yspeed = 5000, air = true}
									
									S_StartSound(s, sfx_thok)
									p.actionspd = skins[s.skin].actionspd
									p.charflags = $ & ~SF_MULTIABILITY
									p.pflags = $|PF_THOKKED
								end
							end
						end
					end
					if (s.SMS_WJpenalty > 105)
						s.SMS_WJpenalty = $-3 --Count down superquick, but suffer a big minimum penalty.
					elseif not (s.eflags & MFE_SPRUNG)
						s.SMS_WJpenalty = 105
					end
				end

			elseif ( p.sms_c1 == 1
			or (p.sms_jumphold == 1 and (p.pflags & PF_THOKKED) and not (p.cmd.buttons & BT_SPIN) and not p.sms_instantairboost) )

			and ((p.pflags & PF_JUMPED) or p.hometrickanim or p.panim == PA_SPRING or p.panim == PA_FALL)

			and not P_IsObjectOnGround(s)
			and not p.hypermysticsonic

				p.sms_tapnothold = $+1 //The second timer, just for this one move. Needed for the alt control schemes.

				if not p.sms_readyairboost
					if not (p.sms_tapnothold > 2)
						if (p.cmd.buttons & BT_CUSTOM1) 
						and not ((p.pflags & PF_THOKKED) and (p.cmd.buttons & BT_JUMP) and not p.sms_jumphold and not (p.cmd.buttons & BT_SPIN))
							p.sms_readyairboost = 4
						else
							p.sms_readyairboost = 10
						end
						if p.sms_instantairboost
							s.readyairboostdelay = false
						else
							s.readyairboostdelay = true
						end
					end
				end
			    if not s.readyairboostdelay and p.sms_readyairboost //These essentially create the sensitivity
			    	if (p.sms_tapnothold < 4)
						if not SMS_Locked(s, p, true) //Panicking people double-tap boost after walljumps, apparently. Stop them, magic script!
						and not p.sms_afterstompthok
						and not p.sms_stompanim	
						
						and not ( ((p.sms_tapnothold > 3) and not ((p.pflags & PF_THOKKED) and (p.cmd.buttons & BT_JUMP)
						and not p.sms_jumphold and not (p.cmd.buttons & BT_SPIN)))
		
						or (p.sms_tapnothold > 5) )
						and not p.smsblastboost
						and not (s.SMS_WallJumpTable and (s.SMS_WallJumpTable.timer > 19))
						and not (p.hookring and (p.cmd.buttons & BT_CUSTOM1))
							SMS_DoAirBoost(s, p)
						end
					end
			    end
			elseif p.sms_tapnothold
				p.sms_tapnothold = 0
			end

			//Water running! Looks like they finally gave up on removing the runonwater ability after Lua, 
			//so there goes the need for my fancy run-on-water custom code...

			if p.homing
			or p.gotflag
			or p.smsdivetimer
			or s.sdodgeoh
			or (p.pflags & PF_SLIDING)
			or (p.panim == PA_PAIN)
				p.charflags = $ & ~SF_RUNONWATER
				s.smsframejump = 0
			else //if not ((p.pflags & PF_SLIDING) or (p.panim == PA_PAIN))
				p.charflags = $|SF_RUNONWATER
				
				//When going fast enough, SMS'll slide over the water!
				if (s.eflags & MFE_TOUCHWATER) and (p.speed > 35*s.scale)
					if not (s.eflags & (MFE_GOOWATER|MFE_SPRUNG|MFE_UNDERWATER)) //Too much friction on solid water for this.
					and P_IsObjectOnGround(s)
					and not (p.pflags & (PF_SPINNING|PF_JUMPED|PF_STARTDASH|PF_SLIDING))
					and not p.hypermysticsonic
					and not p.sms_stompanim
					and not p.homing
					and not (s.momz*P_MobjFlip(s) > 0)
					and s.health
						if (s.eflags & MFE_JUSTHITFLOOR)
						and not (s.SMS_squashtable and s.SMS_squashtable.timer > 5)
						
							local ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_THOK)
							ghs.flags2 = MF2_DONTDRAW ghs.tics = 88 ghs.fuse = 88
							
							S_StartSound(ghs, sfx_bubbl5)
							S_StartSound(ghs, sfx_bubbl3)
							S_StartSoundAtVolume(ghs, sfx_splish, 110)
							
							SMS_QuickDustGFX(s, SKINCOLOR_SILVER)
							SMS_QuickDustGFX(s, SKINCOLOR_SILVER, nil, nil, s)
					
							s.spritexscale = FRACUNIT+2200
							s.spriteyscale = FRACUNIT-2200
							s.spriteyoffset = -14*FRACUNIT
							s.SMS_squashtable = {timer = 14, Xspeed = 120, Yspeed = 120, ground = true}						
						end
						if (p.speed > 75*s.scale)
							if (s.state != S_SMSWATERGRIND1) and (s.state != S_SMSWATERGRIND2)
								s.state = S_SMSWATERGRIND1
							end
							if not (p.cmd.forwardmove > 0)
								s.forcesmsangletimer = 2
								s.forcesmsangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
							end	
						end
						s.smsspeedticket = true
						if s.SMS_squashtable and s.SMS_squashtable.timer == 3
							SMS_QuickDustGFX(s, SKINCOLOR_SILVER, nil, nil, s)
						end
						if (leveltime % 5 == 0)
							SMS_QuickDustGFX(s, SKINCOLOR_SILVER, nil, -3*FRACUNIT)
						end
						if not s.smsspeedticket
							SMSWindLines(s, p, true)
						end
					end
				end
				if (s.state == S_SMSWATERGRIND1) or (s.state == S_SMSWATERGRIND2)
					--We shouldn't be sliding anymore...
					if ((p.speed < 75*s.scale) or not (s.eflags & MFE_TOUCHWATER))
					and not (s.eflags & MFE_SPRUNG)
						s.state = S_PLAY_RUN
					end
				end
			end
			if (p.cmd.buttons & BT_CUSTOM2) --Button checks. Using 2 of these for conflicting ability mo
				p.smsmeleebutton = $+1
				p.smsmeleebutton2 = $+1
			else
				p.smsmeleebutton = 0
				p.smsmeleebutton2 = 0
			end

			//Stomp Attack, Hyper Mystic version!
			if p.hypermysticsonic 
				if (p.hypermysticsonic > 40) //No HMS? No HMS stomp.
					HMS_stomp(s, p)
				end
			else --SMS Stomp Attack! Super Mystic version!
				s.stompnegatedinput = nil
				if (p.cmd.buttons & BT_CUSTOM2) and not (p.smsmeleebutton > 1)
				and not (s.SMS_WallJumpTable and (s.SMS_WallJumpTable.timer > 19))
					SMS_stomp(s, p) --SMSstomp
				end
				if (s.state == S_SMS_STOMP1)
				or (s.state == S_SMS_STOMP2)
					if (s.eflags & MFE_GOOWATER) --Roll up if you hit goowater.
						p.sms_stompanim = 0
						p.hometrickanim = false
						p.sms_afterstompthok = false
						if P_IsObjectOnGround(s)
							s.state = S_PLAY_FALL
						else
							s.state = S_SMS_ADVFALL1
						end
					end
					if not p.sms_stompanim
					and not p.powers[pw_carry]
						if not P_IsObjectOnGround(s)
							p.pflags = $|PF_JUMPED
							s.state = S_PLAY_ROLL
						else
							s.state = S_PLAY_FALL
						end
					end
				end
			end
			if (p.sms_stompanim or p.sms_afterstompthok)
				SMS_Stomping(s, p)
				SMS_StompGFX(s, p)
				if p.sms_stompanim
					
					if p.sms_afterstompthok
					
						p.hometrickanim = false
						p.sms_stompanim = 0 --SMS can still thok out of a stomp!
						if (s.state == S_SMS_STOMP1) or (s.state == S_SMS_STOMP2)
						or ((p.panim == PA_FALL) and (s.momz*P_MobjFlip(s) < -10*s.scale))
							if not P_IsObjectOnGround(s)
								s.state = S_SMSTHOKANIM
							end
						end
						
					elseif not P_IsObjectOnGround(s)
					
						if (p.panim == PA_FALL) and (s.momz*P_MobjFlip(s) < -10*s.scale) --Won't allow it.
							s.state = S_SMS_STOMP1
						end
						if (p.cmd.buttons & BT_JUMP) --THOK out of a stomp!
							if (p.sms_jumphold <= 1)
							or (p.pflags & PF_THOKKED) and (p.pflags & PF_JUMPED) and p.sms_jumphold <= 3						
								if (s.state == S_SMS_STOMP1 or s.state == S_SMS_STOMP2)
								and not (s.eflags & (MFE_JUSTHITFLOOR|MFE_SPRUNG))		
									if not P_IsObjectOnGround(s) and not p.powers[pw_carry]
										s.state = S_SMSTHOKANIM --Remove PF_JUMPDOWN to make the game instantly thok!
										p.pflags = $|PF_JUMPED & ~(PF_JUMPDOWN|PF_THOKKED|PF_STARTJUMP)
									end
									p.sms_stompanim = 0
									p.hometrickanim = false
									p.sms_afterstompthok = true
								end
							end
						end
					end
				end
			end

//Hold Spindash in midair to homing attack!
//This used to be LUA_HMAT

			if (p.cmd.buttons & BT_JUMP) --button timer?
				p.sms_jumphold = $+1
			elseif p.sms_jumphold
				p.sms_jumphold = 0
			end
			
			--2D mode parameters. Ugh...
			if (s.flags2 & MF2_TWOD) or twodlevel
				if (p.homing or p.smsrdash)
					s.momy = 0 // Prevent 2D shifts into 3D by accident.
				end
			end
			
			--Homing Attack secondary behaviour.
			if (p.homing > 5)
			p.homingtrickcharge = 4
				if p.speed --For momentum use later!
					s.SMShomingspeed = p.speed
					s.SMShomingangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)  
				end
				
				if s.battlemodsms
				and s.tracer
				and ((s.tracer.type == MT_PLAYER) or (s.tracer.type == MT_TARGETDUMMY)) //We're going after a target dummy? ...kay then.
					if (p.homing > 49) //It hurts how broken the homing attack is in battlemod. SMS is a superform, but we STILL need to nerf it
						S_StartSound(s, sfx_s3k72)
						s.momx = 0 s.momy = 0
						P_SetObjectMomZ(s, 2*FRACUNIT)
						local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_BURSTLIGHT)
						ghs.color = s.color
						ghs.blendmode = AST_ADD
						p.homing = 49
						S_StartSound(s, sfx_spndsh)
					elseif (p.homing > 41)
						P_InstaThrust(s, s.angle, -FRACUNIT)
						P_SetObjectMomZ(s, FRACUNIT, false)
					elseif (p.homing == 41)
						s.playerhomecharge = true
						S_StartSound(s, sfx_cdfm62)
						if not (s.tracer and (FixedHypot(FixedHypot(s.x-s.tracer.x, s.y-s.tracer.y), s.z-s.tracer.z) < 900*FRACUNIT))
							P_InstaThrust(s, s.angle, 40*FRACUNIT)
							P_SetObjectMomZ(s, -20*FRACUNIT, false)
							p.homing = 0
							s.playerhomecharge = false
							s.playerhomechargefail = 21		
						end
					end				
			 	elseif (s.eflags & MFE_UNDERWATER)
					s.momx = $*5/7 s.momy = $*5/7 s.momz = $*5/7
				elseif (s.z-(s.momz*5/3) > s.floorz) and not p.hometrickanim
					s.momx = $*5/3 s.momy = $*5/3 s.momz = $*5/3 //Home faster than your average homing attack!
				end
				
			elseif s.playerhomechargefail
			
				s.playerhomechargefail = $-1
				if P_IsObjectOnGround(s)
					s.playerhomechargefail = 0
					s.flags2 = $|MF2_DONTDRAW
					s.momx = $/2
					s.momy = $/2
					A_SMSSTOMPSMOKE(s, 18, MT_SPINDUST)
					A_SMSSTOMPSMOKE(s, 38, MT_SPINDUST)
					P_SetObjectMomZ(s, 4*FRACUNIT, false)
					S_StartSound(s, sfx_cdfm14)
					p.pflags = $|PF_JUMPED|PF_THOKKED & ~PF_SPINNING
					s.state = S_PLAY_ROLL	
				end
				
			elseif s.playerhomecharge
				if s.battlemodsms and (p.homing == 1) and (p.pflags & PF_JUMPED)
					SMSRSpawnGhost(s)
					s.state = S_PLAY_FALL
					p.pflags = $ & ~PF_JUMPED & ~PF_THOKKED
				end
				if s.tracer and ((s.tracer.type == MT_PLAYER) or (s.tracer.type == MT_TARGETDUMMY))
					if not P_IsObjectOnGround(s)
						P_SetObjectMomZ(s, 10*FRACUNIT, false)
						if (p.panim == PA_FALL)
							p.sms_wallstat = 50 //You screwed up. Apply cooldown
							s.retmhtsfx = 48
							s.smsstompcd = 15
							P_InstaThrust(s, R_PointToAngle2(s.x, s.y, s.tracer.x, s.tracer.y), -16*s.scale)
							p.sms_flamedelay = 15 //Set this or it'll become the new meta instead.
							p.powers[pw_nocontrol] = 0
							s.recoilthrust = 0 //I'll do this manually, thanks
							p.pflags = $|PF_JUMPED|PF_THOKKED
							s.state = S_PLAY_ROLL
						else
						p.sms_wallstat = 50 //You screwed up. Apply cooldown
						s.retmhtsfx = 48
						s.smsstompcd = 15
						p.pflags = $|PF_JUMPED|PF_THOKKED
						s.state = S_PLAY_ROLL
					//	s.forcesmstrick = true				
					//	if (s.momz*P_MobjFlip(s) > (FixedMul(10*FRACUNIT, s.scale)))
						end				
					end
				end
				s.playerhomecharge = false
			end

			if p.hometrickanim
				if not ((s.state >= S_SMS_PREHOMET1) and (s.state <= S_SMS_SIDET))
				or P_IsObjectOnGround(s) and not (s.momz*P_MobjFlip(s) > 0)
				or p.hypermysticsonic
					p.hometrickanim = false
					p.homingtrickcharge = 0
				else --Homing Trick Aura. The SA2 jump aura, pretty much!
					SMS_SA2JumpTrail(s)
				end
			elseif p.homingtrickcharge
				p.homingtrickcharge = $-1
			end

			--Currently walljumping! The wall jump stat keeps track of alot of stuff.
			--NOTE: This has NOTHING to do with walljumps anymore, and is only kept as a stun tracker for other actions.
			if p.sms_wallstat
				SMS_WallJumpStats(s,p)
			end

			//Thok against a wall while holding spin to do a super walljump!

			if not p.hypermysticsonic //No walljump when HMS!
			and not p.homing			
				//Water vaporizes off SMS' body if he steps in it.
				if not SMSSHIELD(p, SH_ELEMENTAL, SH_BUBBLEWRAP)
					if P_PlayerTouchingSectorSpecial(p, 1, 3)
						p.sms_steaming = 200
						p.sms_steamingwait = 0 //You can't drip water from lava, dipshit.				
					elseif ((s.eflags & MFE_UNDERWATER)
					or ((s.eflags & MFE_TOUCHWATER) and (p.pflags & PF_SPINNING)))
						p.sms_steaming = 200
						p.sms_steamingwait = 35
					end
				end
				if s.SMSwallslideCD --Stops you from losing ALL speed when scraping walls....for a while.
					s.SMSwallslideCD = $-1
				end
				if s.sms_tauntcooldown
					s.sms_tauntcooldown = $-1
				end		
				p.spinitem = MT_SMSBLINDDASH --Default spin item.
				--The Lightdash move! Can be used with golden shoes!
				if p.lightdashenable
					SMS_LightDash(s, p)
				end	
				
				--Adding the framejump property here! You could call this the main IsObjectOnGround check, btw!
				if P_IsObjectOnGround(s)
					s.smsframejump = 10
					s.sms_painr = 0
					s.SMS_lastwallANG = nil
					s.SMS_lastwallNUM = nil
					s.SMS_WJpenalty = 0
					--Fix for sheer animation stupidity.
					if (s.state >= S_SMS_PREHOMET1) and (s.state <= S_SMS_AIRBOOST)
					and not (s.momz*P_MobjFlip(s) > 0)
						s.state = (p.pflags & (PF_SPINNING|PF_STARTDASH)) and S_PLAY_ROLL or (p.speed > 32*s.scale) and S_PLAY_RUN or S_PLAY_WALK
					else
						if p.speed == 0 or (p.panim == PA_IDLE) --Standing still on the ground?
							if (s.state != S_SMSTAUNT1)
								SMS_IdleBehaviour(s, p) --Do your idle behaviours.
							end
						end
					end
					
				else --if not P_IsObjectOnGround(s) --Main air check if you will.
				
					p.charability = CA_HOMINGTHOK --Always have this ready for the sake of lock-on.
					p.charflags = $|SF_MULTIABILITY --multiability must be active for the lock-on marker too.			
					
					--Didn't rename the prev version for backwards compatibility.
					p.sms_weaponnexthold = (p.cmd.buttons & BT_WEAPONNEXT) and $+1 or 0	
				
					if (p.pflags & PF_THOKKED)
						if (p.pflags & PF_JUMPED)
							if (s.SMS_WJpenalty > 90)
								if (s.momz*P_MobjFlip(s) < -s.scale*4)
									s.SMS_WJpenalty = $-2
									if (p.speed > 56*s.scale)
										s.SMS_WJpenalty = $-2 --rewards for cool-looking play.
									end
									if (s.momz*P_MobjFlip(s) < -s.scale*12)
										s.SMS_WJpenalty = $-1
									end
								end
							else
								s.SMS_WJpenalty = max($, 40) --Minor minimum penalty.
							end
						elseif (p.panim == PA_FALL) and not p.smsatomicdivefail
						and not p.powers[pw_carry] and not P_IsObjectOnGround(s)
							p.pflags = $|PF_JUMPED
							s.state = S_PLAY_ROLL
						end
					end	
					
					if (s.state == S_PLAY_FALL)											
							if ((p.cmd.buttons & BT_JUMP) and (p.sms_jumphold < 5)
							or (p.cmd.buttons & BT_CUSTOM2) and p.smsmeleebutton < 2)
							and not SMS_Locked(s, p, true)
							and not p.hometrickanim
							and not ((p.pflags & PF_JUMPED) and not (p.pflags & PF_NOJUMPDAMAGE))
							and not p.sms_dodging --At ALL.
							and not p.smsatomicdivefail
							and not p.smsblastboost
							
								if p.sms_didairboost --Okay, fine, but you're not spamming it...
									p.sms_didairboost = -7
								end
								p.hometrickanim = true
								p.homingtrickcharge = 0
								p.pflags = $|PF_JUMPED & ~PF_JUMPDOWN
								if (p.cmd.buttons & BT_CUSTOM2) and (p.smsmeleebutton < 2)
								and not (s.SMS_WallJumpTable and (s.SMS_WallJumpTable.timer > 19))
									SMS_stomp(s, p)
								end
								
							else
							
								--Old janky Dust devil code. We have CR_DUSTDEVIL now.
								if not ((s.momz*P_MobjFlip(s) > 17*s.scale) and (s.momz*P_MobjFlip(s) < 22*s.scale))
									if s.iampickedupbysmshelp
									or s.cmphttimer
										s.tornadoretcharge = 50
									elseif s.tornadoretcharge == nil
										s.tornadoretcharge = 0
									end
									s.tornadoretcharge = $+1
								elseif s.tornadoretcharge
									s.tornadoretcharge = 0
								end
								
								--Anyway, try doing a homing attack trickjump!
								if (s.tornadoretcharge == nil or (s.tornadoretcharge < 2))
								and (s.momz*P_MobjFlip(s) > 17*s.scale)
								and not s.iampickedupbysmshelp
								and not s.cmphttimer
									SMS_HomingTrick(s,p) --Do a homing trick!
								end	
								if s.tornadoretcharge
									s.tornadoretcharge = 0
								end
							end
					end
						
					p.thokitem = MT_SMSAURATRAIL
					if (p.cmd.buttons & BT_SPIN) or s.SMS_WJauto
						if ((p.pflags & PF_JUMPED) or p.sms_stompanim or p.hometrickanim
						or (s.state == S_SMS_AIRBOOST) 
						or (p.panim == PA_FALL))
						and not p.smsblastboost
							SMS_WallJumpCheck(s,p)
						end
					end
				end

				//Fancy tricks! Yesh!

				if p.homingtrickcharge
				and ( ( (p.pflags & PF_JUMPED) and (p.pflags & PF_NOJUMPDAMAGE)
				and ((p.speed < 22*s.scale))
				and ( (s.momz*P_MobjFlip(s) > 2*s.scale) or (s.eflags & MFE_UNDERWATER)) ) or s.forcesmstrick )
				
					SMS_HomingTrickJump(s, p, nil)				
					
				elseif p.hometrickanim --Doing tricks!
				and not P_IsObjectOnGround(s)
				
					if (s.state == S_SMS_SIDET) and not s.airboostroll
						s.smstrickroll = true --Currently rolling, yes...
						SMS_TrickRoll(s, p, 16*FRACUNIT, true)
					end
				
				elseif s.smstrickroll
					if not s.airboostroll
						s.rollangle = 0
					end
					s.smstrickroll = false
				end


			//Lets group of a bunch checks behind this for better performance.
			//Better than doing P_IsObjectOnGround 500 times...
				
				if p.panim == PA_PAIN
					if P_PlayerInPain(p) --Not while in a waterslide, tho.
						s.sms_painr = s.sms_painr and $+1 or 1
						p.sms_stompanim = 0
						p.sms_afterstompthok = false
					else
						s.sms_painr = 0
					end

					//YOU MUST RECOVER! Press the jump button to undo potential insta-murder. 
					//I feel every character should have this, but alas, this is SMSreborn, not EverybodyReborn...					
					if s.sms_painr and (s.sms_painr > 28) //If the timer is 29(or higher), YOU MUST RECOVER!!
						if not (p.pflags & PF_SLIDING)
							if (p.cmd.buttons & BT_JUMP) //Ability only starts when you press jump.
							and not p.powers[pw_nocontrol]
								s.airboostroll = 0
								s.rollangle = 0
								s.state = S_PLAY_ROLL
								P_SetObjectMomZ(s, 9*FRACUNIT, false)
								P_DoJump(p, true)
								P_SetObjectMomZ(s, 138500, true) //Slightly higher than a normal jump.
								s.sms_painr = 0 //Bring back painrecovery to 0.
								if not s.SMS_squashtable
									s.spritexscale = FRACUNIT-11100
									s.spriteyscale = FRACUNIT+13500
									s.spriteyoffset = FRACUNIT+6
									s.SMS_squashtable = {timer = 3, Xspeed = 4500, Yspeed = 5000, air = true}	
								end
							end
						end
					end
					
				elseif not p.powers[pw_carry]
				
					if ((s.state >= S_SMS_BOOST01) and (s.state <= S_SMS_BOOST04))
						p.smsboostpanim = true
					else
						if s.SMS_ishoming and SMS_Graphix(s) != 2
							if (s.momz*P_MobjFlip(s) > 8*s.scale)
								local ghs = SMS_GroundWindBlast(s)
								ghs.renderflags = RF_FULLBRIGHT|RF_FLOORSPRITE
								ghs.flags2 = $|MF2_SPLAT
								ghs.z = $-s.momz

								ghs = SMS_GroundWindBlast(s)
								ghs.renderflags = RF_FULLBRIGHT|RF_FLOORSPRITE
								ghs.flags2 = $|MF2_SPLAT
								ghs.spriteyscale = $/3
								ghs.spritexscale = $/3
								ghs.fuse = 11
								ghs.sttspeed = 2
								ghs.tracer = s
								ghs.ditchtracer = 1
								
								ghs = SMS_LightFlash(s, s.color, FRACUNIT-27000, 7, Z+3|TR_TRANS40)
								ghs.renderflags = RF_FULLBRIGHT|RF_FLOORSPRITE
								ghs.spriteyscale = $/3
								ghs.spritexscale = $/3
								ghs.scalespeed = $+7777
								ghs.z = $-s.momz
							end
						end						
						p.smsboostpanim = false
					end
					//If SMS runs off a cliff, go into a special animation that'll let you curl up again!
					if (p.panim == PA_WALK or p.panim == PA_RUN or p.smsboostpanim)
					and not (s.eflags & (MFE_GOOWATER|MFE_SPRUNG))
					and not (p.pflags & PF_SLIDING)
					and not (p.sms_ringburstfly|p.sms_comethaymaker|p.mslightspeedattack|p.sms_dodging|p.exiting) 
					
						p.sms_advfall = $+1
						if (p.sms_advfall > 9) //Been walking in sunshine long enough? Then falling animation, go!
						and not (s.eflags & MFE_GOOWATER)
					
							if (s.momz*P_MobjFlip(s) > 7*s.scale)
								s.state = S_PLAY_SPRING
							else
								s.state = S_SMS_ADVFALL1
							end
							p.sms_advfall = 0
						end
					else
						p.sms_advfall = 0
					end
						
					if (s.state == S_PLAY_SPRING)

						if (s.momz*P_MobjFlip(s) > 6*s.scale)
						and (p.pflags & PF_JUMPED)
						and not p.hometrickanim 
						and not (p.pflags & (PF_NOJUMPDAMAGE|PF_SPINNING)) --Recoiled from homing attack, most likely.
					
							p.pflags = $ & ~PF_JUMPED
			
						--Curl up off springs with the spin button!

						elseif (p.cmd.buttons & BT_SPIN) or (p.cmd.buttons & BT_CUSTOM2) or (p.cmd.buttons & BT_JUMP)
								
							if (p.sms_stompanim or not (p.pflags & PF_JUMPED))
							and not p.exiting and not (p.pflags & PF_GAMETYPEOVER)
							and not p.powers[pw_carry] //Fixes a bug in competition/race.
							and not (p.secondjump == 167)
				
								if ((p.cmd.buttons & BT_SPIN) or p.sms_stompanim) and not p.spinhold 
								or (p.sms_jumphold < 3 and (p.cmd.buttons & BT_JUMP) and not p.smsblastboost)
					
									SMSRSpawnGhost(s, 13)
									s.atomdiveusebuffer = 0
									s.state = S_PLAY_ROLL 
									p.pflags = $|PF_JUMPED & ~PF_THOKKED 
									if (p.cmd.buttons & BT_JUMP)
										if p.powers[pw_carry]
											p.pflags = $|PF_JUMPDOWN
											p.sms_jumphold = 10
										else
											p.pflags = $|PF_JUMPED & ~PF_JUMPDOWN & ~PF_THOKKED & ~PF_NOJUMPDAMAGE
										end
									end						
					
								elseif ((p.cmd.buttons & BT_CUSTOM2) and not (p.smsmeleebutton > 1)
								or ((p.cmd.buttons & BT_JUMP) and (p.sms_jumphold <= 2) and p.smsblastboost))					
									SMS_SideFlip(s, p, true)
								end	
								
							elseif ( ((p.cmd.buttons & BT_SPIN) and not p.spinhold)
							or ((p.cmd.buttons & BT_JUMP) and (p.sms_jumphold <= 2)) )	
							
								P_SpawnGhostMobj(s)
								s.atomdiveusebuffer = 0
								s.state = S_PLAY_ROLL
								p.pflags = $|PF_JUMPED & ~PF_THOKKED //Let's roll!	
							end
						end
						
					elseif (s.state == S_PLAY_GASP) and (s.tics == 1) --Least likely scenario comes last.	
						s.state = S_SMS_ADVFALL1
						p.sms_advfall = $+1
					end
				else --if p.powers[pw_carry]
					s.sms_painr = 0
					p.sms_stompanim = 0
					p.sms_afterstompthok = false
				end
				
				--Execute the frame jump! Or Coyote time, whatever tickles your fancy.
				if s.smsframejump 
				and ((p.cmd.buttons & BT_JUMP) and (p.sms_jumphold < 3) 
				or s.bufferframejump)
					s.bufferframejump = nil
					if ((p.panim >= PA_WALK) and (p.panim <= PA_ROLL))
					or ((s.state >= S_SMS_BOOST01) and (s.state <= S_SMS_BOOST04))
					or (p.sms_dodging > 10)
						
						if ((p.sms_dodging > 10) or not (p.pflags & (PF_SLIDING|PF_STARTDASH|PF_THOKKED|PF_JUMPED|PF_STARTJUMP)))
						
						and not (s.eflags & (MFE_SPRUNG|MFE_UNDERWATER))
						and not SMS_Locked(s, p)
						
							local oldmomz = s.momz
							P_DoJump(p, true)
							
							SMS_WallJumpDelete(s, true) --Act like we jumped off the ground, so refreshed WJ stats.
							s.SMS_lastwallANG,s.SMS_lastwallNUM = nil
							s.SMS_WJpenalty = 0		
							p.sms_ringburstready = 0
							
							if (oldmomz*P_MobjFlip(s) > 0) --Always work in the player's favor!
								s.momz = $+oldmomz
							end
							
							--Turning a bug into a feature! Jump right after a dodge for a cool trickjump! The Dodge Leap.
							if (p.sms_dodging > 10)
							
								p.sms_ringburst = 0 --One or the other!
								p.sms_ringburstfly = 0
								p.sms_ringburstready = 0
								
								S_StopSoundByID(s, skins["sms"].soundsid[SKSJUMP])
								s.stompnegatedinput = nil
								p.sms_dodging = 0
								s.sdodgelvl = 1
								s.smsboostimmune = 7
								S_StartSound(s, sfx_kc5b)
								
								s.spritexscale = FRACUNIT+900
								s.spriteyscale = FRACUNIT-28000
								s.spriteyoffset = 15*FRACUNIT
								s.SMS_squashtable = {timer = 8, Xspeed = 50, Yspeed = 6060, air = true}
								
								local COLOR = (abs(p.cmd.forwardmove) > 35) and SKINCOLOR_SILVER or SKINCOLOR_SKY 	
								
								if SMS_Graphix(s) != 2 --Spawn a whole bunch of cool effects!
									if SMS_Graphix(s) == 0
										SMS_FlatWave(s, nil, nil, 8)
										SMS_QuickDustGFX(s)
										for d = 0,7
											P_SpawnParaloop(s.x+(s.momx*5), s.y+(s.momy*5), s.z+(s.momz*4), 10*FRACUNIT, 16, MT_NIGHTSPARKLE, d*ANGLE_45, S_SMSTSPARK1, false)							
										end
									end
									
									SMS_LightFlash(s, s.color, nil, 5, P|TR_TRANS40) --Leap in a blinding flash of light!
									s.SMS_DLtrail = {timer = 5} --Set default ghosttrail table.
									
									local ghs = SMS_DashGFX(s, (COLOR == SKINCOLOR_SILVER) and COLOR or s.color)
									ghs.spriteyscale = FRACUNIT-15000
									if COLOR == SKINCOLOR_SKY
										ghs.frame = (p.cmd.sidemove > 0) and $|FF_HORIZONTALFLIP or $ & ~FF_HORIZONTALFLIP
									else
										ghs.frame = ($ & ~FF_TRANSMASK)|TR_TRANS10
										if displayplayer and (p == displayplayer) --This won't desync, I think?
											ghs.rollangle = $+ANGLE_270
											ghs.renderflags = $ & ~RF_PAPERSPRITE
										end
									end										
								end
								
								--Be more consistent regardless of bad player timing.
								if COLOR != SKINCOLOR_SKY
									s.state = S_SMS_ROLLT1
									P_InstaThrust(s, R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy), 81*s.scale)
									P_SetObjectMomZ(s, 15*FRACUNIT)							
								else
									P_InstaThrust(s, R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy), 86*s.scale)
									P_SetObjectMomZ(s, 15*FRACUNIT+45655) --Go a bit higher than the frontal dodgeleap.
									s.state = S_SMS_SIDET
									if p.cmd.sidemove 
										if (p.cmd.sidemove < 0)
											s.hmsrotateright = false
										else
											s.hmsrotateright = true
										end
									elseif P_RandomRange(0,1)
										s.hmsrotateright = true
									else
										s.hmsrotateright = false
									end	
								end
								SMS_MediumDustGFX(s)
								p.hometrickanim = true
								s.hmscchange = true
								p.homingtrickcharge = 0
								s.airboostroll = 0
								s.rollangle = 0
								s.smstrickroll = true
								s.smstrickrollang = 0
								p.sms_boostlevel = min($+22,63) --Give some boostlvl too, but not past the point of speedbreak.
								p.pflags = $|PF_JUMPDOWN|PF_JUMPED|PF_NOJUMPDAMAGE & ~PF_SPINNING & ~PF_THOKKED & ~PF_STARTJUMP								

							else
								if SMSSHIELD(p, SH_WHIRLWIND)
									s.momx = $/3 s.momy = $/3
								end							
								local ghs = P_SpawnGhostMobj(s)
								P_MoveOrigin(ghs, s.x-s.momx, s.y-s.momy, s.z-s.momz)							
							end
						end
					end
				end
				s.SMS_ishoming = nil				
				
			--Homing Attack behaviour.

			elseif p.homing
			
				s.rollangle = 0 --Reset some stuff.
				s.smstrickroll = false
				s.airboostroll = 0
				s.sms_boostplustimer = nil
				s.sms_boostplus = nil
				s.sms_tauntcooldown = 0 --Instantly reset taunt CD!
				
				s.SMS_squashtable = nil
				s.spritexscale = FRACUNIT
				s.spriteyscale = FRACUNIT
				s.spriteyoffset = 0
				p.charflags = $ & ~SF_MULTIABILITY
				
				p.sms_advfall = 0
				s.retmhtsfx = 0
				
				s.sms_runspinboost = 0
				p.sms_spinuc = 0
				
				s.SMS_WJauto = 0
				p.sms_wallstat = 0 --No walljumping stats.
				s.SMS_wallwait = (p.cmd.buttons & BT_SPIN) and 8 or 5
				SMS_WallJumpDelete(s, true) --Homing attacks take priority.				
				s.SMS_lastwallANG = nil
				s.SMS_lastwallNUM = nil
				s.SMS_WJpenalty = 0
				
				p.sms_flamedelay = max($,2) --Keep this on cooldown.
				s.SMS_ishoming = true
				
				if (s.eflags & MFE_UNDERWATER) --Appropriate thokitems.
					p.thokitem = 0
					A_BossScream(s, 0, MT_SMALLBUBBLE)
				else
					A_BossScream(s, 0, MT_SMSTSPARK)
					p.thokitem = MT_SMSHOMING
				end
				
				if (p.homing == 87)
					if (p.speed < max(5, s.scale-10000))
						p.pflags = $|PF_SPINNING & ~PF_JUMPED
					end
				elseif s.tracer and s.tracer.valid
				local t = s.tracer
					if (t == p.smspickup) --This would be a real issue.
						if (t.flags & (MF_SHOOTABLE|MF_MONITOR))
							if t.smspickupflags != nil
								t.smspickupflags = $|MF_SHOOTABLE
							else
								t.smspickupflags = t.flags
							end
							t.flags = $ & ~MF_SHOOTABLE
						end
						p.homing = min($,1) 
						s.momz = 0
					elseif not (s.target and s.target.valid)
						s.target = s.tracer --Copy tracer.				
					end
					
					if (p.homing >= 101) and (p.homing <= 104)
					and not (t.flags & (MF_SPRING|MF_MONITOR)) --Only powerup against actual enemies.
					and not (s.eflags & MFE_UNDERWATER)
					and SMS_Graphix(s) != 2					
						local FRAME = (p.homing == 104) and Z+5|FF_TRANS40 or (p.homing % 2) and Z+6|FF_HORIZONTALFLIP|FF_VERTICALFLIP|FF_TRANS60 or Z+7|FF_TRANS60
						local ghs = HMS_BigBangVortex(s, 9, nil, ANG10*5, FRAME, (p.homing != 104) and SKINCOLOR_SMS3R or SKINCOLOR_RED)
							ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
							ghs.tracer = s
							if p.homing != 104
								ghs.ditchtracer = 1
							else
								ghs.scale = $*2/3
								ghs.ditchtracer = 3								
							end
							ghs.spriteyoffset = $+11*FRACUNIT
							ghs.momx = s.momx/2
							ghs.momy = s.momy/2		
							if p.powers[pw_sneakers]
								ghs.sttfade = 7
								ghs.scalespeed = FRACUNIT/5
							end
							if p == displayplayer and CV_FindVar("renderer") == 1
								ghs.flags2 = $|MF2_DONTDRAW
							end		
						--Experimental effect.
					/*	for i = -1,-1,2
							local FRAME = FF_TRANS70|(i == 1 and FF_HORIZONTALFLIP|FF_VERTICALFLIP|Z+6 or Z+7)
							local ghs = HMS_BigBangVortex(s, 8, nil, ANG10*5, FRAME, (p.homing != 104) and SKINCOLOR_SMS3R or SKINCOLOR_RED)	
							ghs.renderflags = RF_SEMIBRIGHT|RF_PAPERSPRITE
							ghs.tracer = s
							ghs.ditchtracer = 2
							ghs.momx = s.momx/-2
							ghs.momy = s.momy/-2			
							if p.homing != 104
								ghs.rollangle, ghs.sttrollangle = ANG20, ANGLE_22h	
								ghs.sttroll = -ANGLE_45 
								ghs.GSoffsetX = (i == 1) and -2*s.scale or -125*s.scale
								ghs.GSoffsetY = (i == 1) and -2*s.scale or -125*s.scale
								ghs.spriteyscale = $/2
								ghs.spritexscale = $/2
							else
								ghs.rollangle, ghs.sttrollangle = ANG20, ANGLE_22h	
								ghs.scale = $*2/3
								ghs.GSoffsetX = 33*s.scale*i
								ghs.GSoffsetY = 33*s.scale*i
								ghs.sttXspeed = -9*FRACUNIT --FF_HORIZONTALFLIP auto-inverts this.
							end
							ghs.GSoffsetZ = s.height+abs(s.momz*2) + ((ghs.frame & FF_VERTICALFLIP) and 10*s.scale or 0)
							if p.powers[pw_sneakers]
								ghs.sttfade = 7
								ghs.scalespeed = FRACUNIT/5
							end
							if p == displayplayer and CV_FindVar("renderer") == 1
								ghs.flags2 = $|MF2_DONTDRAW
							end
						end */
					end
					
					--Attempt an INSTANT homing attack, the Lightning Homing Bolt!
					if (p.powers[pw_sneakers] or (p.sms_boostlevel > 64))
					and not t.player --Not against players, tho.	
					and not (s.eflags & MFE_UNDERWATER)
						if (p.homing >= 98) and (p.homing <= 105)
						
							if (t.type == MT_TNTBARREL)
								t.YOUKICKEDME = s
							elseif not (abs(t.z-s.z) > 1799*FRACUNIT) --Sanity check.
								if p.speed --For momentum use later!
									s.SMShomingspeed = p.speed
									s.SMShomingangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
								else
									s.SMShomingspeed = 24*s.scale
									s.SMShomingangle = s.angle				
								end	
								
								local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK) --Our target for the lightning strike later!
								ghs.flags2 = MF2_DONTDRAW ghs.fuse = 1
							
								local READY = true
								local PARTS = 10
								local INVERSE = false
							
								for i = 1,PARTS
									if i == PARTS --Final step.
										s.z = t.z+t.height
									else --Creep closer.
										local ZDIST = abs(s.z-(t.z+t.height/2)) or 1
										if (t.eflags & MFE_VERTICALFLIP) and not INVERSE
										or INVERSE and not (t.eflags & MFE_VERTICALFLIP)
											if not (s.z+(ZDIST/PARTS) > s.ceilingz)
												s.z = $+(ZDIST/PARTS)
											end
										elseif not (s.z-(ZDIST/PARTS) < s.floorz+s.scale)
											s.z = $-(ZDIST/PARTS)
										end
									end
									local DIST = (FixedHypot(t.x-s.x, t.y-s.y)+s.scale)/PARTS
									local ANGLE = R_PointToAngle2(s.x, s.y, t.x, t.y)
									if DIST --If there's distance, try it!
										if not P_TryMove(s, s.x+FixedMul(DIST, cos(ANGLE)), s.y+FixedMul(DIST, sin(ANGLE)), true)
											INVERSE = true
										else
											INVERSE = false
										end
									end
								end
							
								if READY and P_TryMove(s, t.x, t.y, true)					
									local SfX = P_SpawnMobj(s.x, s.y, s.z, MT_THOK) --Sound object.
									SfX.flags2 = MF2_DONTDRAW SfX.tics = 169 SfX.fuse = 169
		
									S_StartSoundAtVolume(SfX, sfx_rail2, 45)
									S_StartSoundAtVolume(s, sfx_rail1, 90)
									S_StartSoundAtVolume(SfX, sfx_litng4, 155)	
								
									if ghs and ghs.valid
										SMS_LightningStrike(ghs, SKINCOLOR_RED, R)
											
										ghs.sprite = SPR_SMX1
										ghs.frame = Z|FF_TRANS50
										ghs.renderflags = RF_SEMIBRIGHT
										ghs.blendmode = AST_ADD
										ghs.color = SKINCOLOR_SMSROVERGLOWRED
										ghs.fuse = 18 ghs.tics = 99
										ghs.scalespeed = FRACUNIT/18
										ghs.destscale = ghs.scalespeed+1
										SMS_DrawTrail(s, ghs, MT_THOK) --Now draw the trail.
											
										local ths = SMS_LightClash(ghs, SKINCOLOR_SUPERORANGE1, ghs)
										ths.angle = s.SMShomingangle+ANGLE_90
										ths.frame = $+FF_TRANS20
										ths.scalespeed = $*2
										ths.fuse = $-4
										ths.tracer,ths.ditchtracer = nil
											
										ths = SMS_FollowCircle(ghs, SKINCOLOR_SUPERSKY1)
										ths.frame = $+FF_TRANS20
										
										if not ((t.flags & MF_SPRING) and not (t.flags & MF_ENEMY))
											SMS_AngledLightning(s, SKINCOLOR_RED, 23, 4-SMS_Graphix(s))
											S_StartSoundAtVolume(s, sfx_kc40, 115)
										end
										ghs.state = S_NULL										
									end
									if not ((t.flags & MF_SPRING) and not (t.flags & MF_ENEMY)) --Don't electrocute springs!
										S_StartSoundAtVolume(SfX, sfx_brakrx, 35)	
										p.homing = min($, 97)
										SMS_LightningStrike(s, SKINCOLOR_RED)
										SMS_LightningStrike(t, SKINCOLOR_RED, R)
										SMS_LightningTrail(s, t)
									end
								end
							end
						end				
					end
					if abs(s.z-s.floorz) < s.scale
						s.z = $+s.scale
					end						
				/*	if s.SMS_stompmom  
						if not (abs(s.SMS_stompmom ) > 22*s.scale)
							s.SMS_stompmom = 0 --Too slow, stop looking.
						elseif (s.target == s.tracer)
						and not ((t.flags & MF_SPRING) and not (t.flags & MF_ENEMY)) --Don't electrocute springs!
						and not (s.eflags & MFE_UNDERWATER) 
							if FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 400*s.scale
								if not (p.powers[pw_sneakers] or (p.sms_boostlevel > 64))
									local SfX = P_SpawnMobj(s.x, s.y, s.z, MT_THOK) --Sound object.
									SfX.flags2 = MF2_DONTDRAW SfX.tics = 169 SfX.fuse = 169
		
									S_StartSoundAtVolume(SfX, sfx_rail2, 45)
									S_StartSoundAtVolume(s, sfx_rail1, 90)
									S_StartSoundAtVolume(SfX, sfx_litng4, 155)	
									
									S_StartSoundAtVolume(SfX, sfx_brakrx, 35)	
									p.homing = min($, 97)
									SMS_LightningStrike(s, SKINCOLOR_RED)
									SMS_LightningStrike(t, SKINCOLOR_RED, R)
									SMS_LightningTrail(s, t) 
								end

								if (s.SMS_stompmom  < 0) and not (s.eflags & MFE_VERTICALFLIP)
								or (s.SMS_stompmom  > 0) and (s.eflags & MFE_VERTICALFLIP)
									if not p.powers[pw_sneakers]
										local ghs = SMS_ElectricBody(s, 21, SKINCOLOR_SKY)
										ghs.sttfade = true
									end
									
									local PREPTIME = min(7, max(1, FixedInt(abs(s.SMS_stompmom/5)))) --SMS is batman?!
									
									s.SMS_HomingBolt = {
									bounce = s.SMS_stompmom,
									preptimer = PREPTIME,
									launchtimer = 12,
									addmult = 0,
									target = t,
									homespeed = (s.SMShomingspeed != nil) and s.SMShomingspeed or 28*s.scale,
									homeangle = (s.SMShomingangle != nil) and s.SMShomingangle or s.angle,
									start = true
									}
									if s.SMShomingangle != nil
										p.drawangle = s.SMShomingangle
										s.angle = s.SMShomingangle
									end
									p.camerascale =  FRACUNIT*3
									s.bhlcamtimer = 11		
									s.SMS_stompmom = 0
								end	
							end
						end */
				/*	elseif (p.pflags & PF_NOJUMPDAMAGE) and not P_IsObjectOnGround(s)
						local ZDIST = (abs(t.z-s.z) or 1)/14
						if ZDIST
							if (t.z+t.height/2 < s.z)
								if (s.z-ZDIST > s.floorz+s.scale)
									s.z = $-ZDIST
									A_BossScream(s, 0, MT_SMSTSPARK)
								end
							elseif (t.z > s.z+(s.height*2))
								if (s.z+ZDIST < s.ceilingz-s.scale)
									s.z = $+ZDIST
									A_BossScream(s, 0, MT_SMSTSPARK)
								end	
							end
						end 					
					end  */
				end
			end
			
			//Is SMS in advanced falling states? Meaning:
			--When SMS runs off a cliff or ledge, he goes into special falling frames with recurl abilities.
			if (s.state == S_SMS_ADVFALL2)
			or (s.state == S_SMS_ADVFALL1)		

				p.sms_advfall = 0 --This is the tic counter value before these states would've kicked in.

				if p.hypermysticsonic --Can fly again!
				
					s.state = S_PLAY_ROLL --Shouldn't be in those frames to begin with, tbh.
					p.pflags = $|PF_JUMPED
					
				elseif (p.cmd.buttons & BT_CUSTOM2)	and not (p.smsmeleebutton > 1)
				and not p.spinhold and not p.powers[pw_carry] --Trick from falling anim?
				
					A_SMSSTOMPSMOKE(s, 6, MT_SPARK, nil, (s.momz*4/3))
					SMSRSpawnGhost(s, 14)
					
					s.state = S_SMS_ROLLT2
					p.hometrickanim = true
					p.pflags = $ & ~PF_JUMPED & ~PF_THOKKED & ~PF_NOJUMPDAMAGE
					p.homingtrickcharge = 0
					
				elseif ( ((p.cmd.buttons & BT_SPIN) and not p.spinhold) --Curl up from falling anim!
				or ((p.cmd.buttons & BT_JUMP) and (p.sms_jumphold <= 2)) )
				
					local ghs = P_SpawnGhostMobj(s)
					ghs.spriteyscale = s.spriteyscale*5/4
					ghs.spritexscale = s.spritexscale*4/5
					ghs.destscale = ghs.scalespeed+1
					ghs.fuse = 8 ghs.tics = 9

					s.spritexscale = FRACUNIT-11500
					s.spriteyscale = FRACUNIT+14000
					s.SMS_squashtable = {timer = 5, Xspeed = 4500, Yspeed = 5000, air = true}					
					
					s.atomdiveusebuffer = 0
					s.state = S_PLAY_ROLL
					p.pflags = $|PF_JUMPED & ~PF_THOKKED & ~PF_JUMPDOWN //Let's roll!	
				end

			elseif p.sms_advfall --Got a counter but need to disable it?
			
				if P_IsObjectOnGround(s)
				or (p.pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING))
				or not p.panim == PA_RUN and not p.panim == PA_WALK and not p.smsboostpanim
				or p.powers[pw_carry]
					p.sms_advfall = 0
					if not p.homing
						p.pflags = $ & ~PF_THOKKED
					end
				end
			end	
	end
end, MT_PLAYER)