--This is where we store all seperate functions for Yu Sonic.
 
--Auto-calculates proper gravity offsets. s = Sonic. ghs = any new effect mobj.
rawset(_G, "YuFlipZ", function(s, ghs)
	if not (s.eflags & MFE_VERTICALFLIP)
		ghs.eflags = $ & ~MFE_VERTICALFLIP
		return ghs.z --remain the same.
	else
		ghs.eflags = $|MFE_VERTICALFLIP
		return s.z+s.height-FixedMul(ghs.height, s.scale)
	end
end)

--Like most of my mods, let players turn off quakes and sudden flashes if they're sensitive to it.
--There's no reason for P_, btw. It just feels good. 
rawset(_G, "P_YuQuake", function(p, intensity, tics)
	if not p.yusonictable.noquakes and (p == displayplayer)
	P_StartQuake(intensity, tics)
	end
end)
rawset(_G, "P_YuFlash", function(p, pal, tics)
	if not p.yusonictable.noflashes
	P_FlashPal(p, pal, tics)
	end
end)

local function DoSpinRev(p, s, yu, color, spinver)
		local blendmode = AST_TRANSLUCENT	
			if color == SKINCOLOR_SABLUETRAIL or p.powers[pw_super]
			or yu.customtrailshiny or yu.lsacharged
				blendmode = AST_ADD
			end
			local offset = 0
			if (leveltime % 2 == 0)
				offset = 2*s.scale
			elseif leveltime % 3 == 0
				offset = -3*s.scale
			elseif leveltime % 5 == 0
				offset = 3*s.scale		
			end
			for d = -1,1,1
				local rev = P_SpawnMobjFromMobj(s, 0, 0, s.momz-(s.scale*8), MT_YUTHOKDISP)
				rev.tracer = s
				rev.angle = p.drawangle
				rev.spritexoffset = $+(offset*d*3)
				
				if spinver --Spinning
					rev.scale = s.scale*(25+d)/23
					rev.spriteyoffset = $-(2*s.scale)-offset
					rev.frame = Z|FF_FULLBRIGHT|TR_TRANS80
					if (leveltime % 2 == 0)
						rev.spriteyscale = 73000+(s.spriteyscale/10)
						rev.spritexscale = s.spritexscale
						rev.dispoffset = -1
					elseif (leveltime % 3 == 0)
						rev.spriteyscale = 68000+(s.spriteyscale/10)
						rev.spritexscale = s.spritexscale+5000
						rev.rollangle = s.rollangle+ANG20
					else
						rev.spriteyscale = 65000+(s.spriteyscale/10)
						rev.spritexscale = s.spritexscale+15000
						rev.rollangle = s.rollangle-ANG10
					end
				else --Startdash and bouncing
					rev.scale = s.scale*(25+d)/24
					if (yu.spincharge < 48*FRACUNIT)
						rev.frame = Y|FF_FULLBRIGHT|TR_TRANS90
					else
						rev.frame = Y|FF_FULLBRIGHT|TR_TRANS80
					end	
					rev.rollangle = s.rollangle+FixedAngle(offset*6*d)	
					rev.spriteyoffset = $-(6*s.scale)-offset	
					rev.spriteyscale = 60000+(s.spriteyscale/10)
					rev.spritexscale = s.spritexscale+8001
				end
				
				rev.blendmode = blendmode				
				rev.tics = 3
				rev.yustartdash = true
				if not spinver
					if (d == -1) and color == SKINCOLOR_SABLUETRAIL or p.powers[pw_super]
						if not p.powers[pw_super]
							rev.color = SKINCOLOR_VAPOR
						else
							rev.color = SKINCOLOR_FLAME
						end
					elseif (d == 1) and color == SKINCOLOR_SABLUETRAIL
						rev.color = SKINCOLOR_WAVE
					else
						rev.color = color
					end
				else
					rev.color = color
				end
			end
return rev
end
 
--Adventure-style air drag. This is seriously necessary to make him less OP...

rawset(_G, "YuAirDrag", function(p, s, yu)
	if (yu.noairdrag or yu.noairdrag2)
	and not yu.supersonic and not (yu.bouncestate == 1) --Oops, disabled for a while.
	return
	end
	if yu.superflight and yu.supersonic
	return
	end
local airdrag = 804
local nostick = false
	if not (yu.direct > 2)
	or yu.forcenostick
	airdrag = $+18
	nostick = 18
		if yu.forcenostick
		airdrag = $+yu.forcenostick
		nostick = $+yu.forcenostick
		else
		yu.forcebuilder = 0
		end
	end
	
	if (yu.bouncestate == 1) or yu.lsacharged
	
		if (p.speed < 50*s.scale)
			s.momx = $*80/81
			s.momy = $*80/81
			
		else
			s.momx = $*40/41 --Increased drag
			s.momy = $*40/41
		end
		
	elseif yu.supersonic and not yu.bouncestate
	and (yu.direct > 2)
		if (p.speed < 125*s.scale) and not (p.speed > 145*s.scale)
		or (yu.superaura and p.speed < 145*s.scale) --Super Sonic has inverted air drag. Basically, he's faster in the air.
			if yu.superaura
			s.momx = FixedDiv(FixedMul($, 100), 99)
				if not ((s.flags2 & MF2_TWOD) or twodlevel)
				s.momy = FixedDiv(FixedMul($, 100), 99)
				end
			else
				s.momx = FixedDiv(FixedMul($, 150), 149)
				if not ((s.flags2 & MF2_TWOD) or twodlevel)
				s.momy = FixedDiv(FixedMul($, 150), 149)
				end
			end
			if (p.speed > 70*s.scale)
			yu.runfriction = yu.groundfriction+((p.speed/s.scale)*98)
			yu.frictionlock = 25
				if (yu.runfriction > FRACUNIT)
				yu.runfriction = FRACUNIT
				end
			end
		end
		if p.isxmomentum and (p.speed > 150*s.scale) and not p.xmomtoggledoff --Infinitely accelerate in xmom because xmom is dum
			local num = (p.speed/s.scale)*2
			s.momx = FixedDiv(FixedMul($, num), num-1)
				if not ((s.flags2 & MF2_TWOD) or twodlevel)
				s.momy = FixedDiv(FixedMul($, num), num-1)
				end
		end
	elseif (p.speed > 38*s.scale) or nostick  --Slow down in the air, you're not as fast here
		if (p.xmomtoggledoff or not p.isxmomentum) --No air drag with Xmom. OP as hell.
			if (p.speed > 46*FRACUNIT)
				s.momx = FixedDiv(FixedMul($, 800), airdrag+4)
				s.momy = FixedDiv(FixedMul($, 800), airdrag+4)
			else
				if yu.forcenostick and (p.speed < 20*s.scale)
					s.momx = FixedDiv(FixedMul($, 800), 808)
					s.momy = FixedDiv(FixedMul($, 800), 808)				
				else
					s.momx = FixedDiv(FixedMul($, 800), airdrag)
					s.momy = FixedDiv(FixedMul($, 800), airdrag)	
				end
			end
		end
	end
	yu.forcenostick = 0	
end)

--Spawn jumpball around Sonic.

rawset(_G, "YuJumpBallSpawn", function(p, s, yu)
	if ((leveltime % 2 == 0) and not yu.bouncestate)
	or ( ((p.pflags & PF_THOKKED) and (yu.hominganim or yu.hominganim2 or yu.hominganim3)) and not p.homing and not yu.lsaattack)
	or yu.lsacharged and not yu.lsaattack 
	or (yu.homingtrick and not yu.noaura and not yu.bouncestate)
	or yu.spawnedballalready
	or p.realmo != s
	return --Return means the function will stop in this case.
	end
	
	yu.jumpball = P_SpawnMobjFromMobj(s, 0,0,0, MT_YUJUMPBALL)
	
		if yu.jumpball
		yu.jumpball.target = s
		yu.jumpball.tracer = s
		yu.jumpball.mirrored = s.mirrored
		yu.jumpball.skin = s.skin
		yu.jumpball.angle = p.drawangle
		yu.jumpball.rollangle = s.rollangle
		yu.jumpball.colorized = s.colorized
		yu.jumpball.color = s.color
		yu.jumpball.sprite = SPR_PLAY
		
local color = YuAuraColor(s, nil, yu, true)	
	
		if s.state == S_PLAY_SPINDASH--Spinrevving ball?
		yu.jumpball.sprite2 = SPR2_CLMB
			--Spawn weird shakey spindash-charge aura from SA1.
			DoSpinRev(p, s, yu, color)
		else
			yu.jumpball.sprite2 = SPR2_JBAL
		end
		
		if p.powers[pw_super] or yu.lsacharged
		yu.jumpball.blendmode = AST_ADD
		end
		
		local sonicframe = s.frame & ~TR_TRANS10 & ~TR_TRANS20 & ~TR_TRANS30 & ~TR_TRANS40 & ~TR_TRANS50 & ~TR_TRANS60 & ~TR_TRANS70 & ~TR_TRANS80 & ~TR_TRANS90
			if yu.bouncestate or yu.lsaattack or s.state == S_PLAY_SPINDASH
				if not yu.lsaattack and not p.powers[pw_super] and not yu.bouncestate
				yu.jumpball.frame = sonicframe|TR_TRANS10
				else
				yu.jumpball.frame = sonicframe
					if yu.bouncestate
						if (s.frame & ~FF_FULLBRIGHT & ~FF_SPR2SUPER & ~FF_TRANSMASK) == D
						s.frame = E
						end
						yu.jumpball.sprite2 = SPR2_BBAL
						yu.jumpball.spriteyscale = FRACUNIT+2050
						yu.jumpball.spritexscale = FRACUNIT+2050
						if color == SKINCOLOR_SABLUETRAIL
						yu.jumpball.color = SKINCOLOR_BLUE
						end
						if (leveltime % 2 == 0)
							yu.jumpball.frame = sonicframe|TR_TRANS50
						else
							yu.jumpball.shadowscale = FRACUNIT --Sonic flickers at this frame, so have this thing cast a shadow then.
						end
						if s.spriteyscale == FRACUNIT+10002
						yu.jumpball.spriteyscale = FRACUNIT+10002
						yu.jumpball.spritexscale = FRACUNIT-15002
						end
					end
				end
			else
				yu.jumpball.frame = sonicframe|TR_TRANS30
			end 
		end
		yu.spawnedballalready = true
end)

--Determine Aura color based on player color.

rawset(_G, "YuAuraColor", function(s, color, yu, careaboutyu)
	if yu.supersonic or (s.player and s.player.powers[pw_carry] == CR_NIGHTSMODE)
		if yu.hypersonic and s.player
		color = s.player.yuemeraldcolors2[yu.hypercolor]+4
		else
			if yu.superaura
			color = SKINCOLOR_SUPERSKY2
			else
			color = SKINCOLOR_SAYELLOWAURA
			end
		end
		return color
	elseif yu and yu.customtrail and not G_GametypeHasTeams()
		color = yu.customtrail	
		return color
	else
		color = s.color --Default
		if careaboutyu and (yu and yu.lsacharged)
			color = SKINCOLOR_CORNFLOWER
		elseif ((s.color >= SKINCOLOR_SA2SONIC) and (s.color <= SKINCOLOR_DARKNIGHT))
		or ((s.color >= SKINCOLOR_CERULEAN) and (s.color <= SKINCOLOR_COBALT))
			color = SKINCOLOR_SABLUETRAIL
		elseif ((s.color >= SKINCOLOR_CARBON) and (s.color <= SKINCOLOR_BLACK)) or (s.color == SKINCOLOR_GOLD)
			color = SKINCOLOR_SAYELLOWAURA
		elseif (s.color == SKINCOLOR_BONE)
			color = SKINCOLOR_YULSA	
		end
		return color
	end
end)

--SA2-style jump trail.
--OG SA2 has 3 big auras that all increasingly lag behind Sonic a little. We have 1 aura that stays on him, and 5 slowly shrinking ones.

rawset(_G, "YuJumpTrail", function(p, s, yu)
	if (yu.bouncestate and (s.state != S_PLAY_FALL))
	or p.powers[pw_carry]
	or (yu.noaura and (p.pflags & PF_JUMPED))
	or p.realmo != s
	return
	end
		
	local color = YuAuraColor(s, nil, yu, true)
	local blendmode = AST_TRANSLUCENT		
	if color == SKINCOLOR_SABLUETRAIL or p.powers[pw_super]
	or yu.customtrailshiny or yu.lsacharged
		blendmode = AST_ADD
	end
	
			local jumptrail = P_SpawnMobjFromMobj(s, 0, 0, s.momz, MT_YUJUMPTRAIL)
			jumptrail.scale = s.scale*25/17
			jumptrail.tracer = s						
			jumptrail.scalespeed = $+6500
			jumptrail.destscale = jumptrail.scalespeed+1
			jumptrail.frame = Z|FF_FULLBRIGHT|TR_TRANS70
			jumptrail.color = color			
			jumptrail.blendmode = blendmode 
				
			if yu.superaura and yu.supersonic
				P_TeleportMove(jumptrail, jumptrail.x-(s.momx/-2), jumptrail.y-(s.momy/-2), jumptrail.z)
			end
				--Now the rest. The jumptrail's more like spaced out orbs than a real "trail"
				
				for d = 13,38,5
				
						if d == 13
							jumptrail = P_SpawnMobj(s.x, s.y, s.z-(6*s.scale)-(s.momz/2), MT_YUJUMPTRAIL)
						elseif d == 23
							jumptrail = P_SpawnMobj(s.x-(s.momx/30*25), s.y-(s.momy/30*25), s.z-(2*s.scale)-s.momz-((s.momz/25)*d), MT_YUJUMPTRAIL)
						else
							jumptrail = P_SpawnMobj(s.x-(s.momx/30*d), s.y-(s.momy/30*d), s.z-(2*s.scale)-s.momz-((s.momz/25)*d), MT_YUJUMPTRAIL)
						end
						
						if yu.superaura and yu.supersonic
							P_TeleportMove(jumptrail, jumptrail.x-(s.momx/-2), jumptrail.y-(s.momy/-2), jumptrail.z)
						end

						if d == 13
							jumptrail.scale = s.scale*25/17
						elseif d == 18
							jumptrail.scale = s.scale*50/41
						else	
						
							if d == 23
								jumptrail.scale = s.scale*25/23
							elseif d == 28
								jumptrail.scale = s.scale*25/27							
							else
								jumptrail.scale = s.scale*29/d											
							end	
							
							jumptrail.frame = $ & ~TR_TRANS70 & ~TR_TRANS80
							jumptrail.frame = $|TR_TRANS90
						end
							
						jumptrail.scalespeed = $+6500
						jumptrail.destscale = jumptrail.scalespeed+1	
						jumptrail.color = color
						jumptrail.z = YuFlipZ(s, jumptrail)
						jumptrail.blendmode = blendmode
						if (p == displayplayer) and not CV_FindVar("chasecam").value
						jumptrail.flags2 = $|MF2_DONTDRAW
						end
				end
end)

--Frameskip and footblur. Only works with walking, running and rolling frames!

rawset(_G, "YuFrameSkip", function(p, s, yu, treshold)
if p.powers[pw_super] --Never with Super Sonic!
or (s.flags2 & MF2_DONTDRAW)
return end

local nextframe = ((s.frame & ~FF_FULLBRIGHT & ~FF_PAPERSPRITE)+1) 
local currentframe = (nextframe-1)

	if (nextframe == I) or (nextframe >= J) --Too far! Go back to the first frame!
		nextframe = A
		currentframe = H
	end
 	if (nextframe < A) 
		nextframe = H
		currentframe = G
	end	
	if (currentframe < A)
	currentframe = H
	end
	
	if (p.speed > treshold)
		if (s.tics > 1) --Go as fast as you can!
			s.tics = 1
		else --Okay, time to get to work!	
			--Foot Blur!
			local tmomz = (s.z-yu.lastz) --For slopes.
				if (tmomz > 0)
					tmomz = 0
				end
				local ghs = P_SpawnMobjFromMobj(s, 0, 0, tmomz-3*s.scale, MT_YUTHOK)
				ghs.angle = p.drawangle
				ghs.eflags = s.eflags
				ghs.skin = s.skin
				ghs.color = s.color
				ghs.tracer = s
				ghs.sprite = SPR_YUZL
				ghs.colorized = s.colorized	
				ghs.rollangle = s.rollangle
				if (leveltime % 2 == 0)
					ghs.frame = currentframe|TR_TRANS30
					ghs.spritexscale = FRACUNIT+11000
					ghs.spriteyoffset = -1*FRACUNIT
				elseif (leveltime % 3 == 0)
					ghs.frame = currentframe|TR_TRANS40
					ghs.spritexscale = FRACUNIT+18000
					ghs.spriteyoffset = -4*FRACUNIT
				else
					ghs.frame = currentframe|TR_TRANS60 --Try TR_TRANS80 or TR_TRANS90 if you wanna mess with the transparency.
					ghs.spritexscale = FRACUNIT+4000
				end
				ghs.tics = 2
				P_TeleportMove(ghs, s.x+s.momx, s.y+s.momy, s.z+tmomz)
				
			--When running superfast, move in a more stable manner!
			
				if (s.state == S_PLAY_RUN)
				local nframe = (s.frame & ~FF_FULLBRIGHT & ~FF_PAPERSPRITE)
					if (nframe == A) or (nframe == E) --Remember to set the spriteyoffset for the NEXT frame, not the current.
					s.spriteyoffset = -1*FRACUNIT
					ghs.frame = currentframe|TR_TRANS10
					elseif (nframe == B) or (nframe == F)
					s.spriteyoffset = -3*FRACUNIT
					elseif (nframe == C) or (nframe == G)
					s.spriteyoffset = -2*FRACUNIT 
					elseif (nframe == D) or (nframe == H)
					s.spriteyoffset = FRACUNIT
					end
					yu.resetspriteoffset = 2
				end
		end
	end
end)

--Adventure-style spin trail.

rawset(_G, "YuSpinTrail", function(p, s, yu, blendforce)
	if (p.powers[pw_carry] == CR_NIGHTSMODE)
		blendforce = AST_ADD
	elseif (p.speed < 16*s.scale)
	and ((s.momz > -3*s.scale) and (s.momz < 3*s.scale)) --too slow. Don't spawn
	
	or p.powers[pw_carry] == CR_ZOOMTUBE --this often blinds our player.
	or p.realmo != s
		return
	end
	if yu.alreadytrailed --Once per frame. This'll get real laggy otherwise.
		return
	else
		yu.alreadytrailed = true 
	end	
	
local renderer = 1
	if p == displayplayer --This part doesn't need to sync.
		renderer = CV_FindVar("renderer").value
	end
local spintrailcolor = YuAuraColor(s, nil, yu, true)			
local blendmode = AST_TRANSLUCENT

	if blendforce
		blendmode = blendforce
	elseif (spintrailcolor >= SKINCOLOR_SABLUETRAIL and spintrailcolor <= SKINCOLOR_YULSA) or p.powers[pw_super]
	or yu.customtrailshiny or yu.lsacharged
		blendmode = AST_ADD
	end
	--Setup done.

	if not yu.bouncestate --Looks like Wario ended up liking this version more.
	
		--The singular trail ahead of the pack, hovering over your spinball
		if (p.pflags & PF_SPINNING) and not p.powers[pw_carry] and not yu.lsadash
			DoSpinRev(p, s, yu, spintrailcolor, blendmode)
		end
	/*	if yu.lsaattack and yu.lsahoming	
		local jumptrail
			jumptrail = P_SpawnMobjFromMobj(s, 0, 0, s.momz, MT_YUJUMPTRAIL)
			jumptrail.scale = s.scale*50/34
			jumptrail.tracer = s					
			jumptrail.scalespeed = $+6500
			jumptrail.destscale = jumptrail.scalespeed+1
			jumptrail.frame = Z|TR_TRANS70
			jumptrail.spriteyoffset = -4*FRACUNIT
			jumptrail.color = spintrailcolor
			jumptrail.blendmode = blendmode
			A_CapeChase(jumptrail, 1,0)
		end */
	
		--Now to calculate for the actual spintrail.
		
		local density = 16*FRACUNIT --Software is less powerful and can't handle as many sprites.
		if renderer == 2 --Since OpenGL is more accurate, it benefits more from a higher density as well.
		density = 6*FRACUNIT
			if (spintrailcolor >= SKINCOLOR_SABLUETRAIL and spintrailcolor <= SKINCOLOR_SAREDTRAIL)
			or (spintrailcolor >= SKINCOLOR_RUBY and spintrailcolor <= SKINCOLOR_CRIMSON) --Aren't you special?
			density = 2*FRACUNIT
			end
		end

		local dist = FixedDiv(FixedMul((R_PointToDist2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), (s.z-yu.lastz)) / density), FRACUNIT), s.scale)
		
		if dist > 180 --Even if we get this fast through xmom or whatever, we don't need 180+, c'mon.
			dist = 180
		elseif dist <= 0
			dist = 1
		end
		
		local xdistog = (s.momx/dist)
		local ydistog = (s.momy/dist)
		local zdistog = (s.z-yu.lastz)
		
		if zdistog == 0
		zdistog = 1
		end
		zdistog = $/dist
		
		local xdist = 0
		local ydist = 0
		local zdist = 0
		
		--Keep counting down by -1 until we reach 0. Because Sonic needs 5*FRACUNIT to spawn these, it's impossible to get a "divide by 0" error.
			for i = dist,1,-1
				if s.scale != FRACUNIT
					xdist = FixedDiv(FixedMul((s.momx/dist)*i, FRACUNIT), s.scale)
					ydist = FixedDiv(FixedMul((s.momy/dist)*i, FRACUNIT), s.scale)
					zdist = FixedDiv(FixedMul(((s.z-yu.lastz)/dist)*i, FRACUNIT), s.scale)
				else
					xdist = xdistog*i
					ydist = ydistog*i
					zdist = zdistog*i			
				end
				local spintrail = P_SpawnMobjFromMobj(s, xdist, ydist, zdist, MT_YUSPINTRAIL)	
				spintrail.scale = s.scale*10/9
				spintrail.color = spintrailcolor
				spintrail.blendmode = blendmode
				
					if renderer == 2 or (p.powers[pw_carry] == CR_NIGHTSMODE) --2 is OpenGL.
					spintrail.frame = Z|TR_TRANS90 & ~FF_FULLBRIGHT
					else
					spintrail.frame = Z|TR_TRANS70 & ~FF_FULLBRIGHT
					end
					
					if yu.lsahoming or yu.lsadash--Last longer today with these sparkling LSA pills!
					spintrail.tics = 30
					spintrail.fuse = 30
					spintrail.frame = $|FF_FULLBRIGHT
						if yu.lsadash
						spintrail.scale = $*7/6
						spintrail.scalespeed = $/2
						spintrail.destscale = spintrail.scalespeed+1
						P_SetObjectMomZ(spintrail, spintrail.scalespeed*11, true)
						end
						if yu.attackpriority
							spintrail.color = SKINCOLOR_RUBY
						elseif yu.supersonic
							spintrail.color = spintrailcolor
						else
							spintrail.color = SKINCOLOR_SABLUETRAIL
						end
						spintrail.blendmode = AST_ADD
					elseif yu.customtrailtaper
						spintrail.scalespeed = $*10/6
						spintrail.scale = ($*7/6)-(spintrail.scalespeed/i)
						spintrail.destscale = spintrail.scalespeed+1
						P_SetObjectMomZ(spintrail, spintrail.scalespeed*11, true)
					end
					if (i < 3) and (p == displayplayer) and not CV_FindVar("chasecam").value
				//	or (renderer != 2 and density == 2*FRACUNIT and ((i % 2 == 0) or (i % 3 == 0)))
					spintrail.flags2 = $|MF2_DONTDRAW
					end
			end
		
	else --Bounce version!
			
				local jumptrail
				jumptrail = P_SpawnMobjFromMobj(s, 0, 0, s.momz, MT_YUJUMPTRAIL)
				jumptrail.scale = s.scale*50/34
				jumptrail.tracer = s					
				jumptrail.scalespeed = $+6500
				jumptrail.destscale = jumptrail.scalespeed+1
				jumptrail.frame = Z|FF_FULLBRIGHT|TR_TRANS70
				jumptrail.color = spintrailcolor
				jumptrail.blendmode = blendmode			
			
				if yu.supersonic
					if yu.lsadash
						spintrailcolor = P_RandomRange(SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERGOLD5)
					elseif yu.hypersonic
						spintrailcolor = P_RandomRange(SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERPURPLE5)
					end
				end
						
				for d = 0,16

				local spintrail = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUSPINTRAIL)
				spintrail.scale = s.scale*10/9
				spintrail.color = spintrailcolor
				spintrail.blendmode = blendmode
					if (s.eflags & MFE_VERTICALFLIP)
						spintrail.eflags = $|MFE_VERTICALFLIP
						spintrail.spriteyoffset = -15*FRACUNIT
					end
							
					if (d == 0) --Just assume divide by 0 is 0, geez. Quit bitching, game...
						P_TeleportMove(spintrail, s.x+s.momx/3, s.y+s.momy/3, s.z-s.momz-3*s.scale)
					elseif yu.bouncestate
						P_TeleportMove(spintrail, s.x-(s.momx/d), s.y-(s.momy/d), (s.z-(s.momz/d))-3*s.scale)
					else
						P_TeleportMove(spintrail, FixedMul( (s.scale-(6535*d)), s.x)+FixedMul((6535*d), s.x-s.momx), FixedMul( (s.scale-(6535*d)), s.y)+FixedMul((6535*d), s.y-s.momy), (s.z-(s.momz/d))-3*s.scale)
					end
						
					if renderer == 2 --2 is OpenGL.
						spintrail.frame = Z|TR_TRANS90
					else
						spintrail.frame = Z|TR_TRANS70
					end

					if yu.bouncestate
						spintrail.scalespeed = $*2
						spintrail.destscale = spintrail.scalespeed+1
					end
					if yu.lsahoming or yu.lsadash --Last longer today with these sparkling LSA pills!
						spintrail.tics = 30
						spintrail.fuse = 30
						spintrail.frame = $|FF_FULLBRIGHT
						if yu.lsadash
							spintrail.scale = $*5/4
							spintrail.scalespeed = $/2
							spintrail.destscale = spintrail.scalespeed+1
						end
					end
				end
	end
end)

--Spawn SA2-esque wind lines behind Sonic! Function edited from SMSreborn.

rawset(_G, "YuWindSpawn", function(p, s, yu)
if (p.speed < 41*s.scale)
return
end
	local tmomx = (s.x-yu.lastx)
	local tmomy = (s.y-yu.lasty) 
	local tmomz = (s.z-yu.lastz) --SRB2's mom values won't help me here.
	for d = -1,1,2			
			local ghs = P_SpawnMobj(s.x+(tmomx/2)+FixedMul((P_RandomRange(9, 35)*s.scale*d), cos(s.angle+ANGLE_90)), s.y+(tmomy/2)+FixedMul((P_RandomRange(9, 35)*s.scale*d), sin(s.angle+ANGLE_90)), s.z+tmomz+(P_RandomRange(1, 58)*P_MobjFlip(s))*s.scale, MT_YUWINDLINE)			
			ghs.scale = s.scale
			ghs.eflags = s.eflags
			ghs.angle = R_PointToAngle2(s.x, s.y, (s.x+s.momx), (s.y+s.momy))-((ANG2*3)*d)
			ghs.momx = tmomx/4 ghs.momy = tmomy/4 ghs.momz = tmomz-(tmomz/2)			
			if ((s.momz*P_MobjFlip(s)) < -4*s.scale)
				P_Thrust(ghs, s.angle+ANGLE_90, 1*s.scale*d)
			else
				P_Thrust(ghs, s.angle+ANGLE_90, 3*s.scale*d)
			end
			ghs.flags = $|MF_SCENERY
						
			if (s.eflags & MFE_UNDERWATER)
				ghs.fuse = 7
				if leveltime % 2 == 0
				ghs.state = S_MEDIUMBUBBLE
				else
				ghs.state = S_SMALLBUBBLE
				end
			end
			if s.eflags & MFE_VERTICALFLIP
			ghs.spriteyoffset = -46*FRACUNIT
			end
			if yu.superaura and yu.supersonic
			ghs.blendmode = AST_ADD
			ghs.colorized = true
			ghs.color = SKINCOLOR_BLUE
			end
	 end
end)

--Make stuff shiny. Doesn't need to come from a player, btw.

rawset(_G, "YuGoldenShine", function(p, s, yu, color, style)
	for d = 1,style
	local shine = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_YUTHOK)
	shine.sprite = SPR_OILF	  
	shine.frame = A|TR_TRANS90|FF_FULLBRIGHT
		if style == 3
			if d == 1
			shine.scale = (s.scale*5)/7
			elseif d == 2
			shine.scale = (s.scale*5)/8
			else			
			shine.scale = (s.scale*5)/12
			end
		else
		shine.scale = s.scale
		end
	shine.tics = 2
	shine.momx = s.momx
	shine.momy = s.momy
	shine.momz = s.momz
	shine.blendmode = AST_ADD
	if leveltime % 2 == 0
	shine.scalespeed = $-500
	else
	shine.scalespeed = $+1000
	end
	shine.destscale = 9
	shine.flags = MF_NOCLIP|MF_NOCLIPHEIGHT
	
		if color --Unique color?
		shine.color = color
		shine.colorized = true
		end
		if style == 3 --Adventure style sparkle lines!
			if d == 3
			shine.sprite = SPR_OILF	  
			shine.frame = A|TR_TRANS70|FF_FULLBRIGHT
			end
			
			local ghs
			local ghs2			
			local angle = P_RandomRange(0,359)*ANG1
			
				if not yu.invincibilityline --Vertical


					if not P_RandomRange(0,1)			
					ghs = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz+(s.height*4/3), MT_YUTHOKDISP)				
					ghs.ivheight = (s.height*10/P_RandomRange(5,8))
					ghs.ivthrust = P_RandomRange(3,11)*s.scale
					P_SetObjectMomZ(ghs, ghs.ivthrust)
					end
				
				yu.invincibilityline = 1
				
				elseif yu.invincibilityline == 1 --Diagonal
				
				ghs = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz+(s.height*2/3), MT_YUTHOKDISP)			
				ghs.ivheight = (s.height/2)			
				ghs.ivthrust = P_RandomRange(10,13)*s.scale				
				P_InstaThrust(ghs, angle, ghs.ivthrust)
				P_SetObjectMomZ(ghs, ghs.ivthrust)
				
					if not P_IsObjectOnGround(s) 
					ghs2 = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz, MT_YUTHOKDISP)			
					ghs2.ivheight = (s.height/-9)
					ghs2.ivthrust = P_RandomRange(-10,-13)*s.scale
					ghs2.invertspark = true
					P_InstaThrust(ghs2, angle, ghs2.ivthrust)
					P_SetObjectMomZ(ghs2, ghs2.ivthrust)
					end
				
				yu.invincibilityline = 2
				
				else --Horizontal			
				
				ghs = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz+s.height/3, MT_YUTHOKDISP)			
				ghs.ivthrust = P_RandomRange(30,35)*s.scale
				ghs.ivheight = (s.height*2/5)
				
				P_InstaThrust(ghs, angle, ghs.ivthrust)	
				yu.invincibilityline = 0		
				end

				if ghs and ghs.valid
				ghs.invthrustx = ghs.momx
				ghs.invthrusty = ghs.momy
				ghs.invthrustz = ghs.momz
				ghs.momx = s.momx ghs.momy = s.momy ghs.momz = s.momz
				ghs.scale = s.scale/11
				
				ghs.frame = $|FF_FULLBRIGHT|TR_TRANS30
				ghs.momx = $+s.momx ghs.momy = $+s.momy ghs.momz = $+s.momz+(s.scale*2*P_MobjFlip(s))
				ghs.yulsatarget = s
				ghs.invincibleaura = true
				ghs.tics = 7
				ghs.scalespeed = $/10
				ghs.color = color
				ghs.yulsanum = yu.invincibilityline+1
				ghs.blendmode = AST_ADD
				ghs.destscale = ghs.scalespeed+1
				end
				
				if ghs2 and ghs2.valid
				ghs2.invthrustx = ghs2.momx
				ghs2.invthrusty = ghs2.momy
				ghs2.invthrustz = ghs2.momz*-1
				ghs2.momx = s.momx ghs2.momy = s.momy ghs2.momz = s.momz
				ghs2.scale = s.scale/11
				
				ghs2.frame = $|FF_FULLBRIGHT|TR_TRANS30
				ghs2.momx = $+s.momx ghs2.momy = $+s.momy ghs2.momz = $+s.momz+(s.scale*2*P_MobjFlip(s))
				ghs2.yulsatarget = s
				ghs2.invincibleaura = true
				ghs2.tics = 7
				ghs2.scalespeed = $/10
				ghs2.color = color
				ghs2.yulsanum = yu.invincibilityline+1
				ghs2.blendmode = AST_ADD
				ghs2.destscale = ghs2.scalespeed+1	
				end
		end	
	end
		
end)

--Stop Lightdash related properties. Momentum stuff will have to be done manually still.

rawset(_G, "YuStopLSA", function(p, s, yu)
	yu.lsahoming = 0
		if s.target and yu.lsatarget and s.target == yu.lsatarget
		s.target = nil
		end
	yu.vertstylecharge = 0	
	yu.ldvertstyle = false	
	yu.lsatarget = nil
	yu.lsaaattack = 0
	yu.lightdashing = false
	yu.lsaclosest = nil
	yu.lightdashtimer = 0
	yu.lsacheck = 0
	yu.lsatarget = nil
	yu.prevringx = nil yu.prevringy = nil yu.prevringz = nil
	if not ((p.cmd.buttons & BT_USE) and yu.startdash and yu.spin == 2 and (p.pflags & PF_STARTDASH))
	p.pflags = $ & ~PF_SPINNING	& ~PF_STARTDASH
	yu.startdash = 0
	end
end)


--MATH...MAAAAAAAAATHHHH.......groan. Yeah, if I was good at that, maybe. This only came to be out of trying random numbers 1000 times.
--I say yes way too casually to requests like "why not apply BOTH SA1 and SA2 LightSpeed fx for the lulz"

rawset(_G, "YuLSAglow", function(p, s, yu, momz, dist, glow, freq, postthink)
			
				--Setup
				if yu.lsaangle == nil or yu.lsaangle2 == nil
				yu.lsaangle = 90
				yu.lsaangle2 = yu.lsaangle*ANG1
				end
				
				if glow
				--Our glow pulses around us.
					if yu.lsaglow > 2000
					yu.lsaglowd = -1
					elseif yu.lsaglow < 970
					yu.lsaglowd = 1
					end
					yu.lsaglow = $+(970*yu.lsaglowd)
				
				--Spawn the encasing glow around Sonic's form.
					for d = 0,2			
					local ghs = P_SpawnMobjFromMobj(s, 0, 0, (s.scale*-8), MT_YUTHOKDISP)
					
						ghs.skin = "adventuresonic"
					
						if d != 0
							ghs.scale = s.scale+(((s.scale/7)*d+(yu.lsaglow*d)))
							if not ((ghs.spriteyscale-yu.lsaglow) < 1)
							ghs.spriteyscale = $-yu.lsaglow
							end
							ghs.spritexscale = FRACUNIT+yu.lsaglow
						end
						if (s.eflags & MFE_VERTICALFLIP)
							ghs.z = YuFlipZ(s, ghs)+(s.scale*8)
							P_SetObjectMomZ(ghs, ghs.scalespeed*100, true)
						end
						if p.ctfteam and p.ctfteam == 1 and G_GametypeHasTeams() or yu.attackpriority
						ghs.color = SKINCOLOR_RED --In CTF/teammatch, glow red instead of blue if you're on red team.
						else
						ghs.color = SKINCOLOR_YULSA
						end
						if p.powers[pw_super] and not p.ctfteam
						ghs.color = SKINCOLOR_SUPERSILVER1
						ghs.scalespeed = $*4
						ghs.blendmode = AST_ADD
						end
						ghs.colorized = true
						
						if postthink
							ghs.angle = p.drawangle
							ghs.tics = 1
							P_TeleportMove(ghs, s.x, s.y, s.z-((((s.scale*7)*d)-(ghs.scale-s.scale))*P_MobjFlip(s)))
							ghs.sprite = s.sprite
							ghs.rollangle = s.rollangle
							ghs.sprite2 = s.sprite2
							ghs.spriteyoffset = $+s.spriteyoffset
							ghs.spritexoffset = $+s.spritexoffset
							if d == 0
							ghs.frame = (s.frame & ~FF_TRANSMASK)|TR_TRANS40|FF_FULLBRIGHT
							else
							ghs.frame = (s.frame & ~FF_TRANSMASK)|(TR_TRANS40+(d*FRACUNIT))|FF_FULLBRIGHT
							end
						else
							ghs.tics = 2
							ghs.yulsatarget = s --This is your hedgehog.
							ghs.yulsanum = d --Remember what number you're assigned						
						end
				
					end
				end
				
				if yu.lsadash
				return
				end
				
				--Spawn Sonic's large glowing orbs of justice
				if (leveltime % freq == 0)
				
				/*	--Reverse angle everytime.
					if yu.lsaorbangle == ANGLE_180
					yu.lsaorbangle = 0
					else
					yu.lsaorbangle = ANGLE_180
					end */
				
				local ghs = P_SpawnMobj(s.x+FixedMul(dist, cos(yu.lsaangle2)), s.y+FixedMul(dist, sin(yu.lsaangle2)), s.z+(s.scale*8), MT_YULDORB)
					ghs.target = s
					ghs.tracer = s
					ghs.yuldmomz = momz
					ghs.yulddist = dist
						if momz == 1 and not p.powers[pw_super]
						ghs.scale = s.scale/7
						else
						ghs.scale = s.scale/4
						end
					ghs.blendmode = AST_ADD
					ghs.yuldangle = yu.lsaangle2
					ghs.tics = 45
						if (s.eflags & MFE_VERTICALFLIP)
						ghs.z = YuFlipZ(s, ghs)+(s.scale*8)
						end
					ghs.frame = K|FF_FULLBRIGHT|TR_TRANS20 & ~TR_TRANS50 & ~TR_TRANS60 & ~TR_TRANS40 & ~TR_TRANS30
					if p.powers[pw_super]
						if yu.hypersonic
						ghs.color = p.yuemeraldcolors2[yu.hypercolor]+4
						else
						ghs.color = s.color
						end
					else
					ghs.color = SKINCOLOR_SUPERSKY5
					end
				end
				
				--Keep the angle change at the end!
				if (yu.lsaangle > 358)
					yu.lsaangle = 0
				else
					yu.lsaangle = $+20
				end
end)

--Are we above a death pit?

rawset(_G, "YuCheckPit", function(p, s, yu, skip)
	if skip or not P_IsObjectOnGround(s)
		if P_PlayerTouchingSectorSpecial(p, 1, 7) or P_PlayerTouchingSectorSpecial(p, 1, 6)
			if s.subsector and s.subsector.sector
			and ( ((s.floorz == s.subsector.sector.floorheight) and not (s.eflags & MFE_VERTICALFLIP)) or ((s.eflags & MFE_VERTICALFLIP) and (s.ceilingz == s.subsector.sector.ceilingheight)) )
			return true
			elseif not s.subsector //Can't obtain info? Then assume it's a death pit
			return true
			end
		end
	end
	return false
end)

--Another lazy function.

rawset(_G, "YuCancelTricks", function(p, s, yu)
	yu.homingtrick = 0
	yu.lsatrick = nil
	s.rollangle = 0
	yu.chosentrick = 0
	yu.lsatrickrollang = 0
	yu.lsatrickanim = 0
	yu.advance2trail = 0
end)

--The beginning of the bounce attack!

rawset(_G, "YuStartBounce", function(p, s, yu)
if p.gotflag -- Not with the flag.
or yu.lsadash or yu.lsahoming or p.exiting
return end
		p.pflags = $|PF_JUMPED & ~PF_THOKKED & ~PF_SPINNING		
			if (s.momz*P_MobjFlip(s) > -25*FRACUNIT)
			P_SetObjectMomZ(s, -35*FRACUNIT)
			else
			P_SetObjectMomZ(s, -10*FRACUNIT, true)
			end
			if (yu.hypersonic or yu.mysticsuper) and (s.momz*P_MobjFlip(s) < 0)
			s.momz = $*2
			end
		YuCancelTricks(p, s, yu)	
		yu.superaura = 0
		yu.superaurabuild = 0			
		s.momx = $*3/4
		s.momy = $*3/4
		s.state = S_PLAY_ROLL
			if not yu.bouncestate
			yu.firstbounce = false
			end
		yu.forceledgeprotect = 0
		if not yu.bouncestate
		and (yu.supersonic or p.powers[pw_sneakers])
		yu.superbouncetime = 11
		end
		yu.bouncestate = 1
		yu.spin = 3
		yu.startdash = 0
		yu.noairdrag = 0
		yu.bounceframe = 2
		s.spriteyscale = FRACUNIT+10002
		s.spritexscale = FRACUNIT-15002
		yu.alteredscale = false
end)

--Stop the LSA Dash!(The part where Sonic dashes forwards, not necessarily the homing/lightdashing, though that'll end here too)

rawset(_G, "YuStopLSAdash", function(p, s, yu)
		YuResetBounce(p, s, yu)
		yu.ldvertstyle = false		
		yu.startdash = 0
		yu.lightdashtimer = 0		
		yu.lsadash = 0
		yu.ringtarget = nil
		yu.hitspring = 0
		yu.lsahoming = 0
		yu.lightdashing = false
		yu.noairdrag2 = 4
		yu.prevringx = nil yu.prevringy = nil yu.prevringz = nil
end)

--A special function for the special state of the Bounce Attack!

rawset(_G, "YuBounce", function(p, s, yu)
yu.noairdrag = 0
				if yu.bouncefloor and s.pmomz --Teleport up if you're on a platform so you don't hit it again, because SRB2 coding is genius.
					if (s.eflags & MFE_VERTICALFLIP) 
						if (s.pmomz > 0)
						s.momz = $+s.pmomz*-1
						end
					else
						if (s.pmomz < 0) --Don't decrease bounce height when bouncing off lowering platforms.
						s.momz = $+s.pmomz*-1
						end
					end
					s.eflags = $ & ~MFE_JUSTHITFLOOR
					s.z = $+(6*s.scale*P_MobjFlip(s))
					p.pflags = $|PF_JUMPED & ~PF_THOKKED & ~PF_SPINNING
					yu.firstbounce = true
					yu.bouncefloor = 0
				end
				if s.state == S_PLAY_ROLL
					if not (leveltime % 2 == 0)
					s.flags2 = $|MF2_DONTDRAW
					end
					if s.tics > 1 or s.anim_duration > 1
						s.anim_duration = 1
						s.tics = 1
					end
					if ((s.frame & ~FF_FULLBRIGHT & ~FF_SPR2SUPER) >= H)
						s.frame = A
					else
						s.frame = $+1
					end
				end
				
				if not s.health or (s.eflags & MFE_SPRUNG) or P_PlayerInPain(p)
				or p.powers[pw_carry] or (s.state == S_PLAY_PAIN) or (s.state == S_PLAY_GASP) --Cancel bounce when...
					YuResetBounce(p, s, yu)
					return
				elseif yu.bouncestate == 1 --Going down?
					YuSpinTrail(p, s, yu)
					DoSpinRev(p, s, yu, YuAuraColor(s, nil, yu, true))
					if (s.state != S_PLAY_ROLL)
						s.state = S_PLAY_ROLL
					end
					if (s.eflags & MFE_GOOWATER) and (s.momz*P_MobjFlip(s) >= 1)
					and ( ((s.z <= s.floorz+5*FRACUNIT) and not (s.eflags & MFE_VERTICALFLIP))
					or ((s.z+s.height >= s.ceilingz-20*FRACUNIT) and (s.eflags & MFE_VERTICALFLIP)) )
						P_SetObjectMomZ(s, 760000)
						yu.bouncestate = 2
						S_StartSound(s, sfx_yusfx3)
						yu.firstbounce = true
						return
					end
					if (s.momz*P_MobjFlip(s) > FRACUNIT) and not s.pmomz --Wait, we're going UP? How?? Well, switch to phase 2 then...
						yu.bouncestate = 2
						S_StartSound(s, sfx_yusfx3)
						yu.firstbounce = true						
						return
					end
					
					if ((s.eflags & MFE_JUSTHITFLOOR) or P_IsObjectOnGround(s)) --Land on the floor and BOUNCE!
					
						local sectorz = R_PointInSubsector(s.x, s.y).sector //Break through bustable floors below!
						for fof in sectorz.ffloors()
							if (fof.flags & FF_EXISTS) and ((fof.flags & FF_STRONGBUST) or (fof.flags & FF_BUSTUP))
							and not (s.z-99*FRACUNIT >= fof.topheight)
							and not (s.z+99*FRACUNIT+s.height < fof.bottomheight)
							local line = fof.master
							EV_CrumbleChain(fof)
								if (line.flags & ML_EFFECT5)
   								P_LinedefExecute(P_AproxDistance(line.dx, line.dy) >> FRACBITS, s, fof.target)
								end
							end
						end
						
						if P_PlayerTouchingSectorSpecial(p, 3, 6) or P_PlayerTouchingSectorSpecial(p, 3, 5)
						YuResetBounce(p, s, yu) --Speed pad? Cancel bounce and run!
						s.momz = 0
						S_StartSound(s, sfx_zoom)
							if (s.state == S_PLAY_ROLL) and not (p.pflags & PF_SPINNING)
							s.state = S_PLAY_FALL
							end
						return
						end
						
						s.pmomz = 0
						yu.runfriction = yu.groundfriction
						yu.skipgroundcheck = 2
						yu.bouncexstretch = 70
						yu.bounceystretch = 132
						
						s.state = S_PLAY_ROLL
						s.sprite2 = SPR2_ROLL

						if (s.eflags & MFE_UNDERWATER)
							yu.firstbounce = false
							P_SetObjectMomZ(s, 560000)
						elseif yu.firstbounce
							P_SetObjectMomZ(s, 930000)				
						else --Bounce higher on your second bounce.
							yu.firstbounce = true
							P_SetObjectMomZ(s, 820000)
						end
						if yu.hypersonic or yu.mysticsuper
						P_YuQuake(p, 50*FRACUNIT, 3)			
						S_StartSound(s, sfx_brakrx) S_StartSound(s, sfx_s1b9)
							if yu.hypersonic
							P_NukeEnemies(s, s, 1200*s.scale)
							else
							P_NukeEnemies(s, s, 250*s.scale)
							end
							if (s.momz*P_MobjFlip(s) > 0)
							s.momz = $*10/8
							end
							local rng = P_RandomRange(7,44)
							for d = 0,7 --Rocks!
								local debris = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_BOSSJUNK)
								if debris and debris.valid
								debris.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING
								debris.sprite = SPR_ROIA
								debris.frame = A
								debris.rollangle = (P_RandomRange(0,359)*ANG1)
								P_InstaThrust(debris, (ANGLE_45*d)-(rng*ANG1), rng*s.scale)
								P_SetObjectMomZ(debris, 13*s.scale-(rng/10), false)
								end
							end
							
						end
						
						yu.bouncefloor = 2
						p.pflags = $|PF_JUMPED & ~PF_THOKKED & ~PF_SPINNING	& ~PF_STARTJUMP			
						S_StartSound(s, sfx_yusfx3)
						yu.bouncestate = 2
						
						if (s.ceilingz-s.floorz < s.height+FRACUNIT) --Bounced into a tight coridor? Transition to spin.
						YuResetBounce(p, s, yu)
						p.pflags = $|PF_SPINNING & ~PF_THOKKED & ~PF_JUMPED & ~PF_STARTJUMP	
						end				
					end		
				end
				if (p.pflags & PF_THOKKED) --Fast Thok from bounce cancel!
					YuResetBounce(p, s, yu)
					s.state = S_PLAY_FALL
					s.momx = $*24/19
					if not ((s.flags2 & MF2_TWOD) or twodlevel)
						s.momy = $*24/19
					end
					yu.frictionlock = 2
					yu.runfriction = FRACUNIT
					s.friction = FRACUNIT
				end
end)
--Lazy function to reset LSA properties
rawset(_G, "ResetLSA", function(p, s, yu)
	yu.lsaattack = 0
	yu.lightdashing = false
	yu.lsaattackchain = 0
	yu.hadnotarget = 0
	yu.lsadeadjump = 0
	yu.lsahoming = 0
	yu.lightdashtimer = 0
	yu.lsatarget = nil
	yu.lsaclosest = nil
	S_StopSoundByID(s, sfx_yusfx5)
	S_StopSoundByID(s, sfx_yusfx6)
	if P_IsObjectOnGround(s) and (s.state == S_PLAY_ROLL) and not (p.pflags & PF_SPINNING)
		s.state = S_PLAY_FALL
	end
end)

--Lazy function to reset bounce properties
rawset(_G, "YuResetBounce", function(p, s, yu)
	yu.firstbounce = false
	yu.bouncestate = 0
	s.spriteyscale = FRACUNIT
	s.spritexscale = FRACUNIT
	yu.bouncexstretch = 100
	yu.bounceystretch = 100
	yu.skipgroundcheck = 0
end)

--Lazy function to reset pretty much all properties.

rawset(_G, "YuResetAll", function(p, s, yu)
	p.yumenutable = nil
	if p == consoleplayer and p.yusonictable and p.yusonictable.yumusic
		if S_MusicName() == "YUSUPR"	
			COM_BufInsertText(p, "tunes -default")
			P_RestoreMusic(p)
		end
	end
	yu.mysticsuper = 0
	yu.bosskiller = 0
	yu.endlvl = 0
	yu.tauntstate = 0
	yu.fallbuffer = 0
	yu.fallbuffer2 = 0
	yu.tauntdoll = 0
	yu.tauntroll = 0		
	yu.tauntno = 0	
	yu.tauntcd = 10
	yu.tauntdead = false
	yu.deathtouchedground = false
	yu.hassupershield = nil
	yu.startdash = 0
	yu.airborne = 0
	yu.advance2trail = 0
	yu.advance2roll = 0
	yu.homingtrick = 0
	yu.strongbspring = nil
	yu.strongspring = 0
	yu.sa2jumpdone = false
	yu.ledgeprotectcd = 0
	yu.forceledgeprotect = 0
	yu.edgenope = 0
	yu.speedup = 0
	yu.speedupreward = nil
	yu.speeduprewardfail = nil
	yu.frictionspeedtreshold = 0
	yu.frictionlock = 0
	yu.spindashfriction = false
	yu.groundfriction = 59392
	yu.runfriction = 59392
	yu.frictionreset = 180
	yu.alteredscale = false
	yu.bouncestate = 0
	yu.bouncefloor = 0
	yu.firstbounce = false
	yu.bouncexstretch = 100
	yu.bounceystretch = 100
	yu.maxcrush = 0
	yu.skipgroundcheck = 0
	yu.painrecovery = 0 
	yu.falltransition = 0
	yu.framejump = 5
	yu.noairdrag = 0
	yu.noubercontrol = 0
	yu.lastslopeunstuck = 0	
	yu.hitspring = 0
	yu.homingrecurl = 0
	yu.homingsetup = false
	yu.hominganim = 4
	yu.hominganim2 = 4
	yu.hominganim3 = 4
	yu.hominganimstart = 0
	yu.nospindrag = 50
	yu.lsacharged = false
	yu.lsaattack = 0
	yu.ringtarget = nil
	yu.lsadash = 0
	yu.dramaticdeath = false
	yu.burning = 0
	yu.spacedeath = false
	yu.drowning = false
	yu.drownanim = 0
	yu.drownanim2 = 0
	yu.electricdeath = 0
	yu.bombdeath = false
	yu.eleccolorized = false
	yu.lightdashing = false
	yu.spinanimspeed = 0
	yu.flyswitchdisabled = false
	yu.supersonic = false
	yu.hypersonic = false
	yu.downtheholedeath = false
	yu.downthehole = 0
	yu.downtheholefire = 0
	yu.ret2transform = 0
	yu.supertransform = 0
	yu.superflash = 0
	yu.superflashd = 1
	yu.hypermemories = 0
	yu.uncurlanim = nil
	yu.superaura = 0
	yu.superaurabuild = 0
	yu.nosarun4 = 0
	yu.vaultreadytarget = nil
	yu.superorigin = nil
	if s.valid 
		if yu.superoffset != 0
		s.spriteyoffset = 0
		end
		if s.state == S_PLAY_FLY
		s.state = S_PLAY_FALL
		end
	end
	yu.superoffset = 0
	yu.superoffsetd = 1	
	yu.jump = 0
	yu.spin = 0
	yu.custom2 = 0
	yu.custom3 = 0
	if not p.powers[pw_super]	
		p.charflags = $ & ~SF_CANBUSTWALLS
		p.charflags = $ & ~SF_SUPER
	end
	if yu.forceyuangletimer
		yu.forceyuangletimer = 0
		p.pflags = $ & ~PF_FORCESTRAFE
	end
end)

--Yes, uncurling comes with alot of special properties for Yu Sonic

rawset(_G, "YuUncurl", function(p, s, yu)
		if (s.eflags & MFE_UNDERWATER) or p.gotflag
			if s.friction > FRACUNIT
			s.friction = FRACUNIT
			yu.runfriction = FRACUNIT
			end
			s.momx = $*10/11 --No friction shenanigans underwater. Only slow.
			s.momy = $*10/11
		else
			s.friction = FRACUNIT
			yu.runfriction = FRACUNIT
					
			yu.frictionlock = 8
			if p.speed > 2*FRACUNIT
				yu.frictionlock = $+((p.speed/FRACUNIT)/4)
			end
			if yu.frictionlock > 20
			yu.frictionlock = 20
			end
		end
					
		p.pflags = $ & ~PF_SPINNING & ~PF_STARTDASH & ~PF_THOKKED & ~PF_JUMPED
		
			if not P_IsObjectOnGround(s)
				yu.superaurabuild = $+3
				if (s.momz*P_MobjFlip(s) > 6*s.scale)
					s.state = S_PLAY_SPRING
				else
					s.state = S_PLAY_FALL
				end
			else
				yu.superaurabuild = $+1
				if (p.speed < 45*s.scale)
						s.state = S_PLAY_WALK
				else
						s.state = S_PLAY_RUN
				end
				s.frame = P_RandomRange(0,7)
					
				yu.uncurlanim = A
				s.sprite2 = SPR2_ROLL
				s.frame = A
			end
		yu.frictionreset = 180
		yu.startdash = 0
		yu.spin = 3
end)

--Lightdash cancel gfx

rawset(_G, "YuLSAgfx", function(p, s, yu)
		if not (yu.bonkeddash > 3)
		local boom = P_SpawnMobjFromMobj(s, 0, 0,0, MT_YUINSTASHIELD)
		boom.scalespeed = $*6
		boom.destscale = s.scale*99
		boom.blendmode = AST_ADD
		end
		for d = 1,4
		local ghs = P_SpawnGhostMobj(s)
			ghs.tics = 6+(d*3)
			ghs.fuse = 6+(d*3)
			ghs.scalespeed = $*d
			ghs.destscale = $*99
			ghs.frame = $ & ~TR_TRANS50 & ~TR_TRANS60 & ~TR_TRANS70 & ~TR_TRANS80
			ghs.frame = $|(TR_TRANS50+(d*FRACUNIT))
			ghs.flags = $|MF_NOCLIPHEIGHT
			ghs.momz = $-((ghs.scalespeed*12)*P_MobjFlip(s))
			if yu.supersonic
			ghs.blendmode = AST_ADD
			ghs.color = SKINCOLOR_CRIMSON
			else
			ghs.color = (SKINCOLOR_SUPERSKY5-d)
			end
			ghs.colorized = true
			ghs.momx = (s.momx*3)/2 ghs.momy = (s.momy*3)/d
		end
end)

--Cancel LSA. Comes with some aftereffects.

rawset(_G, "YuCancelLSA", function(p, s, yu)
		S_StartSound(s, sfx_mswing)
		yu.lsacharged = false
		yu.lsacharge = 0
			if not yu.autojumproll
			s.momx = $/2 s.momy = $/2
			end
		YuLSAgfx(p,s,yu)
		if not P_IsObjectOnGround(s) and not p.homing and not p.powers[pw_carry] and not yu.autojumproll
			s.momz = $/2
			s.state = S_PLAY_FALL
			yu.sa2jumpdone = false
		end
end)

--LSA Impact. Extra effects to make hitting enemies with this more juicy!

--Determine our color real quick....
local function DoDebrisColor(s, debris, color)
color = SKINCOLOR_SILVER
		if s.color
			color = s.color
		elseif (s.type == MT_BLUECRAWLA) or (s.type == MT_SPRINGSHELL)  or (s.type == MT_YELLOWSHELL) or (s.type == MT_PENGUINATOR)
			color = SKINCOLOR_CORNFLOWER
		elseif (s.type == MT_GFZFISH) or (s.type == MT_CRAWLACOMMANDER) or (s.type == MT_METALSONIC_BATTLE)
			color = SKINCOLOR_COBALT
		elseif (s.type == MT_GSNAPPER) or (s.type == MT_JETTBOMBER) or (s.type == MT_ROBOHOOD)
			color = SKINCOLOR_GREEN
		elseif (s.type == MT_REDCRAWLA) or (s.type == MT_REDBUZZ) or (s.type == MT_DETON) or (s.type == MT_VULTURE) or (s.type == MT_CRUSHSTACEAN)
			color = SKINCOLOR_RED
		elseif (s.type == MT_EGGGUARD) or (s.type == MT_BANPYURA) or (s.type == MT_PTERABYTE)
			color = SKINCOLOR_LAVENDER
		elseif (s.type == MT_FACESTABBER) or (s.type == MT_JETJAW)
			color = SKINCOLOR_CRIMSON
		elseif (s.type == MT_DRAGONBOMBER) or (s.type == MT_PYREFLY) or (s.type == MT_CANARIVORE) or (s.type == MT_SNAILER) or (s.type == MT_GOLDBUZZ)
		or (s.type == MT_HIVEELEMENTAL) or (s.type == MT_BUMBLEBORE)
			color = SKINCOLOR_GOLD
		elseif (s.type == MT_JETTGUNNER) or (s.type == MT_CYBRAKDEMON)
			color = SKINCOLOR_BROWN
		elseif (s.type == MT_UNIDUS) or (s.type == MT_POPUPTURRET) or (s.type == MT_MINUS)
			color = SKINCOLOR_CARBON
		end
return color
end

rawset(_G, "YuLSAimpact", function(p, so, yu, s) --s is target getting hit, so is the player.

			if CBW_Chaos and (gametype == GT_CHAOS)
				if s and ((s.flags & MF_ENEMY) or (s.flags & MF_BOSS))
				yu.lsalimit = $+1
				end
			end
			yu.lsadeadjump = 1
			so.target = nil
			yu.lsalasttarget = yu.lsatarget
			yu.lsaclosest = nil
			yu.lsatarget = nil

			S_StartSound(so, sfx_bedeen)
			S_StartSound(so, sfx_brakrx)	
			
				for d = 0,7
					local debris = P_SpawnMobj(s.x+(P_RandomRange(-50,50)*s.scale), s.y+(P_RandomRange(-50,50)*s.scale), s.z+(P_RandomRange(5,80)*s.scale), MT_BOSSJUNK)
					if debris and debris.valid
					debris.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING
					debris.scale = s.scale*30/P_RandomRange(20,35)
					debris.sprite = SPR_YUSO
					debris.frame = P_RandomRange(17,21)
					debris.color = SKINCOLOR_SILVER
					P_InstaThrust(debris, so.angle+(P_RandomRange(-30,30)*ANG1), (P_RandomRange(10,36)*s.scale)+p.speed)
					P_SetObjectMomZ(debris, P_RandomRange(2,12)*s.scale, false)
					
						if (s.flags & MF_ENEMY) --Actually hit an enemy?
							if (debris.frame < T)
							debris.color = DoDebrisColor(s, debris, color)
							end
							if (d > 6) --Break off specific pieces.
								if (s.type == MT_BLUECRAWLA)
								debris.sprite = SPR_BRKN
								debris.frame = A
								elseif s.type == MT_REDCRAWLA
								debris.sprite = SPR_BRKN
								debris.frame = A
								debris.color = SKINCOLOR_CRIMSON
								debris.colorized = true
								elseif s.type == GOLDBUZZ
								debris.sprite = SPR_BRKN
								debris.frame = I
								elseif (s.type == MT_SPRINGSHELL) or (s.type == MT_YELLOWSHELL)
								debris.sprite = SPR_BRKN
								debris.frame = E							
								elseif s.type == MT_FACESTABBER
								debris.sprite = SPR_BRKN
								debris.frame = Q							
								elseif s.type == MT_GSNAPPER
								debris.sprite = SPR_BRKN
								debris.frame = U								
								end
							end
						end
					end
				end
				
				local boom = P_SpawnMobjFromMobj(s, 0, 0,0, MT_YUINSTASHIELD)
				boom.scalespeed = $*11
				boom.destscale = s.scale*99
				boom.blendmode = AST_ADD
			
end)

--Lightdash function. Searches blockmaps, then rushes for the rings! No nearby target = FAIL.

rawset(_G, "YuLightDash", function(p, s, yu)

	local spring = false
	local skip = false
	local lock = 0
	local oldtarget = yu.ringtarget --If we had a target prior to this, store it here!
	
	if yu.ringtarget and yu.ringtarget.valid and not (yu.ringtarget.health <= 0)
	skip = true
	else
	yu.ringtarget = nil --We'll start with no target, then.
	end
	
	if P_IsObjectOnGround(s) --No ground today.
	s.z = s.z+(10*FRACUNIT*P_MobjFlip(s))
	end	
	--Okay, now let's search for a ring.
	if not skip --If we're not at our current ring yet, then don't look for a new one!
   	searchBlockmap("objects", function(ref, m) --Blockmaps save us the trouble from having to look through ALL of the map.
	
		if not yu.ldvertstyle 
		and ( (m.flags & MF_SPRING) and not m.info.damage --Without a damage value, springs have no horizontal power!
		or ((m.type >= MT_FAN) and (m.type <= MT_BLUESPRING)) )
			spring = true --Found a spring-esque object. Vertical lightdash is practically guaranteed!
		end
		if ((m.type == MT_RING) or (m.type == MT_COIN) or (m.type == MT_BLUESPHERE) --Anything around?
		or ((m.type == MT_REDTEAMRING) and p.ctfteam == 1)
		or ((m.type == MT_BLUETEAMRING) and p.ctfteam == 2)
		or ((m.type >= MT_BOUNCERING) and (m.type <= MT_GRENADEPICKUP)))
			if not (m.health <= 0) --It's alive and we can see it?
			and (P_CheckSight(s, m))
			and (m.flags & MF_SPECIAL) --Conveniently all objects we're looking for have MF_SPECIAL.
			
				--Vertical ring-follow style! We'll no longer chase rings at or below our height, ensuring we go skyward!
				if yu.ldvertstyle
					if (yu.prevringx == m.x and yu.prevringy == m.y) and not (yu.prevringz == m.z) and not (m.z <= s.z)
					and not (m.z > (s.z+(364*FRACUNIT*P_MobjFlip(s))) )
						yu.ringtarget = m
						lock = 1
					elseif lock != 1
					local lastditch = 0
						for d = 41,1,-4
						if not lastditch
							if (FixedHypot(s.x-m.x, s.y-m.y) <= ((150*FRACUNIT)/d)) --Let's try this first. Favor vertical upward lines!
								if yu.ldvertstyle == -1
									if not (yu.prevringz >= m.z) and not (s.z >= m.z)
									and not (m.z > (s.z+(364*FRACUNIT*P_MobjFlip(s))) )	
									yu.ringtarget = m
									lastditch = d
									end
									
								else
									if not (yu.prevringz <= m.z) and not (m.z <= s.z)
									and not (m.z > (s.z+(364*FRACUNIT*P_MobjFlip(s))) )
									yu.ringtarget = m
									lastditch = d
									end
								end
							end
						end
						end
					end
				else	
					if spring and yu.prevringx == m.x and yu.prevringy == m.y and not yu.prevringz == m.z
					and not (m.z > s.z+(364*FRACUNIT*P_MobjFlip(s)))
					and not (m.z < s.z-(140*FRACUNIT*P_MobjFlip(s)))
						yu.ringtarget = m
						s.momx = $/40 s.momy = $/40
						yu.vertstylecharge = $+2
						lock = 1
					elseif spring and lock != 1 and (FixedHypot(s.x-m.x, s.y-m.y) <= 31*FRACUNIT) --Second attempt. Distance check.
					and not (m.z > s.z+(364*FRACUNIT*P_MobjFlip(s)))
					and not (m.z < s.z-(140*FRACUNIT*P_MobjFlip(s)))
						if not (yu.ringtarget and FixedHypot(FixedHypot(s.x-m.x, s.y-m.y), s.z-m.z) >
						FixedHypot(FixedHypot(s.x-yu.ringtarget.x, s.y-yu.ringtarget.y), s.z-yu.ringtarget.z))					
						yu.ringtarget = m
						s.momx = $/2 s.momy = $/2
						yu.vertstylecharge = $+2
						lock = 2
						end
					elseif not lock and (FixedHypot(FixedHypot(s.x-m.x, s.y-m.y),s.z-m.z) <= 300*FRACUNIT) --Still no? Try all-around then!
						if not (yu.ringtarget and FixedHypot(FixedHypot(s.x-m.x, s.y-m.y), s.z-m.z) >
							FixedHypot(FixedHypot(s.x-yu.ringtarget.x, s.y-yu.ringtarget.y), s.z-yu.ringtarget.z)) --Closest one gets priority!
							yu.ringtarget = m
        				end
					end
				end
				
			end
		end
  	end, s, s.x-300*FRACUNIT, s.x+300*FRACUNIT, s.y-300*FRACUNIT, s.y+300*FRACUNIT)
	end
	
	--Ring Dashing time!
	
	if yu.ringtarget and yu.ringtarget.valid --Did we find a target?
	local t = yu.ringtarget
		s.state = S_YU_LIGHTDASH
		if not yu.ldvertstyle
			s.angle = R_PointToAngle2(s.x, s.y, t.x, t.y)
			p.drawangle = s.angle
		else
			s.angle = yu.lsadashlastangle --Try not to disorient the player with spazzing while we go up!
			p.drawangle = s.angle
		end
		
		--This homing setup we use for LSA too, to end up EXACTLY where the ring actually is rather than beelining from 1 inch away.
		local mult = FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z)
		if mult < 1
			mult = 1
    	end
		s.momx = FixedMul(FixedDiv(t.x-s.x, mult), (70*FRACUNIT)) 
		s.momy = FixedMul(FixedDiv(t.y-s.y, mult), (70*FRACUNIT))
		s.momz = FixedMul(FixedDiv(t.z-s.z, mult), (70*FRACUNIT))		
	
		p.pflags = $ & ~PF_JUMPED & ~PF_SPINNING & ~PF_STARTDASH
		yu.startdash = 0
		yu.lsacheck = 3
		yu.lsaclosest = nil
		yu.lsadash = 0
		yu.lsaattack = 0
		yu.lightdashaftereffects = 12
		yu.lightdashtimer = $+1						
		yu.framejump = 0
		yu.nosarun4 = 2
						
			if yu.spin == 1 --Mash to break free early if you can't wait 1 second when the Lightdash gets stuck.
				yu.lightdashtimer = $+10
			end
			if oldtarget != t
			yu.lightdashtimer = 1
				if not yu.ldvertstyle			
					if (yu.vertstylecharge < 0)
						yu.vertstylecharge = 0
					end
					if t.x == yu.prevringx
					and t.y == yu.prevringy
					yu.vertstylecharge = $+3
					end
					if (yu.vertstylecharge > 5) or spring
						if (s.momz < -1)
							yu.ldvertstyle = -1
						else
							yu.ldvertstyle = 1
						end
					end
				end
			end
			if (yu.lightdashtimer < 40) --Give Sonic the LSAhoming property while we're doing this.
				yu.lsahoming = 5
			else --Okay, we're homing onto the same target too long, stop this madness!
				s.momx = $/5
				s.momy = $/5
				s.momz = $/5
				YuStopLSAdash(p, s, yu)
				S_StartSound(s, sfx_ngskid)
				YuStopLSA(p, s, yu)
				ResetLSA(p, s, yu)
				yu.lsahoming = 0
				yu.lightdashtimer = 0
			end
			
			--Finally, save this thing's coordinates!
			yu.prevringx = t.x
			yu.prevringy = t.y
			yu.prevringz = t.z
			
		return true --Success!
    elseif yu.lightdashing --We're at the end of the Lightdash!
		if (yu.ldvertstyle or ((s.momz*P_MobjFlip(s)) > 19*FRACUNIT)) and yu.lsadashlastangle != nil
		s.angle = yu.lsadashlastangle
		end
		yu.prevringx = nil
		yu.prevringy = nil
		yu.prevringz = nil
		yu.ringtarget = nil
		yu.lsahoming = 0
		yu.lsacheck = 0
		yu.lightdashtimer = 0
		yu.vertstylecharge = 0
		yu.ldvertstyle = false
		yu.lightdashing = false
		yu.speedupreward = true
		yu.lsatarget = nil
		s.target = nil
	end
	return false
end)

--The main LightSpeed Attack and LightDash function! Let's gooo! Also, make sure Sonic has a target before activating this function!

rawset(_G, "YuLightSpeed", function(p, s, yu)

				if not yu.lsaattack and not yu.lightdashing --We dunno what type of move we're using? Then determine that first.
					if s.target and s.target.valid and s.target.health and P_CheckSight(s, s.target) and yu.lsatarget and s.target == yu.lsatarget
					local m = s.target
					yu.hadnotarget = 1
						if ((m.type == MT_RING) or (m.type == MT_COIN) or (m.type == MT_BLUESPHERE) 
						or (m.type == MT_REDTEAMRING)
						or (m.type == MT_BLUETEAMRING)
						or ((m.type >= MT_BOUNCERING) and (m.type <= MT_GRENADEPICKUP))) --Yep, these are lightdash objects.
						
							yu.hitspring = 0
							yu.lsaattack = 0
							yu.lsadeadjump = 0
							yu.lightdashtimer = 0
							yu.lightdashing = true						
							
						else --Uhh, just assume if it's not those it's probably something we wanna attack.
							yu.hitspring = 0
							yu.lsaattack = 1
							yu.lightdashing = false
							yu.lsadeadjump = 0
							yu.lsaattackchain = 2
							YuLSAgfx(p, s, yu)
					
								if (s.state != S_PLAY_ROLL) --Always rollin', always hatin'
								s.state = S_PLAY_ROLL
								end							
											
						end
					end
				end
				if yu.lightdashing --Lightdash!
					
					YuLightDash(p, s, yu) --Big Function
					yu.jump = 10 yu.spin = 10 yu.custom3 = 10
					//	yu.forceyuangletimer = 2
					//	yu.forceyuangle = s.angle
					
					if yu.lightdashing and yu.lsahoming
					or yu.lightdashaftereffects
						local ghs = P_SpawnGhostMobj(s)
						ghs.rollangle = s.rollangle
						ghs.tics = 14 ghs.fuse = 14 ghs.destscale = $*3
						ghs.colorized = true
						if p.powers[pw_super]
							ghs.color = s.color
						else
							ghs.color = SKINCOLOR_SUPERSKY3
						end
						ghs.frame = $|TR_TRANS90 & ~TR_TRANS30 & ~TR_TRANS40 & ~TR_TRANS50 & ~TR_TRANS60 & ~TR_TRANS70 & ~TR_TRANS80
						ghs.flags2 = $|MF2_SHADOW
						ghs.blendmode = AST_ADD
						
						if yu.lightdashing
						p.pflags = $ & ~PF_SPINNING & ~PF_JUMPED & ~PF_STARTDASH & ~PF_THOKKED & ~PF_NOJUMPDAMAGE
						end
					end
					
				elseif yu.lsaattack --Lightspeed Attack!
				
				YuSpinTrail(p, s, yu)
					if p == consoleplayer 
						if yu.lsacamspeed == nil
						yu.lsacamspeed = CV_FindVar("cam_speed").string
						COM_BufInsertText(p, "cam_speed 0.03999")
						end
					end
				
					--Our sound timers.
					if yu.setuplsasfx
					yu.setuplsasfx = $-1
						if not yu.setuplsasfx
						yu.setuplsasfx2 = 26
						S_StopSoundByID(s, sfx_yusfx5)
						S_StartSound(s, sfx_yusfx6)
						end
					elseif yu.setuplsasfx2
						yu.setuplsasfx2 = $-1
						if not yu.setuplsasfx2
						yu.setuplsasfx2 = 25
						yu.setuplsasfx = 0
						S_StartSound(s, sfx_yusfx6)
						end
					end
					yu.lsadash = 0
					yu.lsahoming = 5
					yu.noairdrag = 9
					yu.lightdashing = false
					yu.spin = 50 yu.jump = 50 yu.custom3 = 50
					yu.startdash = 0
					p.pflags = $|PF_JUMPED|PF_THOKKED & ~PF_SPINNING & ~PF_STARTDASH & ~PF_NOJUMPDAMAGE
					
					
					if (yu.lsaattackchain > 2) and not p.sms_intoship
					
						local detect = P_SpawnMobj(s.x+FixedMul(170*FRACUNIT,cos(s.angle)), s.y+FixedMul(170*FRACUNIT,sin(s.angle)), s.z-800*FRACUNIT, MT_YUECHECK)
						if detect and detect.valid
						detect.target = s
						detect.height = 1600*FRACUNIT
						detect.radius = 1200*FRACUNIT
						end
						
						yu.lsaattackchain = 2
						yu.lsaattack = 1
						if (s.state != S_PLAY_ROLL) --Always rollin', always hatin'
						s.state = S_PLAY_ROLL
						end
						
					elseif not yu.lsaattackchain
					
						if not s.target 
						or (s.target and s.target.health)
							ResetLSA(p, s, yu)
							if not yu.autojumproll
							s.momx = $/2 s.momy = $/2 s.momz = $/2
							end
						end
					end
					
					if yu.lsaattack --Check again incase yu.lsaattack was set to 0 before.
 					P_RadiusAttack(s, s, 30*FRACUNIT)
					yu.lsaattack = $+1
					
						if s.target and s.target.valid and s.target.health
						and not (s.target.flags2 & MF2_FRET)
						and not (yu.lsalasttarget and (s.target == yu.lsalasttarget))
						and ((FixedHypot(s.target.x-s.x, s.target.y-s.y)) < 1400*FRACUNIT)
						and (P_CheckSight(s, s.target))
						
						local t = s.target
						yu.lsaattackchain = 2
						yu.lsadeadjump = 0
						yu.hadnotarget = 0
						s.lsaclosest = nil
						s.lsatarget = nil
						s.angle = (R_PointToAngle2(s.x, s.y, t.x, t.y))
						yu.forceyuangletimer = 2
						yu.forceyuangle = s.angle
						
						
							if P_IsObjectOnGround(s) and not (t.subsector == s.subsector)
							or ((t.floorz > s.z) and not (s.eflags & MFE_VERTICALFLIP))
							or ((t.ceilingz < s.z-s.height) and (s.eflags & MFE_VERTICALFLIP))
								
								if ((t.floorz > s.z+200*FRACUNIT) and not (s.eflags & MFE_VERTICALFLIP))
								P_SetObjectMomZ(s, 200*FRACUNIT) --We've got a ways to go. Let's speed this up!						
								else
								P_SetObjectMomZ(s, 75*FRACUNIT) --Hop up a bit and get to a favorable attacking position!
								end
								
							elseif (yu.lsaattack < 6)
								P_SetObjectMomZ(s, (6*FRACUNIT*yu.lsaattack))
								s.momx = ((FixedMul(FixedDiv(t.x-s.x, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2)))/3)/yu.didmanuallsa
								if not (s.flags2 & MF2_TWOD or twodlevel)
								s.momy = ((FixedMul(FixedDiv(t.y-s.y, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2)))/3)/yu.didmanuallsa
								end
							else
								s.momx = FixedMul(FixedDiv(t.x-s.x, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2))/yu.didmanuallsa
								if not (s.flags2 & MF2_TWOD or twodlevel)
								s.momy = FixedMul(FixedDiv(t.y-s.y, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2))/yu.didmanuallsa
								end
								s.momz = FixedMul(FixedDiv(s.target.z-s.z, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2))
							end
							
							yu.didmanuallsa = 1
							
							if (yu.lsaattack < 30) --People want this feature, man. You know they do.
							and not (P_FaceStabCheckMeleeRange(s)) --What kind of LSA can't fly circles around your foes?
								if (yu.direct > 2)
								local dirang = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, p.cmd.forwardmove<<16, -(p.cmd.sidemove<<16)))
								P_Thrust(s, R_PointToAngle2(s.x-s.momx,s.y-s.momy, s.x+P_ReturnThrustX(s,dirang, 60*FRACUNIT), s.y+P_ReturnThrustY(s, dirang, 60*FRACUNIT)), 60*FRACUNIT)
								yu.didmanuallsa = 2
								end
							end

							--Stuck on a wall RIGHT next to your target? Let's blow it up and pretend we didn't get stuck on anything!

							if (p.speed < 5*FRACUNIT) and (yu.lsaattack > 8) and ((s.momz > -5*FRACUNIT) and (s.momz < 5*FRACUNIT))
							and (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 192*FRACUNIT)
							
							P_DamageMobj(t, s, s)
							
							P_SetObjectMomZ(s, 80*FRACUNIT)
							s.momx = FixedMul(FixedDiv(t.x-s.x, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2))
								if not (s.flags2 & MF2_TWOD or twodlevel)
								s.momy = FixedMul(FixedDiv(t.y-s.y, 512*FRACUNIT), FixedDiv(261*FRACUNIT, 3*FRACUNIT/2))
								end
							
							end
							
							--Now for a billion special occasions.
							
							if (t.type == MT_SPRINGSHELL) //These jerks! Use P_Radius so we don't just recoil from their springs
							or (t.type == MT_YELLOWSHELL)
							
								P_RadiusAttack(s, s, 70*FRACUNIT)
							
							elseif (t.type == MT_TURRET) //Kill even the infamous turrets.
								if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 70*FRACUNIT)
								P_KillMobj(t, s, s)
								end

							elseif (t.type == MT_SPINCUSHION)
							
								if t.health
								t.flags = $|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_BOUNCE & ~MF_PAIN				
									if (t.state < S_SPINCUSHION_STOP2)
									t.state = S_SPINCUSHION_STOP2
									end
								end
								
							elseif (t.type == MT_MINUS)
							
								if (t.state != t.info.missilestate)
								t.state = t.info.missilestate
								t.flags = $|MF_SPECIAL|MF_SHOOTABLE
									if (t.z < t.floorz+20*FRACUNIT)
									t.z = $+(20*FRACUNIT*P_MobjFlip(t))
									t.momz = 0
									end
								end
							
							elseif (t.type == MT_EGGROBO1)
							
								if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 89*FRACUNIT)
								P_SpawnMobj(t.x, t.y, t.z, MT_EXPLODE)
								YuLSAimpact(p, s, yu, t)
								yu.lsaattack = 1
								yu.lsaattackchain = 2
								
									if t and t.valid
									t.state = S_NULL
									end
								end
								
							elseif (t.type == MT_METALSONIC_BATTLE) --Yay, the worst boss in the game.
								if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 89*FRACUNIT)
									if (t.state == S_METALSONIC_FLOAT) --DOOODGE!
										P_TryMove(s, t.x, t.y)
										s.z = t.z
										yu.hadnotarget = 12
										yu.lsaattack = 1
										yu.lsaattackchain = 2
										P_InstaThrust(s, R_PointToAngle2(s.x, s.y, t.x, t.y), -60*FRACUNIT)
										yu.nosarun4 = 70										
										s.target = nil
									elseif (t.health > 1)
									yu.hadnotarget = 12
									yu.lsaattack = 1
									yu.lsaattackchain = 2
										if ((t.state == S_METALSONIC_STUN) or (t.state == S_METALSONIC_VECTOR)) and not t.yulsaresist
											for d = 1,5
											P_SpawnMobj(t.x+P_RandomRange(-70,70)*t.scale, t.y+P_RandomRange(-70,70)*t.scale, t.z+P_RandomRange(-20,50)*t.scale, MT_CYBRAKDEMON_VILE_EXPLOSION)
											end		
											
										YuLSAimpact(p, s, yu, t)										
										t.health = $-2
										P_YuQuake(p, 50*FRACUNIT, 12)	
										
										else
										t.health = $-1
											for d = 1,3
											P_SpawnMobj(t.x+P_RandomRange(-70,70)*t.scale, t.y+P_RandomRange(-70,70)*t.scale, t.z+P_RandomRange(-20,50)*t.scale, MT_SONIC3KBOSSEXPLODE)
											end											
											S_StartSound(t, sfx_cybdth)
											S_StartSound(s, sfx_dmpain)
											P_YuQuake(p, 30*FRACUNIT, 3)												
										end
										
										t.yulsaresist = true --Always do this!
										P_InstaThrust(s, R_PointToAngle2(s.x, s.y, t.x, t.y), -70*FRACUNIT)
										yu.nosarun4 = 70
										
									else
									YuLSAimpact(p, s, yu, t)
									P_KillMobj(t, s, s)
									end
								end
								
							elseif (t.type == MT_SUSPICIOUSFACESTABBERSTATUE)
								if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 70*FRACUNIT)							
									if not (t.state == S_SUSPICIOUSFACESTABBERSTATUE_BURST2)
									t.state = S_SUSPICIOUSFACESTABBERSTATUE_BURST2
										if (t.tics > 2)
										t.tics = 2
										end
									elseif (t.tics > 2) and (t.state == S_SUSPICIOUSFACESTABBERSTATUE_BURST2)
										t.tics = 1
									end
								end
							elseif (t.flags & MF_MONITOR) and t.health
							
								if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 70*FRACUNIT)
								P_KillMobj(t, s, s)
								end
								
							elseif (t.type == MT_EGGSHIELD)
								if (FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z) < 89*FRACUNIT)
									if t.target and t.target.valid and t.target.health and (t.target.type == MT_EGGGUARD)
									t.target.flags = $|MF_ENEMY|MF_SHOOTABLE
									P_KillMobj(t.target, s, s)
									end
									YuLSAimpact(p, s, yu, t)
									if t and t.valid
									t.state = S_NULL --Vanish!
									end								
								end				
								
							elseif (t.health == 2) and ((t.flags & MF_ENEMY) or (t.flags & MF_BOSS))
							and not t.yulsaresist
								if (t.flags & MF_BOSS)
								yu.nosarun4 = 90 --Prepare to boing
								end
							t.health = 1 --You only have 1 health as far as the Lightspeed Attack is concerned!
							
							end
							
							if (yu.lsaattack > 29)
							
								s.momx = $*2
								if not (s.flags2 & MF2_TWOD or twodlevel)	
								s.momy = $*2 --We're outta time, speed up and get that MF!
								end
								s.momz = $*2
							end
							
							--We're stuck...shoot! What can we do??
							if s.target and s.target.valid
								if not (s.eflags & MFE_VERTICALFLIP) and ( (s.z+s.height >= s.ceilingz) or ((t.floorz < s.floorz) and (t.subsector == s.subsector) and (t.ceilingz < s.floorz) and (s.z < s.floorz+50*FRACUNIT))) --Hit a ceiling!
								or (s.z <= s.floorz) and (s.eflags & MFE_VERTICALFLIP)
								
								S_StartSound(s, sfx_dmpain)
								S_StartSound(s, sfx_cdfm28)
								P_RadiusAttack(s, s, 200*FRACUNIT)
								s.target = nil
								end
							end
							
						else
							if (yu.lsadeadjump != 2)
							yu.lsadeadjump = 1
							end
						end
					end
				
					yu.hadnotarget = $+1
					
					if (yu.lsaattack > 35)
					or (yu.hadnotarget > 3)
					or (yu.lsadeadjump and (yu.lsadeadjump == 1))
					and ((s.target and not s.target.health) or (s.target and (s.target.flags2 & MF2_FRET)) or (s.target and not s.target.valid) or not s.target)
					or yu.forceswitchtarget
						yu.forceswitchtarget = nil
						s.lsaclosest = nil
						s.lsatarget = nil
						yu.lsaattackchain = 4
						yu.lsadeadjump = 2
						p.pflags = $|PF_JUMPED & ~PF_THOKKED & ~PF_SPINNING & ~PF_STARTJUMP
						P_SetObjectMomZ(s, FRACUNIT)
						if not yu.autojumproll
						s.momx = $/3 s.momy = $/3
						end
						
						if (yu.hadnotarget > 2) or (yu.lsalimit > 1) --Couldn't find a target for too long? Then finish the attack!
							if (s.eflags & MFE_UNDERWATER)
							P_SetObjectMomZ(s, 9*FRACUNIT)
							else
							P_SetObjectMomZ(s, 16*FRACUNIT) --Jump off that last enemy in style!
							end
							if not yu.autojumproll
							s.momx = $/2 s.momy = $/2
							end
							yu.airborne = 0
							yu.sa2jumpdone = false
							yu.homingtrick = 40
							yu.airstart = 10
							yu.homingresist = 15
							yu.lsatrickanim = 39 yu.lsatrickrollang = 0
							ResetLSA(p, s, yu)	
						elseif (yu.lsaattack > 35)
							yu.lsalimit = 0
							yu.airborne = 0
							yu.sa2jumpdone = false
							yu.homingtrick = 40
							yu.airstart = 10
							yu.lsatrickanim = 39 yu.lsatrickrollang = 0
							yu.homingresist = 15
							if not yu.autojumproll
							s.momz = $/4 s.momx = $/4 s.momy = $/4
							end
							ResetLSA(p, s, yu)
						
						else
							YuSpinTrail(p, s, yu)
							
							local detect = P_SpawnMobj(s.x+FixedMul(170*FRACUNIT,cos(s.angle)), s.y+FixedMul(170*FRACUNIT,sin(s.angle)), s.z-800*FRACUNIT, MT_YUECHECK)
							if detect and detect.valid
							detect.target = s
							detect.height = 1600*FRACUNIT
							detect.radius = 1200*FRACUNIT
							end
						
						end
					end
					
				// This party can't go on forever! Here's some cases where it's gotta stop!

					if (p.pflags & (PF_GLIDING|PF_STASIS|PF_SPINNING))
					and not (p.powers[pw_carry])
						ResetLSA(p, s, yu)
					end
					
					if not (p.panim == PA_ROLL) and yu.lsahoming
					P_SetMobjStateNF(s, S_PLAY_ROLL)
					p.pflags = $|PF_JUMPED --You son of a....KEEP ROLLING, do you WANT me to strangle you?!
					end
				end

end)

--Our spindash! Other than it using the PF_SPINNING flag for convenience, pretty much an original ability.

rawset(_G, "YuSpinDash", function(p, s, yu)

 	if yu.bouncestate
	or (p.pflags & PF_JUMPED)
	or (yu.lsacharged)
 	return
 	end
	
			if yu.spin == 1 and (p.cmd.buttons & BT_USE) and not p.exiting
				
				--Not spinning! Initialize spindash!
				
				if not (p.pflags & PF_SPINNING) and not yu.startdash and (P_IsObjectOnGround(s) or yu.framejump)
				and ((s.state <= S_PLAY_DASH) or (s.state == S_PLAY_EDGE)) and not yu.bouncestate
					s.state = S_PLAY_SPINDASH
					yu.startdash = 2
					p.pflags = $|PF_SPINNING|PF_STARTDASH & ~PF_THOKKED & ~PF_JUMPED
					yu.lsacharged = false
					yu.lsacharge = 0
					
					if p.gotflag
						yu.spincharge = 11*FRACUNIT
					elseif p.powers[pw_sneakers] or p.powers[pw_super]
						yu.spincharge = 20*FRACUNIT
						yu.lsacharge = 20
					elseif yu.mysticsuper
						yu.spincharge = 30*FRACUNIT
					else
						yu.spincharge = 15*FRACUNIT
					end
					
					if not p.rmomx and not p.rmomy
					P_Thrust(s, p.drawangle, 500)
					end
					
					yu.spin = 2
					
					if not (yu.direct > 1)
					yu.spinanglecooldown = 2
					end
				--Spawn Yuvault	
					if not (yu.yuvault and yu.yuvault.valid)
						yu.yuvault = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUVAULT)
						yu.yuvault.tics = 6
						yu.yuvault.target = s
					else
						yu.yuvault.tics = 6
					end	
					
				--We're uncurling from a spin!
				
				elseif (p.pflags & PF_SPINNING) and not yu.startdash 
				and not (p.pflags & PF_JUMPED) and (s.state == S_PLAY_ROLL or s.state == S_PLAY_SPINDASH) 

					YuUncurl(p,s,yu)
		
				end
				
			elseif (yu.spin > 1) and yu.startdash and (p.cmd.buttons & BT_USE) --We're holding the button and charging the spin!
				
				if not (yu.yuvault and yu.yuvault.valid)
					yu.yuvault = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUVAULT)
					yu.yuvault.tics = 8
					yu.yuvault.target = s
				else
					yu.yuvault.tics = 8	
				end
				
				if (P_IsObjectOnGround(s) or yu.framejump or yu.startdash)
				p.pflags = $|PF_SPINNING|PF_STARTDASH & ~PF_THOKKED & ~PF_JUMPED
					if s.state != S_PLAY_SPINDASH 
					s.state = S_PLAY_SPINDASH
					end
					yu.startdash = 2
					yu.framejump = 5 --We can always jump while charging a spindash, even in midair.
				end
				
				if (yu.startdash and not P_IsObjectOnGround(s))
					s.momx = $*33/34 --Slow down if charging in midair.
					s.momy = $*33/34 --Don't want startdash-jumping to become too much of an OP meta-move, it's intended as a safety net...
				end 
				
				if (yu.spincharge < 85*FRACUNIT)
					if p.gotflag
					yu.spincharge = $+87770
					else
					yu.spincharge = $+167770 --How fast we charge.
					end
					if (yu.spincharge > 85*FRACUNIT) and not yu.mysticsuper --Our maxdash value, basically.
					yu.spincharge = 85*FRACUNIT
					end
				end
				if yu.mysticsuper --Mystic Super Charging.	
					if (yu.spincharge > 70*FRACUNIT)
						if not (yu.spincharge > 200*FRACUNIT) and not S_SoundPlaying(s, sfx_bejet1)
							S_StartSound(s, sfx_s3ka3)
							S_StartSound(s, sfx_s3k53)
							S_StartSound(s, sfx_bejet1)
						end
						local ghs = P_SpawnMobj(s.x+(P_RandomRange(-200,200)*s.scale), s.y+(P_RandomRange(-200,200)*s.scale), s.z, MT_YUTHOK)
						ghs.blendmode = AST_ADD
						ghs.colorized = true
						ghs.color = P_RandomRange(SKINCOLOR_SUPERRED3, SKINCOLOR_SUPERGOLD5)
						ghs.scale = $*P_RandomRange(1,5)
						ghs.rollangle = (P_RandomRange(-90,90)*ANG1)
						ghs.state = S_WATERZAP
						ghs.tics = $+P_RandomRange(2,15)
						ghs.frame = $|FF_FULLBRIGHT
					end				
					if (yu.spincharge < 450*FRACUNIT) --Mystic Super gets ridiculous spindash power!!
						yu.spincharge = $+167770 --Charge faster!
						P_YuQuake(p, (yu.spincharge/4), 1)
					end
				end
				
				if yu.spinguideline and not (s.flags2 & MF2_TWOD or twodlevel or s.currentaxis or yu.mysticsuper)
					local num = 10-((yu.spincharge/9)/FRACUNIT)
					local maxnum = ((yu.spincharge/2)/FRACUNIT)-2
					-- A little aiming reticule, fancier version of my SMS version.
					for i = num,maxnum,1
					local dist = yu.spincharge/3*i
					local asph = P_SpawnMobj(s.x+FixedMul(dist ,cos(s.angle)), s.y+FixedMul(dist ,sin(s.angle)), s.z+(s.height*10/13), MT_YUTHOK)
						if (s.scale/2-(i*1000) > 0)	//Avoid sigsevs, thx			
							asph.scale = s.scale/2-(i*1000)
						else
							asph.scale = 500
						end
						asph.dispoffset = -10
						asph.flags2 = $|MF2_SHADOW
						asph.color = SKINCOLOR_SUPERSILVER1
						asph.tics = 2
						if (s.eflags & MFE_VERTICALFLIP)
						asph.z = $-36*s.scale
						end
						if (p == displayplayer) and not CV_FindVar("chasecam").value
						or (dist < p.speed+(3*s.scale))
						asph.flags2 = $|MF2_DONTDRAW
						end
					end
				end
				
				if p.gotflag
					yu.lsacharge = 0 --None of this, sorry.
				else
					yu.lsacharge = $+1
					YuLSAglow(p, s, yu, -1, (170*s.scale), false, 14)
					YuLSAglow(p, s, yu, 0, (250*s.scale), false, 19)
					
					if (yu.lsacharge == 44)
					
						local boom = P_SpawnMobjFromMobj(s, 0, 0,0, MT_YUINSTASHIELD)
						boom.scalespeed = $*7
						boom.destscale = s.scale*99
						boom.colorized = true
						boom.blendmode = AST_ADD
						boom.color = SKINCOLOR_CORNFLOWER
						
					elseif (yu.lsacharge > 80) and not yu.mysticsuper --Charged long enough? Lightspeed ready!
						YuUncurl(p, s, yu)
						yu.runfriction = yu.groundfriction
						s.momx = $/2 s.momy = $/2 s.momz = $/2
						yu.framejump = 8
						YuLSAgfx(p,s,yu)
						yu.lsacharge = 0
						yu.lsalimit = 0
						yu.lsaangle = 90
						yu.lsacharged = true
						yu.lsalasttarget = nil
						yu.homingresist = 16 --Frames of "invincibility"
						YuVoice(p, s, yu, sfx_yuvoc4) --Readyyy!!
						if p.powers[pw_super]
							P_YuQuake(p, 5*FRACUNIT, 7)
							for d = 0,6,2
							local boom = P_SpawnMobjFromMobj(s, 0, 0,0, MT_YUINSTASHIELD)
							boom.scale = $+(50000*d)
							boom.scalespeed = $*7+d
							boom.destscale = s.scale*99
							boom.colorized = true
							boom.blendmode = AST_ADD
							boom.color = SKINCOLOR_AETHER+d
							end	
						end
					end
				end
			
			elseif not (p.cmd.buttons & BT_USE) --Release the spin charge! Add speed depending on actual speed!
			and yu.startdash and yu.spincharge
								
				yu.startdash = 0
				yu.edgenope = 0
				yu.homingtrick = 0
				yu.chosentrick = 0
				s.state = S_PLAY_ROLL
				
				local endspeed
				local cmomx2 = p.cmomx*5/3 --Don't forget this.
				local cmomy2 = p.cmomy*5/3
				
					if not yu.mysticsuper
						if (p.powers[pw_sneakers] or p.powers[pw_super])
						and not p.gotflag
							if (p.speed > 101*s.scale)
							yu.spincharge = $-8*FRACUNIT
							elseif (p.speed > 40*s.scale)
							yu.spincharge = $-5*FRACUNIT
							end					
						else
							if (p.speed > 85*s.scale) or p.gotflag --Diminishing boosts if already going ultrafast
							yu.spincharge = $-8*FRACUNIT
							elseif (p.speed > 30*s.scale)
							yu.spincharge = $-5*FRACUNIT
							end
						end
					end

					if not P_IsObjectOnGround(s)					
					yu.spincharge = $*5/11 --Slower underwater or if done from midair
					else
						if (s.eflags & MFE_UNDERWATER)
						yu.spincharge = $*3/4
						end
					end
					
					yu.spindashhover = 42 --Incase you wanna do that thing.
					
					if (yu.spincharge < 4*FRACUNIT) --Always gain 4 minimum.
					yu.spincharge = 4*FRACUNIT
					end
					
					yu.spincharge = ($/FRACUNIT)*s.scale --NOW we convert it to be properly scaled with Sonic's scale.
					
					--Total End Speed
					endspeed = p.speed+yu.spincharge
					if not yu.mysticsuper --Our spindash limits!
						if p.powers[pw_sneakers] or p.powers[pw_super]
							if (endspeed > 125*s.scale)
							endspeed = 125*s.scale
							end
						else
							if (endspeed > 107*s.scale)
							endspeed = 107*s.scale
							end
						end
					yu.superbounceprep = (endspeed/4)/FRACUNIT
					end
					if (gametype == GT_RACE or gametype == GT_COMPETITION) and (leveltime < 140)
						endspeed = 0 --Not going anywhere until the race starts, bub
					elseif p.gotflag and (endspeed > 65*s.scale)
						endspeed = 65*s.scale
					elseif p.speed > endspeed
						endspeed = p.speed --Kay, don't let the spindash slow you DOWN, tho'
					end

				if (s.friction > FRACUNIT)
					yu.frictionlock = 0
					yu.runfriction = FRACUNIT
					s.friction = FRACUNIT
				end
				
				if endspeed+3*s.scale > yu.savedspeed
				yu.savedspeed = endspeed+3*s.scale
				end
				yu.savedspeedtimer = 4
				if not yu.direct	
					P_InstaThrust(s, p.drawangle, endspeed)
					yu.spinanglecooldown = 2
				else
					if (s.flags2 & MF2_TWOD or twodlevel)
					P_InstaThrust(s, s.angle, endspeed)
					else
					P_InstaThrust(s, p.drawangle, endspeed)
					end	
				end
				if yu.mysticsuper
					if (endspeed > 120*FRACUNIT)
					S_StartSound(s, sfx_smach)
					yu.hudboost = 1
					P_YuQuake(p, endspeed/4, (endspeed/FRACUNIT)/30)
					end
					yu.frictionlock = 8
					yu.runfriction = FRACUNIT
					s.friction = FRACUNIT		
				end

				s.momx = $+cmomx2
				s.momy = $+cmomy2
				
				yu.framejump = 5
				S_StopSoundByID(s, sfx_yusfx1)
				S_StopSoundByID(s, sfx_yusfx2)			
				p.pflags = $|PF_SPINNING & ~PF_STARTDASH
				S_StartSound(s, sfx_zoom)				
			end
end)

--The sparkles that appear when Sonic becomes Super Sonic or reverts!

rawset(_G, "YuSuperSparkles", function(p, s, yu, rotate, intensity)
	for d = 1,intensity
	
		local ghs
		
		if rotate
			ghs = P_SpawnMobj(s.x+FixedMul(P_RandomRange(1,300)*s.scale, cos(p.drawangle+ANGLE_90+(P_RandomRange(-20,20)*ANG1))),
			s.y+FixedMul(P_RandomRange(1,300)*s.scale, sin(p.drawangle+ANGLE_90+(P_RandomRange(-20,20)*ANG1))) ,
			s.z+P_RandomRange(-50,50)*s.scale, MT_THOK)
		else
			ghs = P_SpawnMobj(s.x+P_RandomRange(-400,400)*s.scale, s.y+P_RandomRange(-400,400)*s.scale, s.z+P_RandomRange(-150,100)*s.scale, MT_THOK)
		end
			ghs.blendmode = AST_ADD
			ghs.sprite = SPR_YUSO
			ghs.frame = J|FF_FULLBRIGHT|(P_RandomRange(0,9)*FRACUNIT)
			
			if rotate
			ghs.scale = s.scale
			ghs.fuse = 8
			ghs.tics = 50
			P_Thrust(ghs, R_PointToAngle2(ghs.x, ghs.y, s.x, s.y), -25*FRACUNIT)
			else
				if (leveltime % 2 == 0)
					ghs.scale = $/2
				elseif (leveltime % 3 == 0)
					ghs.scale = $/3
				end
			ghs.scalespeed = $/P_RandomRange(1,9)
			ghs.fuse = 17*intensity
			ghs.tics = 17*intensity+30
			end
			
			ghs.destscale = $*999
			ghs.eflags = s.eflags
				if not P_RandomRange(0,4)
				ghs.color = P_RandomRange(SKINCOLOR_SUPERGOLD1, SKINCOLOR_SUPERGOLD5)
				else
				ghs.color = P_RandomRange(SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERGOLD5)
				end
			P_SetObjectMomZ(ghs, P_RandomRange(-1,3)*FRACUNIT)
	end
end)

--The sparkles that appear when Sonic becomes Super Sonic or reverts!

rawset(_G, "YuSuperFlyStart", function(p, s, yu, on)
--Not if disabled! Though it's never disabled by default, 
--This is just for mods that wanna use a certain set of Super Sonic's moveset.
if yu.flyswitchdisabled
return
end
				if not on --Turning off flight!
							yu.superflight = 0
							yu.flighthoming = 0
							yu.nogravity = nil
							s.flags = $ & ~MF_NOGRAVITY
							S_StartSound(s, sfx_s236)
							S_StartSound(s, sfx_s3k7e)
							S_StartSound(s, sfx_s236)
							S_StartSound(s, sfx_s3k7e)							
							local ghs = P_SpawnGhostMobj(s)
							ghs.blendmode = AST_ADD
							ghs.destscale = $*99
							p.pflags = $ & ~PF_CANCARRY
							
							if not P_IsObjectOnGround(s)
							p.pflags = $|PF_JUMPED & ~PF_THOKKED & ~PF_SPINNING & ~PF_STARTDASH & ~PF_STARTJUMP
								s.state = S_PLAY_ROLL
							else --Grounded, then.
								p.pflags = $ & ~PF_JUMPED & ~PF_THOKKED & ~PF_SPINNING
								s.state = S_PLAY_FALL
							end
							
				else --Switching flight mode on!
				
							p.pflags = $|PF_CANCARRY
							P_SetObjectMomZ(s, 8*FRACUNIT)
							p.pflags = $|PF_THOKKED|PF_FORCESTRAFE & ~PF_STARTDASH & ~PF_SPINNING & ~PF_JUMPED & ~PF_STARTJUMP
							yu.startdash = 0
							p.powers[pw_nocontrol] = 15
							yu.forceyuangletimer = 15
							yu.forceyuangle = s.angle
							yu.supertransformangle = s.angle
							yu.lsacharge = 0
							s.flags = $|MF_NOGRAVITY
							s.momx = $/2 s.momy = $/2
							yu.spin = 5
							yu.jump = 5
							yu.airborne = 55
							yu.flighthoming = 0
							yu.superflyrun = 0
							yu.superflyswitch = 19
							S_StartSound(s, sfx_yusfx8)
							yu.custom3 = 20
							yu.hominganimstart = 0
							yu.hominganim = 0 yu.hominganim2 = 0 yu.hominganim3 = 0
							yu.homingtrick = 0
							yu.farthok = 0
							yu.sa2jumpdone = true
							s.state = S_PLAY_SPRING
				end
end)

--Shortcut for all aura functions.
local function DoYuAura(ghs, p, s, yu, mom, infront)
local angle = p.drawangle
		if yu.forceyuangletimer or s.rollangle != 0
		angle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
		end
		if infront
			P_TeleportMove(ghs, s.x+FixedMul(12*s.scale, cos(angle)), s.y+FixedMul(12*s.scale, sin(angle)), s.z)
		else
			if (p.panim == PA_FALL)
			P_TeleportMove(ghs, s.x, s.y, s.z-(5*s.scale*P_MobjFlip(s)))
			elseif (p.panim == PA_RIDE)
			P_TeleportMove(ghs, s.x, s.y, s.z-(25*s.scale*P_MobjFlip(s)))
			else		
			P_TeleportMove(ghs, s.x, s.y, s.z)
			end
		end
		ghs.momx = s.momx
		ghs.momy = s.momy
		ghs.momz = s.momz
		if (s.eflags & MFE_VERTICALFLIP)
			ghs.z = YuFlipZ(s, ghs)
		else
			ghs.eflags = $ & ~MFE_VERTICALFLIP
		end		
		if mom
		ghs.angle = angle
		end
		ghs.fuse = 2
	/*	if (leveltime % 2 == 0)
		ghs.spriteyscale = FRACUNIT+2900
		ghs.spritexscale = FRACUNIT+550		
		elseif (leveltime % 3 == 0)
		ghs.spriteyscale = FRACUNIT+1100
		ghs.spritexscale = FRACUNIT+2900
		elseif (leveltime % 5 == 0)
		ghs.spriteyscale = FRACUNIT+3000
		ghs.spritexscale = FRACUNIT		
		end */
		ghs.spriteyscale = FRACUNIT+P_RandomRange(0,3000)
		ghs.spritexscale = FRACUNIT+P_RandomRange(0,3000)
		ghs.blendmode = AST_ADD
		if (p == displayplayer) and not CV_FindVar("chasecam").value
			ghs.flags2 = $|MF2_DONTDRAW
		else
			ghs.flags2 = $ & ~MF2_DONTDRAW
		end			
end

--The Golden Shield Aura, the Blue Bolt aura, and the Flight Aura!

rawset(_G, "YuSuperAura", function(p, s, yu, flyaura, share)

	if flyaura and not share
	local ghs
		if (p.speed > 44*s.scale) --DIAGIONAL
			if not (yu.yuauraflyd and yu.yuauraflyd.valid) --The center one!
				yu.yuauraflyd = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURAFLYD)
			end			
			ghs = yu.yuauraflyd			
				ghs.scale = s.scale*10/11 
				if flyaura == 1 --Going up!
					ghs.frame = $ & ~FF_VERTICALFLIP
					ghs.spriteyoffset = FRACUNIT-9
				else --Going down!
					ghs.frame = $|FF_VERTICALFLIP
					ghs.spriteyoffset = FRACUNIT*-85
				end
				DoYuAura(ghs, p, s, yu, true, true)
				ghs.angle = p.drawangle
			
		else --Straight up/down!
			if not (yu.yuaurafly and yu.yuaurafly.valid) --The center one!
				yu.yuaurafly = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURAFLY)
			end			
			ghs = yu.yuaurafly			
				ghs.scale = s.scale*10/11
				if flyaura == 1 --Going up!
					ghs.rollangle = 0
					ghs.spriteyoffset = 0
				else --Going DOWN!
					ghs.rollangle = ANGLE_180
					ghs.spriteyoffset = FRACUNIT*-48
				end
				DoYuAura(ghs, p, s, yu)
		end
		if ghs and ghs.valid
			if yu.hypersonic
				ghs.color = (p.yuemeraldcolors2[yu.hypercolor])+4
				ghs.colorized = true
			elseif (p.rings < 10)
				if leveltime % 2 == 0
					ghs.color = SKINCOLOR_RED
				else
					ghs.color = SKINCOLOR_VIOLET
				end
					ghs.colorized = true
			else
					ghs.colorized = false
			end
		end
		
	return
	end
	
	--Not a fly aura, then, so....
		
				if not yu.superaura or share --Super Sonic's Golden Shield!
				  if p.powers[pw_shield] == SH_YUSUPERSHIELD and yu.superorigin and yu.superorigin.player 
					yu.superauraframe = $-1
					if (yu.superauraframe < B)
					yu.superauraframe = H
					end
				local superaura2 = yu.superauraframe+1
					if superaura2 >= I
					superaura2 = B
					end
				local superaura3 = superaura2+1
					if superaura3 >= I
					superaura3 = B
					end					
					
					for d = 0,4
					local ghs
						if (p.panim == PA_RIDE) and s.skin == "adventuresonic"
						ghs = P_SpawnMobjFromMobj(s, 0, 0, -22*s.scale, MT_YUTHOKDISP)
						else
						ghs = P_SpawnMobjFromMobj(s, 0, 0, s.height/12, MT_YUTHOKDISP)
						end
						ghs.yulsatarget = s
						ghs.yulsanum = d
						ghs.superaura = true
						ghs.sprite = SPR_BUBS
						ghs.tics = 2
						ghs.blendmode = AST_ADD
						ghs.colorized = true
						ghs.spriteyoffset = s.spriteyoffset
						ghs.spritexoffset = s.spritexoffset
					//	if (s.eflags & MFE_VERTICALFLIP)
					//	ghs.z = YuFlipZ(s, ghs)
					//	end
							if d == 0
							ghs.frame = (yu.superauraframe+1)|FF_FULLBRIGHT|TR_TRANS50+(d*FRACUNIT)			
							elseif d < 3
							ghs.frame = (superaura2)|FF_FULLBRIGHT|TR_TRANS50+(d*FRACUNIT)
							else
							ghs.frame = (superaura3)|FF_FULLBRIGHT|TR_TRANS50+(d*FRACUNIT)
							end
							ghs.scale  = FixedDiv(FixedMul($, skins[s.skin].shieldscale), FRACUNIT)+(d*(s.scale/10))
							if (yu.superorigin.player.rings < 10)
								ghs.color = SKINCOLOR_RED+d
							elseif yu.superorigin.player.yusonictable.hypersonic
								ghs.color = yu.superorigin.player.yuemeraldcolors2[yu.superorigin.player.yusonictable.hypercolor]+4
							else
								ghs.color = SKINCOLOR_SUPERGOLD5-d
							end
					end			
					
				  else --Super Sonic actual AURA! More of a shield than a Super Saiyan aura, until we get past the Dreamcast days.
				  
				 	if yu.superflyswitch or yu.supertransformangle or yu.flighthoming
					or ((p.rings < 10) and p.speed < 70*s.scale) or (p.powers[pw_super] == 1 and not yu.hypersonic) --SA2 AURA for transforming and running out of rings!

					if not (yu.yuaurasa2 and yu.yuaurasa2.valid) --The center one!
						yu.yuaurasa2 = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURASA2)
					end
					local ghs = yu.yuaurasa2
					local ogframe = yu.yuaurasa2.frame

						for d = 0,2,2

							if d != 0
							ghs = P_SpawnMobj(s.x, s.y, s.z+s.height/12, MT_YUAURASA2)
							ghs.frame = P_RandomRange(0,5)|FF_FULLBRIGHT|TR_TRANS80 & ~TR_TRANS50 & ~TR_TRANS30 & ~TR_TRANS70
							end

						ghs.scale = s.scale+(d*(s.scale/10))
						ghs.spriteyoffset = yu.superoffset
						DoYuAura(ghs, p, s, yu)
							if (p.rings < 10)
								ghs.color = SKINCOLOR_RED+d
								ghs.colorized = true
							elseif yu.hypersonic
								ghs.color = ((p.yuemeraldcolors2[yu.hypercolor])+4)-d
								ghs.colorized = true
							else
								ghs.colorized = false
								ghs.color = SKINCOLOR_SADXSUPERSONIC
							end
						end


					elseif (p.speed > 70*s.scale) or yu.farthok --GOLD AURA FOR RUNNING
				 		if p.powers[pw_carry]
				 			return
				 		end
						if not (yu.yuaurarun and yu.yuaurarun.valid) --The center one!
							yu.yuaurarun = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURARUN)
						end
						local ghs = yu.yuaurarun
						local ogframe = yu.yuaurarun.frame

						for d = 0,4,2
							if d != 0
							ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURARUN) --ANOTHER TWO.
								if d < 3 and not yu.hypersonic
								ghs.frame = P_RandomRange(0,5)|FF_FULLBRIGHT|TR_TRANS80 & ~TR_TRANS50
								else
								ghs.frame = P_RandomRange(0,5)|FF_FULLBRIGHT|TR_TRANS90 & ~TR_TRANS50
								end
							end
							ghs.scale = s.scale*(10+d)/13
							ghs.spriteyoffset = (-3*FRACUNIT)*d
							DoYuAura(ghs, p, s, yu, true, true)
							if yu.lsacharged
								ghs.color = P_RandomRange(SKINCOLOR_SUPERSILVER3, SKINCOLOR_SUPERGOLD2)
								ghs.colorized = true
								ghs.scale = (s.scale*(11+d))/P_RandomRange(10,14)							
							elseif yu.hypersonic
								ghs.color = ((p.yuemeraldcolors2[yu.hypercolor])+4)-d
								ghs.colorized = true
							elseif p.rings < 10
								ghs.color = SKINCOLOR_RED+d
								ghs.colorized = true
							else
								ghs.colorized = false
							end				
						end
					else --MAIN AURA, emulating SA1's aura!


						if not (yu.yuauragold and yu.yuauragold.valid) --The center one!
							yu.yuauragold = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURAGOLD)
						end	
						local ghs = yu.yuauragold
						local ogframe = yu.yuauragold.frame
					
						for d = 0,4
							if d != 0
							ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURAGOLD) --ANOTHER TWO.
								if d < 3
								ghs.frame = ogframe|FF_FULLBRIGHT|TR_TRANS80 & ~TR_TRANS30 & ~TR_TRANS50
								else
								ghs.frame = ogframe|FF_FULLBRIGHT|TR_TRANS90
								end
							end
							ghs.spriteyoffset = yu.superoffset-5*FRACUNIT
							ghs.scale = (s.scale*(11+d))/P_RandomRange(11,14)
							DoYuAura(ghs, p, s, yu)
							if yu.lsacharged
								ghs.color = P_RandomRange(SKINCOLOR_SUPERSILVER3, SKINCOLOR_SUPERGOLD2) //P_RandomRange(SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERGOLD2)
								ghs.colorized = true
								ghs.scale = (s.scale*(11+d))/P_RandomRange(10,14)
							elseif yu.hypersonic
								ghs.color = ((p.yuemeraldcolors2[yu.hypercolor])+4)-d
									if ghs.color <= SKINCOLOR_SUPERSILVER5
									ghs.color = SKINCOLOR_SUPERSKY5-d
									elseif (ghs.color <= SKINCOLOR_SUPERORANGE5 and ghs.color > SKINCOLOR_SUPERORANGE1)
									ghs.color = SKINCOLOR_PURPLE-d
									end
								ghs.colorized = true
							elseif p.rings < 10
								ghs.color = SKINCOLOR_RED+d
								ghs.colorized = true
							else
								ghs.colorized = false
							end				
						end
					end							
				  end
				  
				else
					if p.powers[pw_carry]
				 		return
				 	end
					--Blue Bolt Boost Aura. The true first "boost" aura!

						if not (yu.yuaurabb and yu.yuaurabb.valid) --The center one!
							yu.yuaurabb = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURABLUEBOLT)
						end			
						local ghs = yu.yuaurabb
						local ogframe = yu.yuaurabb.frame
					
						for d = 0,4
							if d != 0
							ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUAURABLUEBOLT) --ANOTHER TWO.
								if d < 3
								ghs.frame = ogframe|FF_FULLBRIGHT|TR_TRANS80 & ~TR_TRANS50
								else
								ghs.frame = ogframe|FF_FULLBRIGHT|TR_TRANS90
								end
							end
							ghs.scale = s.scale*(11+d)/10
							DoYuAura(ghs, p, s, yu, true, true)
							if yu.hypersonic
								ghs.color = SKINCOLOR_ICY+d
								ghs.colorized = true
							elseif p.rings < 10
								ghs.color = SKINCOLOR_AZURE+d
								ghs.colorized = true
							else
								ghs.colorized = false
							end				
						end
				end
end)

--You can use the Far Thok here.

rawset(_G, "YuFarThok", function(p, s, yu, homecancel)
			if yu.spin and (yu.spin < 4)
			
						yu.hominganim = 0 yu.hominganim2 = 0 yu.hominganim3 = 0
						yu.homingtrick = 0
						
						if homecancel --Cancel your homing properties if there's target nearby.
							yu.hominganimstart = 12
							p.homing = 0
							yu.prehomecancel = 0
							s.angle = yu.prehomeangle
							p.drawangle = yu.prehomeangle
							if (yu.lastz > s.z-100*s.scale) and (yu.lastz < s.z+100*s.scale)
								s.z = yu.lastz
							end
							yu.homingsetup = false
							yu.hominganim = 0 yu.hominganim2 = 0 yu.hominganim3 = 0
						end
						
						if not (p.pflags & PF_ANALOGMODE)
						p.drawangle = s.angle
						end
						
						p.pflags = $|PF_THOKKED & ~PF_JUMPED & ~PF_SPINNING & ~PF_STARTDASH
						s.state = S_PLAY_FLOAT_RUN
						yu.farthok = 9
						yu.sa2jumpdone = true
						yu.edgenope = 0
						yu.noairdrag2 = 19
						S_StartSound(s, sfx_rail2)
						P_SpawnGhostMobj(s)
						S_StopSoundByID(s, sfx_yuvoc1)
						yu.frictionlock = 10
						yu.runfriction = FRACUNIT
						s.friction = FRACUNIT
						yu.fallbuffer = 0
						yu.fallbuffer2 = 0
							if (yu.spin < 2) --Correction for our buffer feature.
								yu.spin = 2
							end
							if (yu.jump < 2)
								yu.jump = 2
							end	
							if (s.eflags & MFE_UNDERWATER) --No underwater haxx. It's slowed down.										
								P_InstaThrust(s, s.angle, (26+yu.hominganimstart)*s.scale)
								yu.noairdrag2 = 3
									if (s.eflags & MFE_GOOWATER)
									P_SetObjectMomZ(s, FRACUNIT) --Up we go!
									else
									P_SetObjectMomZ(s, -s.scale)
									end
							else --Later input means a less efficient far-thok!
								P_InstaThrust(s, s.angle, (42+yu.hominganimstart)*s.scale)
								P_SetObjectMomZ(s, 0)
							end
							yu.hominganimstart = 0
							
							if yu.hypersonic or yu.mysticsuper --Ridiculously OP Far Thok for Hyper Sonic.
								s.momx = $*3 --Three times the speed!
								s.momy = $*3
								P_YuQuake(p, 60*FRACUNIT, 9)							
								if not yu.superaura --Instant superaura!
									yu.superaurabuild = 16
								end
								if yu.hypersonic
									P_NukeEnemies(s, s, 1440*s.scale) --BOOM!
									P_YuFlash(p, PAL_WHITE, 3) --FLASH!
									S_StartSound(s, sfx_bkpoof) --KAPOW!
								elseif yu.mysticsuper
									S_StartSound(s, sfx_smach)
									yu.hudboost = 1
								end
								S_StartSound(s, sfx_zoom) --ZOOM!
							end
							if ((s.flags2 & MF2_TWOD) or twodlevel) --2D mode is a pain in the ass.
								s.momy = 0
							end				
			end
end)

--Death animation ragdoll physics.

rawset(_G, "YuDeathAnim", function(s, p, yu)
	if yu.downtheholedeath
	return
	end
	if P_CheckDeathPitCollide(s) --Transition into falling-to-death
	s.flags = $|MF_NOCLIPHEIGHT
		if s.momz*P_MobjFlip(s) > -22*FRACUNIT
		s.momz = -22*FRACUNIT*P_MobjFlip(s)
		end
	return
	end
 			if yu.drowning --Drowning animation is complex because it needed to replace a whole animation for Metalwario.
				if yu.drownanim
					if (yu.superauraframe >= H)
					yu.superauraframe = A
					end
					if (yu.drownanim > 30)
						if P_IsObjectOnGround(s) --Never touch the ground during this.
							s.z = $+(5*s.scale*P_MobjFlip(s))
						end
						if (yu.drownanim > 60)
							yu.superauraframe = $+1	
							s.sprite2 = SPR2_RUN_
							if (s.eflags & MFE_UNDERWATER)
							P_SetObjectMomZ(s, FRACUNIT*2, true)
							end
						else
							if (s.eflags & MFE_UNDERWATER)
							P_SetObjectMomZ(s, FRACUNIT, true)
							end
							if (yu.drownanim > 54)
							yu.superauraframe = $+1
							else
								if (yu.drownanim > 44)
									if yu.drownanim % 2 == 0
									yu.superauraframe = $+1
									end
								elseif yu.drownanim % 4 == 0
								yu.superauraframe = $+1
								end
							end
						s.sprite2 = SPR2_WALK
						end
						
						if (yu.drownanim % 2 == 0) --Bubbles!
						local rng = P_RandomRange(sfx_bubbl1, sfx_splash)
						S_StartSound(s, rng)
					
						local ghs = P_SpawnMobj(s.x+(P_RandomRange(-42,42)*s.scale), s.y+(P_RandomRange(-42,42)*s.scale), s.z+(P_RandomRange(-15,15)*s.scale), MT_SPINDUST)
						ghs.scale = s.scale*2/P_RandomRange(1,5)
						ghs.state = S_SPINDUST_BUBBLE1
						ghs.eflags = s.eflags
						P_SetObjectMomZ(ghs, P_RandomRange(0,5)*s.scale)
						P_InstaThrust(ghs, s.angle+ANGLE_180, P_RandomRange(0,5)*s.scale)
						end
						
						s.frame = yu.superauraframe
						
					else --Gasping animation
					
						if yu.drownanim > 21
							yu.ragdoll = yu.ragdoll and $+((ANG1)*yu.lsaglow) or (ANG1*yu.lsaglow)
							s.sprite2 = SPR2_RIDE
						else
							yu.ragdoll = yu.ragdoll and $+((ANG2)*yu.lsaglow) or (ANG2*yu.lsaglow)
							s.sprite2 = SPR2_GASP
							P_SetObjectMomZ(s, -FRACUNIT/2, true)
						end
						s.frame = A
						s.rollangle = yu.ragdoll
							if (yu.drownanim == 17) --Big exhale! SA1 was scarily detailed with this! ..other than having no mouth, but we'll just assume one for this.
						//	P_YuFlash(p, PAL_NUKE, 3)
							S_StartSound(s, sfx_cdfm38)
							s.rollangle = 0
							yu.ragdoll = 0
								P_YuQuake(p, 80*FRACUNIT, 3)
								
								for d = 1,16
								local rng = P_RandomRange(sfx_bubbl1, sfx_splash)
								S_StartSound(s, rng)
									if d == 1
										local ghs2 = P_SpawnMobj(s.x+FixedMul(12*s.scale,cos(s.angle)), s.y+FixedMul(12*s.scale,sin(s.angle)), s.z+(52*s.scale*P_MobjFlip(s)), MT_EXTRALARGEBUBBLE)
										ghs2.eflags = s.eflags
										ghs2.scale = s.scale
									else
										local ghs2 = P_SpawnMobj(s.x+FixedMul(12*s.scale,cos(s.angle)), s.y+FixedMul(12*s.scale,sin(s.angle)), s.z+(52*s.scale*P_MobjFlip(s)), P_RandomRange(MT_SMALLBUBBLE, MT_MEDIUMBUBBLE))
										ghs2.eflags = s.eflags
										ghs2.scale = s.scale
										P_SetObjectMomZ(ghs2, P_RandomRange(2,15)*s.scale)
										P_InstaThrust(ghs2, s.angle+P_RandomRange(-34,34)*ANG1, P_RandomRange(1,24)*s.scale)
									end
								end
								
							else
								if (yu.drownanim % 3 == 0) --MORE Bubbles!
								local rng = P_RandomRange(sfx_bubbl1, sfx_splash)
								S_StartSound(s, rng)
								end
					
								local ghs = P_SpawnMobj(s.x+FixedMul(12*s.scale,cos(s.angle)), s.y+FixedMul(12*s.scale,sin(s.angle)), s.z+(45*s.scale*P_MobjFlip(s)), P_RandomRange(MT_SMALLBUBBLE, MT_MEDIUMBUBBLE))
								ghs.scale = s.scale*3/P_RandomRange(1,6)
								ghs.eflags = s.eflags
								P_SetObjectMomZ(ghs, P_RandomRange(1,8)*s.scale)
								P_InstaThrust(ghs, s.angle+P_RandomRange(-60,60)*ANG1, P_RandomRange(1,24)*s.scale)
							end	
							if not yu.drownanim
							yu.drownanim2 = 1
							yu.ragdoll = yu.ragdoll and $+((ANG30)*yu.lsaglow) or (ANG30*yu.lsaglow)
							s.rollangle = yu.ragdoll
							end
					end
				else --Idle.
						s.sprite2 = SPR2_DEAD
						s.frame = A
						if P_IsObjectOnGround(s) or (s.z < s.floorz+FRACUNIT*5)
						yu.ragdoll = 0
						s.rollangle = 0
						else
						
							if yu.drownanim2
							yu.drownanim2 = $-1
							yu.ragdoll = yu.ragdoll and $+(ANG2*2*yu.lsaglow) or (ANG10*yu.lsaglow)
								for d = 1,2
									local ghs2 = P_SpawnMobjFromMobj(s, 0, 0, 0, P_RandomRange(MT_SMALLBUBBLE, MT_MEDIUMBUBBLE))
									ghs2.eflags = s.eflags
									ghs2.scale = s.scale
									P_SetObjectMomZ(ghs2, P_RandomRange(-10,6)*s.scale)
									P_InstaThrust(ghs2, P_RandomRange(0,359)*ANG1, P_RandomRange(10,35)*s.scale)
								end
							end
						
							if (((yu.ragdoll/ANG1) >= 176) or ((yu.ragdoll/ANG1) <= -176))
							yu.ragdoll = ANGLE_180
							else//if (s.eflags & MFE_UNDERWATER)
							yu.ragdoll = yu.ragdoll and $+(ANG1*yu.lsaglow) or (ANG1*yu.lsaglow)
							end
						s.rollangle = yu.ragdoll
				//		p.drawangle = yu.ragdoll-(ANGLE_90*yu.lsaglow)
							if (s.eflags & MFE_UNDERWATER)
							s.z = $+(FRACUNIT*P_MobjFlip(s))
						//	P_SetObjectMomZ(s, 3*FRACUNIT)
							end
						end					
							if not (yu.corpse and yu.corpse.valid)
								yu.corpse = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUTHOK)
								local corpse = yu.corpse
								corpse.flags = s.flags
								corpse.skin = "adventuresonic"
								corpse.sprite = SPR_PLAY
								corpse.sprite2 = SPR2_DEAD
								corpse.frame = A
								corpse.eflags = s.eflags
								corpse.angle = p.drawangle 
								corpse.scale = s.scale
								corpse.rollangle = s.rollangle
								corpse.colorized = s.colorized
								corpse.color = s.color
								s.flags2 = $|MF2_DONTDRAW
							else --Keep it around.
								s.flags2 = $|MF2_DONTDRAW
								yu.corpse.flags = s.flags
								yu.corpse.rollangle = s.rollangle
								P_TeleportMove(yu.corpse, s.x, s.y, s.z)
								yu.corpse.color = s.color
								yu.corpse.colorized = s.colorized
								yu.corpse.tics = 3
							end					
				end

				
			--Okay!! So NOT drowning, then. Do other death animation!
				
 			else
 						s.flags2 = $ & ~MF2_DONTDRAW & ~MF2_SHADOW
						
						if P_PlayerTouchingSectorSpecial(p, 1, 3) --Touching Lava.				
							if (yu.burning < 3) 
							yu.burning = 90
							s.flags = $|MF_NOCLIPHEIGHT & ~MF_NOCLIP & ~MF_SHOOTABLE
							P_SetObjectMomZ(s, -FRACUNIT)						
							end
						s.flags = $|MF_NOCLIPHEIGHT & ~MF_NOCLIP & ~MF_SHOOTABLE					
 						elseif P_CheckDeathPitCollide(s)
						s.flags = $|MF_NOCLIPHEIGHT & ~MF_NOCLIP & ~MF_SHOOTABLE
						else
 						s.flags = $ & ~MF_NOCLIPHEIGHT & ~MF_NOCLIP & ~MF_SHOOTABLE
						end
						
						if P_IsObjectOnGround(s)
							s.sprite2 = SPR2_DEAD
							s.frame = A
							s.rollangle = 0
							s.momx = $*21/22
							s.momy = $*21/22
							if (p.deadtimer > 70) and not P_CheckDeathPitCollide(s)
								if not (yu.corpse and yu.corpse.valid)
								yu.corpse = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUTHOK)
								local corpse = yu.corpse
								corpse.flags = $|MF_NOCLIPHEIGHT|MF_NOCLIP
								corpse.skin = "adventuresonic"
								corpse.sprite = SPR_PLAY
								corpse.sprite2 = SPR2_DEAD
								corpse.frame = A
								corpse.eflags = s.eflags
								corpse.angle = p.drawangle 
								corpse.scale = s.scale
								corpse.colorized = s.colorized
								corpse.color = s.color
								else --Keep it around.
								s.flags2 = $|MF2_DONTDRAW
								P_TeleportMove(yu.corpse, s.x, s.y, s.z)
								yu.corpse.color = s.color
								yu.corpse.colorized = s.colorized
								yu.corpse.tics = 3
								end
							end
							
							if s.x+4*FRACUNIT < yu.lastx or s.x-4*FRACUNIT > yu.lastx --Dust sliding
							or s.y+4*FRACUNIT < yu.lasty or s.y-4*FRACUNIT > yu.lasty
							
							S_StartSound(s, sfx_s3kd1s)
							local ghs = P_SpawnMobj(s.x+P_RandomRange(-30,30)*s.scale, s.y+P_RandomRange(-30,30)*s.scale, s.z, MT_SPINDUST)
							ghs.scale = s.scale
							ghs.color = SKINCOLOR_BEIGE
							ghs.colorized = true
							end
							
							
							yu.lastx = s.x
							yu.lasty = s.y
								if yu.ragdoll
									if not yu.burning and not yu.spacedeath and not yu.drowning
								//	S_StartSound(s, sfx_s3k9b) --dramatic crusher stomp
								//	S_StartSound(s, sfx_s3k81) --Echoing sound
									S_StartSound(s, sfx_cdfm42)
									S_StartSound(s, sfx_s3k5d)
										P_YuQuake(p, 50*FRACUNIT, 3)	
										for d = 1,8
											local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_SPINDUST)
											P_InstaThrust(ghs, ANGLE_45*d, 10*s.scale)
											ghs.scale = s.scale
											ghs.destscale = $*99
											ghs.tics = 1
											ghs.color = SKINCOLOR_BEIGE
											ghs.colorized = true
										end
									end
								yu.ragdoll = nil
								end
						else
							if yu.spacedeath
								s.sprite2 = SPR2_DEAD
								s.frame = A
								yu.ragdoll = yu.ragdoll and $+(ANG2+ANG1) or (ANG2+ANG1)
									if yu.spaceanim
										if not (s.rollangle and (s.rollangle > (ANGLE_90)))
										s.rollangle = yu.ragdoll --Cut further code shenanigans out when you're KO'd.
										end
									else
									yu.ragdoll = $+(ANGLE_45/5)
									s.rollangle = yu.ragdoll
									p.drawangle = yu.ragdoll
									s.momz = $*10/11
									end
							else
								s.sprite2 = SPR2_PAIN
								s.frame = A
								yu.ragdoll = yu.ragdoll and $+((ANG10+ANG1)*yu.lsaglow) or (ANG10*yu.lsaglow)
								s.rollangle = yu.ragdoll --Cut further code shenanigans out when you're KO'd.
							end
						end
			end

end)

--Super Sonic Transform animation!

rawset(_G, "YuSuperTransform", function(p, s, yu)
			yu.supertransform = $-1	
				if yu.supertransformangle != nil
				yu.supertransformangle = $-((ANG1*18)+1930465)
				end
				p.pflags = $|PF_THOKKED|PF_FORCESTRAFE & ~PF_STARTDASH & ~PF_SPINNING & ~PF_JUMPED & ~PF_STARTJUMP
				s.state = S_PLAY_SPRING
				s.momx = $/3 s.momy = $/3
				yu.startdash = 0
				yu.spin = 10
				yu.jump = 10		

				if (yu.supertransform < 8)
					s.momz = 0
				elseif yu.supertransform --Animation into Super Sonic!
				
						--You mean the CHAOS EMERALDS?!
						for d = 1,7
							local angadd = (ANG1*51*d)+(yu.supertransform*ANG10)
							local ghs = P_SpawnMobj(s.x+FixedMul(((45+(yu.supertransform*6))*s.scale), cos(angadd)),s.y+FixedMul(((45+(yu.supertransform*6))*s.scale), sin(angadd)),
							s.z+((s.height-(yu.supertransform*s.scale*2)+(d*5*s.scale))*P_MobjFlip(s)), MT_YUTHOK) //-(yu.supertransform*s.scale*2)+(d*10*s.scale)
							
							ghs.flags = $|MF_NOCLIPHEIGHT|MF_NOCLIP
							ghs.tics = 2
							ghs.eflags = s.eflags
							local FlashMobjC={SKINCOLOR_EMERALD, SKINCOLOR_PURPLE, SKINCOLOR_SKY, SKINCOLOR_RED, SKINCOLOR_GREY, SKINCOLOR_BLUE, SKINCOLOR_SUPERGOLD5}
							ghs.color = FlashMobjC[d]
							ghs.z = YuFlipZ(s, ghs)
							
							if yu.hyperpower and p.rings >= 100
								ghs.scale = (s.scale*14)/9 --SUPER emeralds!
								ghs.z = $-((10*s.scale)*P_MobjFlip(s))
								ghs.frame = 28|FF_FULLBRIGHT|TR_TRANS20
								local ghs3 = P_SpawnGhostMobj(ghs)
								ghs3.blendmode = AST_ADD
								ghs3.fuse = 6
								if (leveltime % 3 == 0)
								ghs.color = SKINCOLOR_SUPERSILVER1
								ghs3.color = SKINCOLOR_SUPERSILVER1
								end
							else
								ghs.scale = (s.scale*4)/7
								ghs.frame = 28|FF_FULLBRIGHT|TR_TRANS20
							end
							
							
							local ghs2 = P_SpawnMobjFromMobj(ghs, 0, 0, 0, MT_IVSP)
							ghs2.colorized = true
							ghs2.color = ghs.color
							ghs2.scale = ghs.scale*2
							ghs2.blendmode = AST_ADD
							ghs2.frame = P_RandomRange(0,12)|FF_FULLBRIGHT|TR_TRANS50
							
							if yu.supertransform == 8
								ghs2.tics = 14
								ghs2.destscale = $*99
								ghs2.frame = P_RandomRange(0,12)|FF_FULLBRIGHT|TR_TRANS20
								P_SetObjectMomZ(ghs2, 4*FRACUNIT, true)
							else
							ghs2.tics = 2
							end
							
						end				
				
					if (yu.supertransform > 15)
						if (yu.supertransform % 3 == 0) --SAVE THE FRAMES!!
						local num = 4
							if (yu.supertransform % 5 == 0) --YOU'RE GONNA DESTROY THE WHOLE PC, SONIC!
							num = 2
							end
							for d = 1,90,num
								local angadd = yu.presupertransformangle+(ANG2*2*d)
								local ghs = P_SpawnMobj(s.x+FixedMul(((135-yu.supertransform)*s.scale), cos(angadd)),s.y+FixedMul(((135-yu.supertransform)*s.scale), sin(angadd)), s.z, MT_YUTHOK)
								ghs.flags = $|MF_NOCLIPHEIGHT|MF_NOCLIP
									if (d % 3 == 0)
									ghs.blendmode = AST_ADD
									end
								ghs.tics = 69
								if (d > 40 and d < 50)
								ghs.frame = 27|FF_FULLBRIGHT|TR_TRANS80
								else
								ghs.frame = 27|FF_FULLBRIGHT|TR_TRANS50
								end
								ghs.scale = s.scale
								ghs.eflags = s.eflags
								local FlashMobjC={SKINCOLOR_GOLD, SKINCOLOR_KETCHUP, SKINCOLOR_BROWN, SKINCOLOR_CRIMSON, SKINCOLOR_JET, SKINCOLOR_SUPERGOLD2, SKINCOLOR_ORANGE}			
								ghs.color = FlashMobjC[P_RandomRange(1,7)]
								ghs.z = $-(((150+yu.supertransform)*s.scale)*P_MobjFlip(s))
								P_SetObjectMomZ(ghs, 24*FRACUNIT) 
							end
						end
			
						if (yu.supertransform > 20)
							if yu.supertransform == 30
							S_StartSound(s, sfx_yusfxa)
							end
						local ghs = P_SpawnGhostMobj(s)
						ghs.destscale = $*99
						ghs.blendmode = AST_ADD
						ghs.colorized = true
						ghs.color = SKINCOLOR_SUPERGOLD1
						ghs.destscale = ghs.scalespeed+1
						s.momx = 0 s.momy = 0
				
						local ghs = P_SpawnGhostMobj(s)
						ghs.destscale = $*99
						ghs.blendmode = AST_ADD
						ghs.colorized = true
						ghs.tics = 2
						ghs.scale = s.scale*6/5
						ghs.color = SKINCOLOR_SUPERGOLD5
						ghs.flags2 = $|MF2_SHADOW
						P_TeleportMove(ghs, s.x+s.momx, s.y+s.momy, s.z+s.momz)
						end
						
					end			
					if yu.supertransform == 20 or yu.supertransform == 14
					s.momz = $*10/13
					end			
				end
				if yu.supertransform and (yu.supertransform <= 16) --Alright, sick of it, let's force this!
					s.sprite2 = SPR2_TRNS
					if (yu.supertransform > 13)
						s.frame = I
					elseif (yu.supertransform > 11)
						s.frame = J
					elseif (yu.supertransform > 6)
						s.frame = K
					elseif (yu.supertransform > 4)
						s.frame = M
					elseif (yu.supertransform > 2)
						s.frame = N
					else
						s.frame = O
					end
				end					
								
				if not yu.supertransform
				yu.supertransformangle = nil
				yu.forceyuangletimer = 0
					if P_IsObjectOnGround(s)
					s.z = $+5*(s.scale*P_MobjFlip(s))
					end
				p.pflags = $|PF_JUMPED & ~PF_FORCESTRAFE & ~PF_STARTDASH & ~PF_SPINNING & ~PF_STARTJUMP	& ~PF_THOKKED
				p.charflags = $|SF_SUPER
				yu.superaura = 0
				yu.superaurabuild = 0
				p.speed = 0
				P_RadiusAttack(s, s, 300*FRACUNIT)
				P_DoSuperTransformation(p)
				S_StopSoundByID(s, sfx_supert)
				YuVoice(p, s, yu, sfx_yuvoc7, true)
				S_StartSound(s, sfx_yusfx9)
				yu.supersonic = true
				yu.superflash = 9*FRACUNIT
				yu.superflashd = 1
				yu.superflight = 0
				yu.flighthoming = 0
				s.flags = $ & ~MF_NOGRAVITY
				p.charflags = $|SF_CANBUSTWALLS
				yu.changedcharflags = 10
				s.tics = $+5
				s.anim_duration = $+5
					--Hyper Sonic? We'll need 100 rings.
					if yu.hyperpower and (p.rings >= 100)
						if p.isxmomentum
						S_StartSound(s, sfx_htrns)
						end
						if yu.hypermemories
						yu.hypermemories = 0
						end
						P_YuQuake(p, 50*FRACUNIT, 33)
						P_YuFlash(p, PAL_WHITE, 11)
						P_NukeEnemies(s, s, 1536*FRACUNIT)
						
						yu.hypersonic = true
						if not yu.noflashes
							S_StartSound(s, sfx_bkpoof)
							S_StartSound(s, sfx_brakrx)
							for d = 1,5
							local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_YUTHOK)
							ghs.scale = s.scale/d
							ghs.destscale = $*999
							ghs.scalespeed = $*d
							ghs.tics = 40 ghs.fuse = 40
							ghs.color = SKINCOLOR_SUPERSILVER3+(d*5) --RAINBOOOOOW!!
							end
						end
					end
					if (p == consoleplayer) and yu.yumusic
						if S_MusicName() == "YUSUPR" or S_MusicName() == "_super"
						COM_BufInsertText(p, "tunes YUSUPR")
						S_ChangeMusic("YUSUPR", true, p)
						S_StartMusicCaption("Live and Learn", 210, p)
						S_SetMusicPosition(1040)
						end
					end
				end
				if p.powers[pw_carry] --Somebody's trying to break it, abort.
					yu.supertransform = 0
					s.flags = $ & ~MF_NOGRAVITY
					p.pflags = $ & ~PF_FORCESTRAFE
					yu.supertransformangle = nil
					yu.forceyuangletimer = 0
				end
end)

rawset(_G, "YuFlightHomingAttack", function(p, s, yu)
	if not p.bot and not yu.flighthoming and not p.homing
		s.target = nil --Paranoia
		s.target = P_LookForEnemies(p, true, true)
		if s.target and s.target.valid and not (s.target.type == MT_BIGMINE)
		and not ((FixedHypot(s.target.x-s.x, s.target.y-s.y)) > 4000*FRACUNIT)
		yu.flighthoming = 40
		end
	end
end)

--NiGHTS special!

rawset(_G, "YuNiGHTSSuperSonic", function(p, s, yu)
						if (p.cmd.buttons & BT_USE)
							yu.spin = $+1
						else
							yu.spin = 0
						end
						
					p.charflags = $|SF_SUPER & ~SF_NOSUPERSPIN --Making sure...
					yu.spawnedballalready = false
					yu.alreadytrailed = false
					
						if (s.state == S_PLAY_NIGHTS_TRANS6) and (leveltime % 2 == 0)
							if ((s.frame & ~FF_FULLBRIGHT) >= H)
							s.frame = F
							else
							s.frame = $+1
							end
						end
						if ((s.color >= SKINCOLOR_SUPERGOLD1) and (s.color <= SKINCOLOR_SUPERGOLD5))
							if p.skincolor == SKINCOLOR_ADVANCESONIC
							s.color = SKINCOLOR_ADVANCESUPERSONIC --Request from Metal
							else
							s.color = SKINCOLOR_SADXSUPERSONIC
							end						
						end
						
						if p.powers[pw_flashing] and (s.state == S_PLAY_NIGHTS_STUN) --Pain animation
							yu.rollangle = yu.rollangle and $+ANG30 or ANG30
							s.rollangle = yu.rollangle
							yu.nightscharge = 0
							yu.nightsspin = 0
							yu.spritexscale = FRACUNIT
							yu.spriteyscale = FRACUNIT

						elseif yu.rollangle --End pain animation
							yu.rollangle = 0
							s.rollangle = 0
							
						elseif yu.nightsbrake
						
							yu.nightsbrake = $-1
							p.cmd.forwardmove = 0
							p.cmd.sidemove = 0
							s.rollangle = 0
							s.momx = 0 s.momy = 0 s.momz = 0
							p.powers[pw_nocontrol] = 2
							S_StopSoundByID(s, sfx_nbmper)
							S_StopSoundByID(s, sfx_nxbump)
							S_StopSoundByID(s, sfx_drill1)
							S_StopSoundByID(s, sfx_drill2)
							S_StopSoundByID(s, sfx_yusfx1)
							S_StopSoundByID(s, sfx_yusfx2)						
							
							s.state = S_PLAY_NIGHTS_STAND
							s.sprite2 = SPR2_TRNS|FF_SPR2SUPER
							
							if leveltime % 2 == 0
								s.frame = F
							elseif leveltime % 3 == 0
								s.frame = G
							else
								s.frame = H
							end
							if p.flyangle > 90 and p.flyangle < 270
								p.flyangle = 180
							else
								p.flyangle = 0
							end
							
							
						elseif ((s.state >= S_PLAY_NIGHTS_STAND) and (s.state <= S_PLAY_NIGHTS_DRILL)) or (s.state == S_PLAY_ROLL)
							if p.exiting
							yu.nightsspin = 10
							
								for d = 1,4,3
									local ghs = P_SpawnGhostMobj(s)
									ghs.rollangle = P_RandomRange(-50,50)*ANG1
									ghs.blendmode = AST_ADD
									ghs.flags2 = MF2_SHADOW
									ghs.scale = s.scale/2*d
									ghs.z = $-((7*ghs.scale)*P_MobjFlip(s))
								end
							
								if p.exiting == 62
								S_StartSound(s, sfx_yusfxb)
									for d = 1,90
									local ghs = P_SpawnMobj(s.x+FixedMul((128*s.scale), cos(s.angle+(ANG2*2*d))),s.y+FixedMul((128*s.scale), sin(s.angle+(ANG2*2*d))), s.z, MT_YUTHOK)
									ghs.flags = $|MF_NOCLIPHEIGHT|MF_NOCLIP
										if (d % 2 == 0)
										ghs.blendmode = AST_ADD
										end
									ghs.tics = 69
									ghs.frame = 27|FF_FULLBRIGHT|TR_TRANS70
									ghs.scale = s.scale
									ghs.eflags = s.eflags
									local FlashMobjC={SKINCOLOR_GOLD, SKINCOLOR_RED, SKINCOLOR_CRIMSON, SKINCOLOR_CRIMSON, SKINCOLOR_JET, SKINCOLOR_SUPERGOLD2, SKINCOLOR_KETCHUP}			
									ghs.color = FlashMobjC[P_RandomRange(1,7)]
									ghs.z = $-((150*s.scale)*P_MobjFlip(s))
									P_SetObjectMomZ(ghs, 24*FRACUNIT) 
									end								
								end
							end
						 --Nothing else special happening? Then custom ability, goooo!!
						 
							if (yu.nightscharge > 28) --Don't go TOO overboard with speed/drain! (This is multiplied*4)
								yu.nightscharge = 28
							end
							
							--Allow midair spindash to make NiGHTS stages more fun.
							--This replaces his brake.
							
							if (p.cmd.buttons & BT_USE) and not ((p.cmd.buttons & BT_JUMP) and not yu.nightscharge)
							and (p.drillmeter and (p.drillmeter > 11))
							and not p.exiting

								if not yu.nightscharge
								S_StartSound(s, sfx_yusfx1)
								end
								
								yu.nightsspin = 0
								yu.spriteyscale = 80000
								yu.spritexscale = FRACUNIT/2
								yu.nightscharge = $+1
								yu.superauraframe = $+1
								
								if (yu.superauraframe > H)
								yu.superauraframe = A
								end
								
								YuJumpBallSpawn(p, s, yu)
								s.state = S_PLAY_ROLL
								s.frame = yu.superauraframe|FF_FULLBRIGHT
								
								if yu.nightscharge == 23
									S_StartSound(s, sfx_kc5b)
									local boom = P_SpawnMobjFromMobj(s, 0, 0,0, MT_YUINSTASHIELD)
									boom.scalespeed = $*7
									boom.destscale = s.scale*99
									boom.colorized = true
									boom.blendmode = AST_ADD
									boom.color = SKINCOLOR_SUPERGOLD5							
								end
								for d = 1,4,3
								local ghs = P_SpawnGhostMobj(s)
								ghs.rollangle = P_RandomRange(-50,50)*ANG1
								ghs.blendmode = AST_ADD
								ghs.flags2 = MF2_SHADOW
								ghs.scale = s.scale/2*d
								ghs.z = $-((7*ghs.scale)*P_MobjFlip(s))
								end
								P_RadiusAttack(s, s, 220*s.scale)
							
							elseif yu.nightscharge and not (p.cmd.buttons & BT_USE) --Unleash the spindash!
							and not p.exiting
								local ghs = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz, MT_NIGHTSBUMPER)
								ghs.sprite = SPR_NULL
								ghs.scale = ($*yu.nightscharge)/14
									if (ghs.scale < s.scale) and not (ghs.scale > 99999)
										ghs.scale = s.scale --Min Power!
									elseif (ghs.scale > 99999)
										ghs.scale = 99999 --Max power!
										S_StartSound(s, sfx_s23c)
										S_StartSound(s, sfx_s23c)
										S_StartSound(s, sfx_yusfxb)
										P_NukeEnemies(s, s, 500*FRACUNIT)
									end
									if (p.cmd.sidemove < 0)
									ghs.threshold = $-185 //Seems about right
									end
								p.bumpertime = 5
								p.drilldelay = 5
								ghs.nsonicb = s
								ghs.fuse = 1
								yu.spriteyscale = FRACUNIT
								yu.spritexscale = FRACUNIT
								s.rollangle = 0
								S_StartSound(s, sfx_kc3c)
									if (yu.nightscharge < 11)
									p.drillmeter = $-11 --Minimum drain. Spamdashing is possible, just not very useful here.
									else
									p.drillmeter = $-yu.nightscharge*4
									end
									if (p.drillmeter < 0) --Don't be glitching below 0, boy
									p.drillmeter = 0
									end
								P_SpawnGhostMobj(s)
								yu.nightsspin = 23 --Start animation!
								if not p.powers[pw_nights_helper]				
									p.powers[pw_nights_helper] = (45+(yu.nightscharge*3)) 
								end
								yu.nightscharge = 0 --AND back to 0!					
				
							elseif yu.nightsspin --If this, do the spin animation!
								if yu.nightsspin > 22
								S_StopSoundByID(s, sfx_nbmper)
								S_StopSoundByID(s, sfx_nxbump)
								S_StopSoundByID(s, sfx_ngskid)
								end
								P_RadiusAttack(s, s, 120*s.scale)
								YuSpinTrail(p, s, yu)

								yu.superauraframe = $+1
								if (yu.superauraframe & ~FF_FULLBRIGHT > H)
								yu.superauraframe = A
								end
								YuJumpBallSpawn(p, s, yu)
								s.state = S_PLAY_ROLL
								s.frame = yu.superauraframe|FF_FULLBRIGHT
								
								yu.nightsspin = $-1
								if not p.exiting
									if not yu.nightsspin
									s.state = S_PLAY_NIGHTS_FLY --Back to normal!
									end							
									if p.flyangle > 90 and p.flyangle < 270
										p.flyangle = (p.cmd.forwardmove*-1)+180
									else
										p.flyangle = p.cmd.forwardmove
									end
								end
							end
							if not p.exiting and not yu.nightsspin and not yu.nightsbrake
							and not (s.state == S_PLAY_NIGHTS_STUN)
							and ((s.state >= S_PLAY_NIGHTS_STAND) and (s.state <= S_PLAY_NIGHTS_DRILL)) or (s.state == S_PLAY_ROLL)
								if (p.cmd.buttons & BT_JUMP) and (p.cmd.buttons & BT_SPIN) --STOP! Sonic time!!
								and (yu.spin < 5)
								
									yu.rollangle = 0
									s.rollangle = 0
									yu.nightscharge = 0
									yu.nightsspin = 0
									yu.spritexscale = FRACUNIT
									yu.spriteyscale = FRACUNIT
									yu.superauraframe = A
									
									S_StartSound(s, sfx_kc4d)
									yu.nightsbrake = 23
									p.powers[pw_nocontrol] = 2
									P_RadiusAttack(s, s, 550*FRACUNIT)
									s.sprite2 = SPR2_TRNS|FF_SPR2SUPER
									s.frame = H
									
									if p.powers[pw_nights_helper] < 30		
										p.powers[pw_nights_helper] = 30
									end									
									
									for d = 0,3		
										local boom = P_SpawnMobjFromMobj(s, 0, 0,0, MT_YUINSTASHIELD)
										boom.scalespeed = $*8+(d*10)
										boom.destscale = s.scale*99
										boom.blendmode = AST_ADD
										boom.color = SKINCOLOR_RED+(d*5)
										boom.colorized = true
										
										local ghs = P_SpawnGhostMobj(s)
										ghs.scalespeed = $*1+(d*10)
										ghs.destscale = s.scale*99
										ghs.blendmode = AST_ADD
										ghs.color = SKINCOLOR_RED+(d*5)
										ghs.colorized = true										
									end
									
									P_YuQuake(p, 30*FRACUNIT, 5)
									S_StartSound(s, sfx_kc5b)
									S_StartSound(s, sfx_s3kbcs)
									for d = 0,8,2
										for i = -6,6,2 --I am actually fluent in this now, how about that?
										local ghs = P_SpawnMobjFromMobj(s, 0, 0, (i*2*s.scale)+(s.height/2), MT_THOK)
										ghs.state = S_IVSP 
										ghs.fuse = 14
										ghs.blendmode = AST_ADD
										ghs.frame = $ & ~FF_TRANSMASK
										ghs.frame = $|TR_TRANS50
										P_InstaThrust(ghs, (ANGLE_45*d), -36*s.scale)
										P_SetObjectMomZ(ghs, i*4*s.scale)
										end
									end	
									
									local ghs = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz, MT_NIGHTSBUMPER)
									ghs.sprite = SPR_NULL
									ghs.scale = 1
									p.bumpertime = 5
									p.drilldelay = 5
									ghs.nsonicb = s
									ghs.fuse = 1
									yu.spriteyscale = FRACUNIT
									yu.spritexscale = FRACUNIT
									s.rollangle = 0
									
									if p.drillmeter > 50 --Braking ain't free!
									p.drillmeter = $-50
									end
								end								
							end
						end
						
						s.sprite2 = $|FF_SPR2SUPER
						yu.lastx = s.x
						yu.lasty = s.y
						yu.lastz = s.z
end)

--Play a voiceline. If they're disabled or you're underwater, these won't work!

rawset(_G, "YuVoice", function(p, s, yu, sfx, supersonic)
	if not sfx
	or (yu.supersonic and not supersonic) --Silence is golden....badumtish.
	return
	end
	if (s.eflags & MFE_UNDERWATER) --Can't talk underwater. Unless you have a breathable air bubble, I guess!
	and not ( (p.powers[pw_shield] == (SH_ELEMENTAL) or p.powers[pw_shield] == (SH_ELEMENTAL|SH_FIREFLOWER))
	or (p.powers[pw_shield] == (SH_BUBBLEWRAP) or p.powers[pw_shield] == (SH_BUBBLEWRAP|SH_FIREFLOWER)) )
		S_StartSound(s, sfx_s3k7d)
		for d = 1,(P_RandomRange(1,4))
			local bubble = P_SpawnMobj(s.x-P_RandomRange(-35,35)*s.scale, s.y-P_RandomRange(-35,35)*s.scale, s.z+P_RandomRange(-2,20)*s.scale, MT_SMALLBUBBLE)
			if bubble and bubble.valid
			bubble.scale = s.scale
			end	
		end
	return
	end
	if (consoleplayer and consoleplayer.yusonictable.yuvoice) --Client side voice disabling!
	S_StartSound(s, sfx)
	end
end)


--Big SA-menu thinker. Handles menu navigation and changing of stats.

rawset(_G, "YuMenuThinker", function(p, yu, yuog)

--IMPORTANT: YUOG is yusonictable, YU is yusonicmenu!

	--Mobj manipulation. I don't care if people get hit or die, pick a better spot to menu!
	if p.realmo and p.realmo.valid and p.realmo.health
	local s = p.realmo
		if P_IsObjectOnGround(s)
			p.pflags = $|PF_USEDOWN|PF_JUMPDOWN
			p.yusonictable.spin = 10 p.yusonictable.custom3 = 10 p.yusonictable.custom2 = 10
			s.momx = 0
			s.momy = 0
			if p.panim == PA_IDLE
			s.tics = 105
			end
			p.pflags = $|PF_FORCESTRAFE
			p.yusonictable.changedcharflags = 10
			if yu.lsadashlastangle == nil
				yu.lsadashlastangle = s.angle
			else
				s.angle = yu.lsadashlastangle
				p.drawangle = yu.lsadashlastangle
			end
		end
	end

	--Menu controls system.
	--If a button or direction is at 1, that means you just tapped it. Higher means you're holding it down.
	--If it's at 0, you're not currently pressing it.

	if (p.cmd.buttons & BT_JUMP)
		yu.jump = $+1
	elseif yu.jump
		yu.jump = 0
	end
	if (p.cmd.buttons & BT_USE)
		yu.spin = $+1
		yu.jump = 0 --Cancel takes priority over jump.
	elseif yu.spin
		yu.spin = 0
	end
	
	--Directional input. Only one at a time allowed ever, hard inputs are needed for more comfortable controller usage.
	
	if (p.cmd.forwardmove > 19)
		yu.up = $+1
		yu.down = 0
	else
		yu.up = 0
	end
	if (p.cmd.forwardmove < -19)
		yu.down = $+1
		yu.up = 0
	else
		yu.down = 0
	end
	if (p.cmd.sidemove > 19) and not (yu.down or yu.up)
		yu.right = $+1
		yu.left = 0
	else
		yu.right = 0
	end
	if (p.cmd.sidemove < -19) and not (yu.down or yu.up)
		yu.left = $+1
		yu.right = 0
	else
		yu.left = 0
	end
	if yu.lastsubmenu != yu.submenu
		if yu.lastsubmenu < yu.submenu
		S_StartSound(nil, sfx_yusfxf, p) --Went back.
		else
		S_StartSound(nil, sfx_yusfxd, p) --Went forwards!
		end
	end
	yu.lastsubmenu = yu.submenu

	--Translucency magic.
	
	if (yu.menutrans <= 0)
		yu.menutransd = 1
	elseif (yu.menutrans >= FRACUNIT*4)
		yu.menutransd = -1
	end
	if yu.menutranswait --Do it slooower.
		yu.menutranswait = $-1
	else
		yu.menutrans = $+(FRACUNIT*yu.menutransd)
		yu.menutranswait = 2
	end
	if yu.menutimer > 8
		yu.menutimer = 0
	else
		yu.menutimer = $+1
	end
	
	--Set scroll limits for each menu so navigation doesn't screw up.
	if yu.submenu == 0 --Basic
		yu.minvert = 3
		yu.minhoriz = 0
	elseif yu.submenu == 1 --Spintrail
		if yuog.customtrail == nil
			yu.minvert = 0
		else
			yu.minvert = 3
		end
		if yu.menuselect == 1
			yu.minhoriz = #skincolors - 1
		else
			yu.minhoriz = 0
		end
	elseif yu.submenu == 2 --Game/Jump Style
		yu.minhoriz = 0
		yu.minvert = 2
	elseif yu.submenu == 3 --Accessibility
		yu.minvert = 3
		yu.minhoriz = 0
	end
	
	--MENU NAVIGATION!
	
	if yu.up == 1	
		if yu.minvert != 0
			S_StartSound(nil, sfx_yusfxe, p)
			yu.menuselect = $-1
			yu.menuhorizontal = 0
			
			if yu.submenu == 1 and yu.menuselect == 1
			and yuog.customtrail != nil
				yu.menuhorizontal = yuog.customtrail
			end			
		end
		if (yu.menuselect < 0)
			yu.menuselect = yu.minvert 
		end
		
	elseif yu.down == 1
		if yu.minvert != 0
			S_StartSound(nil, sfx_yusfxe, p)
			yu.menuselect = $+1
			yu.menuhorizontal = 0
			
			if yu.submenu == 1 and yu.menuselect == 1
			and yuog.customtrail != nil
				yu.menuhorizontal = yuog.customtrail
			end
		end
		if (yu.menuselect > yu.minvert)
			yu.menuselect = 0
		end
		
	elseif yu.left
		if yu.submenu == 1 and yu.menuselect == 1
			if yuog.customtrail != nil --Special color select plus
			and (yu.left == 1 or (yu.left > 13 and (yu.menutimer % 3 == 0)) or yu.left > 44 and (yu.menutimer % 2 == 0))
				yu.menuhorizontal = $-1
				S_StartSound(nil, sfx_yusfxe, p)
				if (yu.menuhorizontal <= 0)
					yu.menuhorizontal = yu.minhoriz
				end
				if not (yu.menuhorizontal > #skincolors) --Failsafe!	
				yuog.customtrail = yu.menuhorizontal
				end
			end
		elseif yu.left == 1
			if yu.submenu == 3 and yu.menuselect == 0	--Spin control toggling?
				if not (yuog.spindashcontrol <= 2)
				yuog.spindashcontrol = $-1
				S_StartSound(nil, sfx_yusfxd, p)
				end
			else
				if (yu.minhoriz != 0)
					S_StartSound(nil, sfx_yusfxe, p)
					yu.menuhorizontal = 0
					yu.menuhorizontal = $-1
				end
				if yu.menuhorizontal < 0
					yu.menuhorizontal = yu.minhoriz
				end
			end
		end
		
	elseif yu.right
		if yu.submenu == 1 and yu.menuselect == 1			
			if (yu.right == 1 or (yu.right > 13 and (yu.menutimer % 3 == 0)) or yu.right > 44 and (yu.menutimer % 2 == 0))
			and yuog.customtrail != nil --Special color select minus
				S_StartSound(nil, sfx_yusfxe, p)
				yu.menuhorizontal = $+1			
				if (yu.menuhorizontal > yu.minhoriz) or (yu.menuhorizontal == 0)
					yu.menuhorizontal = 1
				end
				if not (yu.menuhorizontal > #skincolors - 1) --Failsafe!	
				yuog.customtrail = yu.menuhorizontal
				end
			end	
			
		elseif yu.right == 1
			if yu.submenu == 3 and yu.menuselect == 0	--Spin control toggling?
				if not (yuog.spindashcontrol >= 6)
				yuog.spindashcontrol = $+1
				S_StartSound(nil, sfx_yusfxd, p)
				end
			else
				if (yu.minhoriz != 0)
				S_StartSound(nil, sfx_yusfxe, p)
				yu.menuhorizontal = $+1
				end
				if yu.menuhorizontal > yu.minhoriz
					yu.menuhorizontal = 0
				end
			end
		end	
	end
	
	--CONFIRMING AND CHANGING STUFF! THE BIG ONE, BASICALLY!
	
	if yu.jump == 1
		if yu.submenu
			if not (yu.submenu == 1 and yu.menuselect == 1)
			and not (yu.submenu == 3 and yu.menuselect == 0)
			S_StartSound(nil, sfx_yusfxd, p)
			end
		end
		if yu.submenu <= 0
			if yu.menuselect == 0 --SPIN TRAILS
				yu.submenu = 1
			elseif yu.menuselect == 1 --STYLE/SOUND
				yu.submenu = 2
			elseif yu.menuselect == 2 --ACCESSIBILITY
				yu.submenu = 3
			elseif yu.menuselect == 3 --EXIT
				YuOpenMenu(p)
				return
			end
			yu.menuselect = 0
		elseif yu.submenu == 1
			if yu.menuselect == 0
				if yuog.customtrail == nil
					yuog.customtrail = p.mo.color
				else
					yuog.customtrail = nil
					yuog.customtrailshiny = nil
					yuog.customtrailtaper = nil
				end
			elseif yu.menuselect == 2 
				if not yuog.customtrailshiny
				yuog.customtrailshiny = true
				else
				yuog.customtrailshiny = nil
				end
			elseif yu.menuselect == 3 
				if not yuog.customtrailtaper
				yuog.customtrailtaper = true
				else
				yuog.customtrailtaper = nil
				end
			end
		elseif yu.submenu == 2 --GAME/SOUND menu!
			if yu.menuselect == 0
				if yuog.ballspinonly and not yuog.noaura
					yuog.ballspinonly = false
					yuog.noaura = nil
				else
					if not yuog.noaura
					yuog.ballspinonly = false
					yuog.noaura = true	
					else
					yuog.ballspinonly = true
					yuog.noaura = nil	
					end
				end
			elseif yu.menuselect == 1
				if yuog.yuvoice
				yuog.yuvoice = false
				else
				yuog.yuvoice = true
				end				
			elseif yu.menuselect == 2 
				if yuog.yumusic
				yuog.yumusic = false
				else
				yuog.yumusic = true
				end	
			end
		elseif yu.submenu == 3 --GAME/SOUND menu!
			if yu.menuselect == 1 --Btw, 0 is the spin smoothing feature and is toggled with side-movement.
				if yuog.spinguideline
				yuog.spinguideline = false
				else
				yuog.spinguideline = true
				end
			elseif yu.menuselect == 2 
				if yuog.noflashes
				yuog.noflashes = nil
				else
				yuog.noflashes = true
				end				
			elseif yu.menuselect == 3
				if yuog.noquakes
				yuog.noquakes = nil
				else
				yuog.noquakes = true
				end				
			end		
		end
		
	--CANCELING OUT OF MENUS!
	
	elseif yu.spin == 1
		if yu.submenu
			yu.menuselect = (yu.submenu-1)
			if (yu.menuselect < 0 or yu.menuselect > 3)
				yu.menuselect = 0 --Failsafe.
			end
			yu.submenu = 0
			yu.menuhorizontal = 0
		elseif yu.submenu <= 0 --Goodbye, menu!
			YuOpenMenu(p) --Make sure this is last in line or we add a "return"
			return
		end
	end
end)

--Opens OR closes the SA menu.

rawset(_G, "YuOpenMenu", function(p)
	if not p.valid
	return
	end
	if not p.yumenutable
	S_StartSound(nil, sfx_yusfxf, p)
	--Table now exists.
		p.yumenutable = {
		menuselect = 0,
		menuhorizontal = 0,
		submenu = 0,
		up = 0,
		down = 0,
		left = 0,
		right = 0,
		jump = 0,
		spin = 0,
		minvert = 3,
		minhoriz = 0,
		lastsubmenu = 0,
		menutrans = 0,
		menutransd = 1,
		menutranswait = 5,
		menutimer = 1}
		return true
	else --Exiting out?
		S_StartSound(nil, sfx_yusfxd, p)
		p.yumenutable = nil
		p.pflags = $ & ~PF_FORCESTRAFE
		return false	
	end
end)