--╔════════════════════════════╗══════════════════════════════════════════════════════════════════════════════════════════════#
--║       PreThinkFrame        ║ PreThinkFrame hooks execute before SRB2 even registers controls. That makes it perfect
--║      & PostThinkFrame      ║ for messing with controls and grabbing things at the earliest possible oppertunity!
--╚════════════════════════════╝══════════════════════════════════════════════════════════════════════════════════════════════#
local XSon = XSon
local function P_MobjFlip(s) if s and s.valid and ((s.eflags&MFE_VERTICALFLIP) or (s.flags2&MF2_OBJECTFLIP)) return -1 end return 1 end

--We need a prethinkframe to properly mess with player controls.
addHook("PreThinkFrame", do

local FSKIN = CV_FindVar("forceskin").string
if FSKIN == "xsonicserious" or FSKIN == "xsonicoverlay"
	if (isdedicatedserver)
		COM_BufInsertText(server, "forceskin xsonic") --Restore the music!
	else
		CV_StealthSet(CVAR, "xsonic")
	end
	print("\x85"+"Forceskin cannot be an invalid variant of\x84 xsonic\x85"+"!\x86 Defaulting to correct xsonic skin!")
	S_StartSound(nil, sfx_appear)
end

for p in players.iterate	
	local xs = p.xsonictable local yu = xs
	
	if not xs continue end --Use continue instead of return, since we're using a players.iterate!
	local s = p.mo
	
	--Button timers. If it's 1, you literally JUST tapped the button. If it's 0, you've let go. 
	--If it's above 1, you've been holding the button for over a tic. (example: If it's 35, you've been holding it for 1 second)
	--These won't register if p.powers[pw_nocontrol] is active.
	if not (p.powers[pw_nocontrol]==1 and s and not s.XS_lastNC)
		if xs.FreeFlight
			xs.FreeFlight.truespin = (p.cmd.buttons & BT_SPIN) and (xs.FreeFlight.truespin and $+1 or 1) or 0
		end
		xs.jump = (p.cmd.buttons & BT_JUMP) and $+1 or 0
		xs.spin = (p.cmd.buttons & (BT_SPIN|BT_CUSTOM1)) and $+1 or 0
		xs.custom1 = (p.cmd.buttons & BT_CUSTOM1) and (xs.custom1 and $+1 or 1) or 0
		xs.custom2 = (p.cmd.buttons & BT_CUSTOM2) and $+1 or 0
		xs.custom3 = (p.cmd.buttons & BT_CUSTOM3) and $+1 or 0
		xs.weaponnext = (p.cmd.buttons & BT_WEAPONNEXT) and $+1 or 0
		xs.weaponprev = (p.cmd.buttons & BT_WEAPONPREV) and $+1 or 0
		xs.tossflag = (p.cmd.buttons & BT_TOSSFLAG) and $+1 or 0
	else
		if s 
			if IsXSonic(s)
				if (xs.zipdash or p.xsringburst)
					if p.xsringburst
						XSRingBurstReset(p, s, xs)
					else--if xs.zipdash
						XSZipDashCancel(p, s, xs)
						s.state = S_PLAY_FALL
						s.spritexscale,s.spriteyscale = FRACUNIT-24000,FRACUNIT+32500
						s.spritexoffset,s.spriteyoffset = 0,0
						s.XSstretch = {timer = 8, Xspeed = 3200, Yspeed = 3900}
					end
					if P_IsObjectOnGround(s)
						S_StartSound(s, sfx_skid)
						S_StartSound(s, sfx_xssfx7)
						XS_QuickDust(s)
						XSSpawnJumpDust(s)
					end
					s.momx,s.momy = 0,0
				end
				xs.ExitState = 2
			end
			s.XS_lastNC = 0
		end
		xs.jump,xs.spin,xs.custom1,xs.custom2,xs.custom3,xs.weaponnext,xs.weaponprev,xs.tossflag = 0,0,0,0,0,0,0,0
	end
	
	if s
		if IsXSonic(s)	
			if s.XS_lastRR==nil s.XS_lastRR = p.rings or 0 end
			if (p.rings > 99)
				if (p.rings > (s.XS_lastRR+96) ) and (p.rings < (s.XS_lastRR+104) )
					if (s.state != S_PLAY_S_XTRANSFORM) and (p.powers[pw_super]!=1) and (leveltime > 3)
						p.rings = $-70
					end
				end
			end
			if (s.XS_lastRR != p.rings)
				s.XS_lastRR = p.rings
			end
			
			if not ((s.flags2 & MF2_TWOD) or (twodlevel))
				--Decide how hard we're pressing the stick! From 0 to 50!		
				xs.direct = (abs(p.cmd.forwardmove)>=abs(p.cmd.sidemove)) and abs(p.cmd.forwardmove) or abs(p.cmd.sidemove)
				--What's our turnangle?	
				xs.turnang = (p.cmd.angleturn<<16) + (R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))	
			else
				xs.direct = abs(p.cmd.sidemove)
				if (xs.direct > 5)
					xs.turnang = (p.cmd.sidemove<0) and ANGLE_270 or 0
				else
					xs.turnang = s.angle
				end
			end
					
			--Never be this skin.
			if s.skin == "xsonicoverlay"
				local OGC,OGC2 = p.skincolor,s.color
				if not (multiplayer)
					local CVAR = CV_FindVar("skin")
					if CVAR!=nil
						CV_StealthSet(CVAR, (xs.darkphase) and "xsonicserious" or "xsonic")
					end
				elseif (splitscreen==true) or (p==consoleplayer)
					COM_BufInsertText(p, "skin xsonicoverlay; skin xsonic")
				end
				R_SetPlayerSkin(p, "xsonic")
				s.skin = "xsonic"
				p.skincolor,s.color = OGC,OGC2
			end
			s.XS_DidSuperAura,s.XS_DidBlur = false,false
			
			xs.alreadytrailed = false --Reset the Ziptrail property here.
			
			--Record our last coordinates for certain functions!
			if s.health	
				if (p.powers[pw_carry] == CR_NIGHTSMODE) and (s.XS_NiGHTStransform!=nil or (s.sprite2 == SPR2_TRNS))
				
					XSon.NiGHTStransform(p,s,xs) --Nights transform animation.
					
				elseif s.XStransform --In your Super Sonic transform animation!
				
					if (p.cmd.buttons & BT_SPIN) and (xs.spin <= 1) and (s.XStransform < 53) and (s.XStransform > 9)
						s.XStransform = 3 s.tics = 3 --Allow a quick transform.
						XS_MediumDust(s, SKINCOLOR_SUPERSILVER1, AST_ADD, Q|FF_TRANS30, 42*s.scale, s.angle)
						XSon.RadiantLight(s)
						local ghs = XS_RingBurstWave(s, 24, SKINCOLOR_SUPERGOLD4)
						ghs.spriteyoffset = $-12<<16
						XSon.sparkles(p,s,xs, 36, 8, 4, 3<<16, SKINCOLOR_WHITE, AST_ADD, FF_TRANS40, 48, FRACUNIT/4)
						XS_RingBurstSparkles(s)
						XSon.TryFlight(p,s,xs, nil, 0, nil, "noSFX")
						s.XSecho = nil
						S_StopSoundByID(s, sfx_xssfph)
						S_StopSoundByID(s, sfx_xsvoc7)
						XSon.Sound(s, sfx_xssfpu)
						XSVoice(p,s,xs, sfx_xsvocs, true) --You can't stop me!!
						p.xssuperflash = {trans = FF_TRANS30, timer = 16, speed = 1, flashtic = 14, reversal = 13, COLOR = SKINCOLOR_SUPERGOLD2}
					end				
					p.cmd.buttons,p.cmd.sidemove,p.cmd.forwardmove = 0,0,0 
					continue --Use continue, not return!!
				else
					if p.xstauntstance
						local TS = p.xstauntstance
						TS.Cforwardmove = p.cmd.forwardmove
						TS.Csidemove = p.cmd.sidemove
						TS.Cbuttons = p.cmd.buttons --For bots.
						XSon.TauntStance(p,s,xs)
					elseif (p.charflags & SF_SUPER)
						if (XSon.SFSUPER(p,s,xs, "OFF")==false) and (p.cmd.buttons & BT_SPIN) and (p.pflags & (PF_JUMPED|PF_NOJUMPDAMAGE))
							p.pflags = $|PF_USEDOWN
						end
					end
					if p.XSonicMenu --Alter the menu's properties and your inputs while in it.
						XSon.MenuThinker(p,s,xs, p.XSonicMenu)
					else
						local RB = s.XS_DarkTable
						if s.XSassault and s.XSassault.autojump
						or RB and RB.jumpDR and s.XSlunging
							p.cmd.buttons = $|BT_JUMP
							p.pflags = $|PF_JUMPDOWN
						else
							if p.panim == PA_IDLE or s.state == S_PLAY_EDGE or s.state == S_PLAY_WALK
								if xs.direct and (p.speed <= s.scale) and (xs.direct < 6) and P_IsObjectOnGround(s) 
								and not p.xstauntstance and not p.powers[pw_carry] --Fix some stupid controller jank for SRB2.
									local MULT = (xs.direct>4) and 2 or (xs.direct>2) and 3 or 0
									xs.direct = $*MULT									
									p.cmd.forwardmove = min(50, $*MULT)
									p.cmd.sidemove = min(50, $*MULT)
								end
								local DARK = (RB and RB.READY) and true or false
								if xs.custom3 and (xs.custom3 < 99<<16) or DARK==true
									if P_IsObjectOnGround(s) and not xs.FreeFlight and (p.speed < 32*s.scale)
									and not p.XSonicMenu and not p.powers[pw_nocontrol]
									and not (p.pflags & (PF_SPINNING|PF_SLIDING|PF_FULLSTASIS|PF_STASIS)) 
									and not p.xstauntstance and not xs.direct and not xs.ExitState and not p.exiting
									and not s.XSassault
										if DARK == true
											P_RadiusAttack(s, s, 88<<16, DMG_NUKE, false)
											s.momx,s.momy = 0,0
											XSon.ObtainTheNPass(p,s,xs)
											s.XS_darkness,s.XS_C3CONTEXT = 0,nil
											p.powers[pw_nocontrol] = 3
											if s.XS_DarkTable s.XS_DarkTable.READY = nil end
										else
											XSon.C3context(p,s,xs) --Reveal Custom 3 Context Actions HUD.
										end
										xs.direct, p.cmd.forwardmove,p.cmd.sidemove = 0,0,0
										p.cmd.buttons = $ & ~(BT_JUMP|BT_SPIN|BT_TOSSFLAG|BT_CUSTOM1|BT_CUSTOM2)
									end
								end
							elseif p.xswallrun
								if (abs(p.cmd.sidemove) > 16)
									p.cmd.buttons = $ & ~(BT_CAMLEFT|BT_CAMRIGHT)
								end
							--	if p.xswallrun.cantsidestep
							--		p.cmd.sidemove = 0
							--	end
								if not p.cmd.forwardmove or (p.cmd.forwardmove < 0)
									p.cmd.forwardmove = 1
								end
							end
							if p.powers[pw_super]
								if (s.color != SKINCOLOR_SUPASONIKKU)
									if p.scolor and p.scolor!="default" --Supercolors mod support.
									or ((XSon.Hyper(p))==true) 
										s.XS_modScolor = s.color 
									end
								end
								local FF = xs.FreeFlight
								if FF and FF.LockOn and FF.LockOn.valid		
									if FF.BlastCharge==nil FF.BlastCharge = {C3 = 0, LetGo = 0} end
									
									if FF.SRAlunge
										FF.BlastCharge.C3 = 99<<16
										FF.BlastCharge.LetGo = 0 --So the player doesn't insta explode.
										p.cmd.buttons = $|BT_CUSTOM1
										if (p.cmd.forwardmove <= 0) and (abs(p.cmd.sidemove) < 11)
											p.cmd.forwardmove = 30
											xs.direct = (abs(p.cmd.forwardmove)>=abs(p.cmd.sidemove)) and abs(p.cmd.forwardmove) or abs(p.cmd.sidemove)
											xs.turnang = (p.cmd.angleturn<<16) + (R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
										end
										if not xs.zipdash
											if not xs.ChaosSnap and not xs.ChaosLambent and not FF.painstun
												FF.canforcezip = 2
												FF.custom1,xs.custom1 = 1,1
												XSon.TryAirZipDash(p,s,xs, true)
												if xs.zipdash
													xs.zipdash = 1
													xs.delayzip,xs.zipcontinue = 11,false
												end
											end
										else
											FF.custom1,xs.custom1,FF.spin = 4,4,4
										end
										p.cmd.buttons = $|BT_CUSTOM1
									elseif FF.RingBurstChase
										FF.BlastCharge.C3 = 0
										FF.BlastCharge.LetGo = 0
										if (p.cmd.forwardmove < 16)
											p.cmd.forwardmove = 16
										end
										if FF.RBupdown and (abs(FF.RBupdown)>4)	
											if (FF.RBupdown > 0)
												p.cmd.buttons = $|BT_JUMP & ~BT_SPIN
											else
												p.cmd.buttons = $|BT_SPIN & ~BT_JUMP
											end
										end
										if FF.RBside
											if (FF.RBside > 0) and (p.cmd.sidemove < FF.RBside)
											or (FF.RBside < 0) and (p.cmd.sidemove > FF.RBside)
												p.cmd.sidemove = FF.RBside
											end
										end
										xs.direct = (abs(p.cmd.forwardmove)>=abs(p.cmd.sidemove)) and abs(p.cmd.forwardmove) or abs(p.cmd.sidemove)
										xs.turnang = (p.cmd.angleturn<<16) + (R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
									else
									
										if (p.cmd.buttons & BT_CUSTOM3)
											FF.BlastCharge.C3 = $+1
											FF.BlastCharge.LetGo = 0
										else
											local CUSTOM3 = FF.BlastCharge.C3
											if CUSTOM3 and (CUSTOM3 < 17)
												FF.BlastCharge.LetGo = 1
											else
												FF.BlastCharge.LetGo = 0
											end
											FF.BlastCharge.C3 = 0
										end									
										
										if FF.magicC2
											xs.custom2,FF.custom2 = 99<<16,99<<16
											FF.pressedC2 = 0
											if not FF.magicC2.timer
												FF.magicC2 = nil
											else										
												FF.magicC2.timer = max($-1,0)
												if not (FF.magicC2.timer > 30)
													if not (p.cmd.buttons & (BT_CUSTOM2|BT_SPIN|BT_TOSSFLAG))
														FF.magicC2.C2 = 0
													else
														FF.magicC2.C2 = $+1
													end
												end
											end
										end
										if FF.shock or FF.counters
											if not xs.ChaosSnap
												if not p.cmd.forwardmove and not p.cmd.sidemove
													p.cmd.forwardmove = 41
												end								
												if FF.LockOn.XSautododge or FF.custom2 and (FF.custom2 > 1)
													p.cmd.buttons = $|BT_CUSTOM2
													FF.custom2 = max($,1)
													xs.custom2 = max($,1)
												end
											end
										elseif xs.snapdive or xs.snapdivetrick or xs.snapdivekick
											if (s.state == S_PLAY_XKICK1) 
												p.cmd.sidemove = 0
												xs.direct = abs(p.cmd.forwardmove)
												xs.turnang = (p.cmd.angleturn<<16) + (R_PointToAngle2(0, 0, abs(p.cmd.forwardmove)<<16, 0))
											end
										elseif ((FF.noinput or 0) > 15)
										and (p.panim >= PA_IDLE) and (p.panim <= PA_FALL)
										and not (p.cmd.buttons & (BT_JUMP|BT_SPIN)) and (p.panim!=PA_PAIN)
										and not (FF.haymaker or xs.stopstick or xs.ChaosLambent)
											local t = FF.LockOn
											local DIST = FixedHypot((s.x+s.momx)-(t.x+t.momx), (s.y+s.momy)-(t.y+t.momy))
											if (DIST < 2000*s.scale)
												local ZDIST = abs((s.z+s.momz) - (t.z+t.momz))
												if (ZDIST > 520<<16) and (ZDIST >= DIST/2) --Autoadjust height input.
													if (s.z < t.z)
														p.cmd.buttons = $|BT_JUMP
														FF.autoinput = BT_JUMP
														if not FF.jump FF.jump = 2 end
													else
														if not FF.truespin FF.truespin = 2 end
														FF.autoinput = BT_SPIN
														p.cmd.buttons = $|BT_SPIN
													end
													if not (FF.PushType)
														FF.PushType = 3
													end
												end
											end
										end
									end

									if xs.ACCE
										if xs.ACCE=="both" or xs.ACCE=="noquakes"
											p.viewrollangle = 0 --This..kind of counts.
										end
									end	
								end
							end
						end
					end
				end
				
				--Stick to the ground better!
				if xs.zipdash and not xs.zipdashleap and not xs.zipdashslide
					XSon.ZipdashControls(p,s,xs)
				elseif xs.sprung and (xs.snapdivetrick > 7) --Force a big jump.
					if not (p.cmd.buttons & BT_JUMP)
						if (s.momz*P_MobjFlip(s) > s.scale)
							p.cmd.buttons = $|BT_JUMP
							p.pflags = $|PF_JUMPDOWN
							xs.jump = FRACUNIT
							xs.snapdivewait = 2
						end
					elseif (p.cmd.buttons & BT_JUMP) and xs.jump >= FRACUNIT
						p.pflags = $ & ~PF_JUMPDOWN
						xs.snapdivewait = 0
					end
				elseif p.xswallrun and not ((s.flags2 & MF2_TWOD) or twodlevel)
					p.cmd.forwardmove = max($,1)
				end
					
				--Keep tracks of lots of early-on values.					
				if not ((s.eflags & MFE_JUSTHITFLOOR) or P_IsObjectOnGround(s)) and not xs.snapdivetrick
					xs.lastmomz = s.momz --Only update off the ground, pls.
				end
				if xs.forcecontrolside != nil
					if p.cmd.sidemove
						xs.forcecontrolside = p.cmd.sidemove
					end
					if xs.forcecontrolforward != nil
						if p.cmd.forwardmove
							xs.forcecontrolforward = p.cmd.forwardmove
						end
					end
				end
			end				
		end
	end
	
	--Affect ALL players from here on out!
	if xs.myshield and xs.myshield.valid --Fix for shields.
		XSon.ShieldThinker(xs.myshield, s, p, xs)
	end
	
	--Prevent unintended stick movement with this.
	if xs.stopstick 
		if p.cmd.sidemove or p.cmd.forwardmove
			xs.stopstick = $-1
			p.cmd.sidemove = 0
			p.cmd.forwardmove = 0
		else
			xs.stopstick = 0
		end
	end
	--Prevent accidental inputs with this.
	if xs.stopbutton
		if p.cmd.buttons
			if (p.cmd.buttons & BT_CUSTOM3) and xs.FreeFlight and xs.FreeFlight.painstun
				p.cmd.buttons = BT_CUSTOM3
			else
				p.cmd.buttons = 0
			end
		else
			xs.stopbutton = nil				
		end
	end
end end)

--#==================================================================================================================#	
--The PostThinkFrame" ! This hook executes right before the game renders it's frames.
--Therefore, is to ensure animations render EXACTLY how I want without anything having the chance to interrupt.
--#==================================================================================================================#	

addHook("PostThinkFrame", do

if (gametype!=GT_COOP) and (gamestate == GS_LEVEL) and (XS_FAKEEMERALDS!=nil)
	XS_FAKEEMERALDS = emeralds or 0 --Copy the Chaos Emeralds when outside of Coop.
end

for p in players.iterate	
	if not (p.mo and IsXSonic(p.mo) and p.xsonictable) continue end
	local s = p.mo local xs = p.xsonictable local yu = xs

	if s.health
		if xs.forceangle --A table forcing you to face a certain way.
			if not (xs.forceangle.timer) or xs.forceangle.angle==nil
				xs.forceangle = nil
			else
				if not xs.forceangle.nosangle s.angle = xs.forceangle.angle end
				p.drawangle = xs.forceangle.angle
				xs.forceangle.timer = max($-1,0)
			end
		end 
		if s.XS_tempcombo --Retains combo during certain moves. (Snapdive/zipdash, etc)
			p.scoreadd = max($, s.XS_tempcombo.combo)
			s.XS_tempcombo.combo = p.scoreadd
			if not (xs.zipdash and (xs.zipdash>5) and not xs.zipdashslide)
			and not xs.snapdive
			and not (xs.snapdivetrick and (xs.snapdivetrick < 13))
			and not (p.xsringburst)
			and not ((s.state >= S_PLAY_XKICK1) and (s.state <= S_PLAY_XKICK4))
				s.XS_tempcombo.timer = max($-1,0)
				if not s.XS_tempcombo.timer
					s.XS_tempcombo = nil
				end
			else
				s.XS_tempcombo.timer = 3
			end	
		end
		local SUPER = XS_Super(p)
		
		--Ring Burst related?
		if p.xsringburst
			XSRingBurstBall(p, s, xs) continue --
		elseif (xs.ringburstcharge > 21) and (xs.ringburstcharge < 25) --Curl up animation
			if (p.panim == PA_ROLL or p.panim == PA_JUMP or p.panim == PA_SPRING or p.panim == PA_FALL)	
			and not xs.zipdash and not xs.FreeFlight
				s.sprite2 = SPR2_MLEE|((SUPER == 3) and FF_SPR2SUPER or 0)
				s.frame = ($ & ~FF_FRAMEMASK)|min(D, (xs.ringburstcharge-21))
				s.tics,s.anim_duration = 2,2
			end
		end
		
		if xs.poutyanim or xs.poutysonic
			XSon.PoutySonic(p,s,xs) continue --Pouty race is master race
		elseif (s.state == S_PLAY_S_XTRANSFORM) --Animate the Super transformation!
			s.XSassault = nil
			XSon.SuperTransform(p, s, xs) 			
			XSon.SuperBlur(p, s, xs, nil)
			XSon.SuperAura(p, s, xs, SKINCOLOR_SILVER)
		else	
			if p.xstauntstance
				if p.xstauntstance.taunt==14
					s.sprite2 = SPR2_ROLL
					s.frame = ($&~FF_FRAMEMASK)|min(D, p.xstauntstance.frame)
					p.pflags = $|PF_STARTDASH|PF_SPINNING
				end
			elseif p.xswallrun
				p.drawangle = p.xswallrun.faceangle
			else		
				if xs.squat
					if (p.panim >= PA_IDLE) and (p.panim <= PA_ABILITY) or (s.state == S_PLAY_EDGE)
						if not xs.FreeFlight and (p.cmd.buttons & BT_JUMP) and (p.panim != PA_PAIN)
							local SPR2SUPER = (s.sprite2 & FF_SPR2SUPER) and FF_SPR2SUPER or 0
							if SPR2SUPER != 0	
								s.sprite2 = SPR2_SKID|SPR2SUPER
							elseif xs.slowsquat
								s.sprite2 = SPR2_TWIN
								if (s.spriteyoffset > -6<<16)
									s.spriteyoffset = -6<<16
								end
							else
								s.sprite2 = SPR2_MLEL|SPR2SUPER
							end
							s.frame = $ & ~FF_FRAMEMASK
						end
					end
				end
				if xs.frontflip --Reverse the flip animation! ...which is surprisingly much of a pain to do.
					XSon.FrontFlip(p,s,xs)
				else
					XSon.SkyDiving(p,s,xs) --Check if we can skydive.
					if p.powers[pw_carry]==2006
						s.sprite2 = SPR2_GRND|((xs.supersonic) and FF_SPR2SUPER or 0)
						s.frame = ($ & ~FF_FRAMEMASK)|((leveltime%2) and B or A)
					end
					if (s.sprite2 & ~FF_SPR2SUPER) == SPR2_GRND --Lazy way of doing stuff, but hey...
						if xs.railpose != 8
							XSon.SoapShoes(p, s, xs, (not (xs.railpose)) and true or nil)
							xs.railpose = 8
						end
					elseif xs.railpose
						xs.railpose = $-1
					end	
				end
			end
		end
		if SUPER == 3 --Super Sonic animations.
			local SPRITE2 = (s.sprite2 & ~FF_SPR2SUPER)
			
			if s.XSassault
				XSon.AssaultAnim(p,s,xs)
			elseif (s.state == S_PLAY_XZIPBRAKESUPER) and not P_IsObjectOnGround(s)
			or (SPRITE2==SPR2_TAL5) or (SPRITE2 == SPR2_TAL3)
				if not (p.powers[pw_carry] == CR_NIGHTSMODE) --idk why you do this, and I can't be arsed to find out.
					s.sprite2 = SPR2_TAL2|FF_SPR2SUPER
					s.frame = ($ & ~FF_FRAMEMASK)|((leveltime%2) and B or A) 		
					s.spriteyoffset = 18<<16
					if not s.XSstretch
						s.XSstretch = {timer = 1}	
					end
				end
			elseif (p.pflags & PF_SLIDING) or s.XSpainoverride
				if (p.pflags & PF_SLIDING)
					if SPRITE2 == SPR2_PAIN --Go into walking frames in a waterslide.
						s.sprite2 = SPR2_WALK|FF_SPR2SUPER
						s.frame = ($ & ~FF_FRAMEMASK) | ((leveltime%3==0) and C or (leveltime%2==0) and B or A)
					end
					s.XSpainoverride = true
				else
					if SPRITE2 == SPR2_PAIN or SPRITE2 == SPR2_WALK
						s.state = (p.pflags & (PF_JUMPED|PF_SPINNING)) and S_PLAY_ROLL or (s.momz*P_MobjFlip(s) > 9*s.scale) and S_PLAY_SPRING or S_PLAY_FALL
					end
					s.XSpainoverride = nil
				end
			elseif xs.darkphase==3 --DSS exclusive.
				if SPRITE2 == SPR2_STND
					if s.XS_DarkTable and s.XS_DarkTable.idle != nil and P_IsObjectOnGround(s)
						s.sprite2 = SPR2_WAIT|FF_SPR2SUPER
						s.frame = ($&~FF_FRAMEMASK) + min(D,s.XS_DarkTable.idle)
					end
				elseif SPRITE2 == SPR2_RUN 
					if (p.speed > 132*s.scale) and xs.zipdash
						s.sprite2 = SPR2_TAL0|FF_SPR2SUPER
						s.frame = ($&~FF_FRAMEMASK)|((leveltime%2) and B or A)
					end
				elseif SPRITE2 == SPR2_FLT_
					s.sprite2 = SPR2_FALL|FF_SPR2SUPER
					s.frame = ($&~FF_FRAMEMASK)|((leveltime%2) and B or A)
				end
				if (s.frame & FF_FULLBRIGHT) --Not for DSS!
					s.frame = ($ & ~FF_FULLBRIGHT)|FF_SEMIBRIGHT
				end
			else
				if xs.ChaosLambent
					XSon.ChaosLambent(p,s,xs, xs.ChaosLambent)
					xs.jump,xs.spin,xs.custom3,xs.custom1 = 99<<16,99<<16,99<<16,99<<16
				elseif xs.FreeFlight local RB = xs.FreeFlight
					if RB.RingBurstChase and (RB.RingBurstChase < 42)
						s.flags2 = $|MF2_DONTDRAW
						XSRingBurstBall(p, s, xs)
					else
						if RB.LockOn and RB.LockOn.valid
							XSon.PvPMagnet(p,s,xs, RB, RB.LockOn)
						end
						if RB.forceanim
							XSon.FlightAnim(p,s,xs, RB, "POST") --Force a flying animation!
						end
					end
				end
			end	
			
		else --Don't do these things when not a Super Saiyan!

			if s.XSassault
				XSon.AssaultAnim(p,s,xs)				
			elseif (s.state == S_PLAY_DASH)
				if not p.powers[pw_sneakers]
					s.state = S_PLAY_RUN
				else
					XSRingBurstBall(p, s, xs, true) --Use the Ring Burst ball graphics for Sonic's feet!
				end
			elseif xs.snapdivetrick and (xs.snapdivetrick < 8)
				if (s.state == S_PLAY_XZIPSLIDE) or ((s.sprite2 & ~FF_SPR2SUPER) == SPR2_SKID) --incase of MFE_FORCESUPER
					if not xs.snapdivekick 
					and not (s.eflags & (MFE_SPRUNG|MFE_APPLYPMOMZ)) 
					and not xs.hitspring and not p.powers[pw_carry]
						s.sprite2 = (SUPER==3) and SPR2_SKID|FF_SPR2SUPER or SPR2_TWIN
						s.frame = $ & ~FF_FRAMEMASK
					end
				end
			elseif s.sprite2 == SPR2_SKID 
				if xs.darkphase and xs.zipdash and (xs.zipdash < 7)
					s.sprite2 = SPR2_MLEL
					s.frame = $ & ~FF_FRAMEMASK
				end
			end
			if (p.charflags & SF_SUPER) 
				XSon.SFSUPER(p,s,xs, "OFF")
			end
			if s.currentaxis --I will go as fast as I WANT. >:(
				p.normalspeed = 42<<16
				p.thrustfactor = skins[s.skin].thrustfactor
				p.accelstart = skins[s.skin].accelstart
				p.acceleration = skins[s.skin].acceleration*3			
			end			
		end
		if SUPER or (p.powers[pw_carry]==CR_NIGHTSMODE)
			XSon.SuperAura(p, s, xs) --Add his aura!
			if xs.darkphase and (xs.darkphase!=3) --Stupid anti-desync ring recovery method.
				if (netgame==true) and p.rings==0 and s.XS_DarkTable 
					local FLASH = p.powers[pw_flashing] or 0
					local RB = s.XS_DarkTable
					if P_PlayerInPain(p) or ((FLASH > 103) and (FLASH < 107))
						local LOSS = (xs.darkphase==2) and 10 or 20
						if RB.lastrings and (RB.lastrings > LOSS)
							local XYDIST = 500<<16
							local NUMR = 0
							searchBlockmap("objects",function(s,m) --Disintegrate overdue rings.
								if m and m.valid and ((m.type==MT_FLINGRING) or (m.type==MT_FLINGCOIN))
									if (NUMR < LOSS-4)
										NUMR = $+1
									else
										XSon.DarkBody(m, nil,nil,nil,1)
										P_RemoveMobj(m)
									end
								end
							end, s, s.x-XYDIST,s.x+XYDIST, s.y-XYDIST, s.y+XYDIST)	
							RB.lastrings = $-LOSS
							p.rings = max(2, RB.lastrings)
							XSon.AddDarkness(s, 5<<16)
							if G_PlatformGametype()
								P_NukeEnemies(s,s, 210<<16)	
							end
							P_PlayerFlagBurst(p, false)
							P_PlayerEmeraldBurst(p, false)
							P_PlayerWeaponPanelOrAmmoBurst(p)			
						end
					end
				end
			elseif SUPER==3 or (p.powers[pw_carry]==CR_NIGHTSMODE)
				XSon.SuperBlur(p, s, xs, (xs.darkphase==3) and XSon.DarkAura(0) or nil)
			end
		end
	elseif (s.state == S_PLAY_DEAD) or (s.state == S_PLAY_DRWN) --We ded.
	
		local MOMZ = s.momz*P_MobjFlip(s)
		local t = s.XS_EnemyDeath
		
		if MOMZ and (MOMZ < 12*s.scale)
		or t == "pit"
			local ROLL = FixedInt(AngleFixed(s.rollangle))
			ROLL = min(179, $+5)
			s.shadowscale = 0 --No shadow!
			if t == "drown"
				s.momz = $/3
			else
				if t
					if t == "pit"
						ROLL = min(179, $+20)
						s.flags = $|MF_NOCLIPHEIGHT
						if (MOMZ > -24*s.scale)
							P_SetObjectMomZ(s, -24*s.scale)
						end	
					else
						if type(t)== "userdata" and t.valid
							XSon.Quake(s, 85<<16, 8, 640<<16)
						--	P_Thrust(s, R_PointToAngle2(s.x, s.y, t.x, t.y), -9*s.scale)
						end
					end
				end
				s.XS_EnemyDeath = nil
				
				--Animate?
				s.frame = $ & ~FF_FRAMEMASK
				if s.XS_KBDeathAnim
					if (s.XS_KBDeathAnim == 20 or s.XS_KBDeathAnim == 18 or s.XS_KBDeathAnim == 16) 
						if s.XS_KBDeathAnim == 20
							XSon.SwapStretch(p, s, xs)
							s.spriteyoffset = -10<<16
							s.spritexscale = FRACUNIT-28000
							s.spriteyscale = FRACUNIT+22500
							s.XSstretch = {timer = 5, Xspeed = 3500, Yspeed = 4000}								
						end					
						local ANG,ghs = s.angle+(s.XS_KBDeathAnim*ANG2)
						local NUM = (s.XS_KBDeathAnim==20) and 12 or 6
						local PLUS = (s.XS_KBDeathAnim==20) and ANG30 or ANG60
						for d = 1,NUM
							ghs = P_SpawnMobjFromMobj(s,
							FixedMul((15+s.XS_KBDeathAnim*2)*s.scale, cos(ANG)),
							FixedMul((15+s.XS_KBDeathAnim*2)*s.scale, sin(ANG)), (-s.XS_KBDeathAnim*s.scale)-s.momz, MT_EXPLODE)
							ghs.flags2 = $|MF2_SHADOW
							ghs.destscale = 99<<16
							ghs.color,ghs.colorized = SKINCOLOR_BEIGE,true
							P_SetObjectMomZ(ghs, -(s.XS_KBDeathAnim/2)*s.scale)
							P_Thrust(ghs, ANG, (s.XS_KBDeathAnim/2)*s.scale)
							ANG = $+PLUS
						end
					end
					s.frame = $|((s.XS_KBDeathAnim>9) and B or C)
					s.XS_KBDeathAnim = $-1
				end
				if s.XS_SideFall --Fling sideways. Don't use actual momentum because it fucks with SRB2's stupid death system.
					if s.XS_XD == nil s.XS_XD = 0 end
					s.XS_XD = $+(s.XS_SideFall*4500)
					s.spritexoffset = s.XS_XD
					s.XS_SideFall = $-1
				end	
			end
			if not (XS_CRAPPYPRIORITIES==1)
				s.rollangle = ROLL*ANG1
			end
		end
		s.tics,s.anim_duration = 99,99	
	end
	
	if p.XSblurtable --Adjust blurtable at the very end of it all.
		for d = -4,8,12
			if p.XSblurtable[d] and p.XSblurtable[d].valid
				XSon.OverGlowThinker(p.XSblurtable[d])
			else
				p.XSblurtable[d] = nil
			end
		end
	end
	if xs.myshield and xs.myshield.valid --Fix for shields.
		XSon.ShieldThinker(xs.myshield, s, p, xs)
	end
	if not xs.XHUD or OLDC
		if xs.HUDpref==true
			XSon.SwapHUD(p,s,xs, "correct", true)
		end
	end
end end)