--╔════════════════════════════╗══════════════════════════════════════════════════════════════════════════════════════════════#
--║   Taunt Stance functions   ║ Specifically X Sonic's taunt stance, not stuff like FreeFlight taunts!
--╚════════════════════════════╝══════════════════════════════════════════════════════════════════════════════════════════════#
local XSon = XSon
local Hey = 0

local function ShutUp(s)
	for i = 0,2
		S_StopSoundByID(s, sfx_xsvopi+i)
	end
end
local function HEY(p,s,xs)
	for i = 0,2
		if S_SoundPlaying(s, sfx_xsvopi+i) return false end
	end 
	Hey = ($!=2) and $+1 or 0
	XSVoice(p, s, xs, sfx_xsvopi+Hey, true) --Hey!			
end

--Checks if you're not already in the taunt, then performs it and returns a number! 
--If it returns 1, then it's a non-animated pose. Returning 2 is animated. 3 is special.
local function XS_SetTaunt(p, s, xs, stance, NUM)
	local RETURN --Table? ...nah, I'mma elseif this one.

	if not NUM or not tonumber(NUM)
		if stance.taunt != 0
			stance.taunt = 0  --Promotional X art thumbs up
			stance.frame = A
			RETURN = 1
		end
	elseif NUM == 1
		if (stance.taunt != 1)
			stance.taunt = 1  --Thumbs up to left!
			stance.frame = B
			RETURN = 1
		end
	elseif NUM == 2
		if (stance.taunt != 2)
			stance.taunt = 2 --Right thumbs up!
			stance.frame = D
			RETURN = 1
		end
	elseif NUM == 3
		if (stance.taunt != 3)
			stance.taunt = 3 --Adventure pose!
			stance.frame = C
			RETURN = 1
		end
	elseif NUM == 4
		if (stance.taunt != 4)
			stance.taunt = 4 --Fist down!
			stance.frame = E
			RETURN = 1
		end
	elseif NUM == 5
		if (stance.taunt != 5)
			stance.sprite2 = SPR2_FLY_ --Be jelly of Shadow's bitches >:(
			stance.taunt = 5
			stance.frame = F
			RETURN = 1
		end	
	elseif NUM == 6
		if (stance.taunt != 6)
			stance.sprite2 = SPR2_TRNS --Angered power up pose. >:(
			stance.taunt = 6
			stance.frame = C
			stance.startframe = nil
			stance.endframe = E
			stance.speed = 4
			RETURN = NUM
		end	
	elseif NUM == 7
		if (stance.taunt != 7)
			stance.sprite2 = SPR2_CNT1 --Spoiled Brat >:(
			stance.taunt = 7
			stance.frame = A
			stance.startframe = A
			stance.endframe = B
			stance.speed = 11
			RETURN = NUM			
		end	
	elseif NUM == 8 --Sit down with puffy cheeks >:T
		if (stance.taunt != 8)
			stance.sprite2 = SPR2_TIRE
			stance.taunt = 8
			stance.frame = E
			stance.startframe = nil
			stance.endframe = G
			stance.speed = 4
			RETURN = NUM
		end			
	elseif NUM == 9 --Kick your legs like a Russian drunkard.
		if stance.taunt != 9 
			stance.sprite2 = SPR2_FKIK
			stance.taunt = 9 --Kick your legs like a Russian drunkard.
			stance.frame = A
			stance.startframe = A
			stance.endframe = E
			stance.speed = 3
			RETURN = NUM
		end
	elseif NUM == 10 --Drop on your face.
		if stance.taunt != 10
			stance.sprite2 = SPR2_SHIT
			stance.tauntswap = 3 
			stance.taunt = 10
			stance.frame = A
			stance.startframe = nil
			stance.endframe = A	
			stance.speed = 0
			stance.cooldown = 25
		
			XSon.Sound(s, sfx_xssfxh, 135)
			S_StartSound(s, sfx_xssfx9)
			XSSpawnJumpDust(s)
			XSon.Quake(s, 36<<16, 4)
			xs.custom3 = 99
			RETURN = 10
		end
	elseif NUM == 11 --Victory pose.
		if stance.taunt != 11
			stance.sprite2 = SPR2_TAL3 
			stance.taunt = 11
			stance.frame = A
			stance.startframe = nil
			stance.endframe = L
			stance.speed = 2
			RETURN = NUM
		end
	elseif NUM == 12 --Sit pose.
		if stance.taunt != 12
			stance.sittime = 64
			stance.sprite2 = SPR2_TIRE
			stance.taunt = 12
			stance.frame = H
			stance.fixangle = (p.cmd.angleturn<<16)+ ((stance.flip==0) and ANGLE_135 or -ANGLE_135)
			stance.flip = 0
			RETURN = 1
		end
	elseif NUM == 13 --Shrug pose
		if stance.taunt != 13
			stance.sprite2 = SPR2_FLY
			stance.taunt = 13
			stance.frame = G
			stance.startframe = nil
			stance.endframe = J
			stance.speed = 4
			RETURN = NUM
		end
	elseif NUM == 14 --Spindash taunt
		if stance.taunt != 14
			stance.spincharge = 0
			stance.sprite2 = SPR2_ROLL
			stance.taunt = 14
			stance.flip = 0
			stance.fixangle = p.cmd.angleturn<<16
			stance.frame = A
			stance.startframe = A
			stance.endframe = D
			stance.speed = 1
			RETURN = NUM	
		end				
	end
	--Basic static return sprites get some default presets.
	if RETURN
		stance.delay = nil
		if ((NUM or 0) >= 12) or NUM == 6
			stance.delay = (NUM==13) and 3 or 2
		end
		if not stance.tauntswap
			stance.tauntswap = true
		end
		if RETURN == 1
			if (stance.taunt <= 5)
				stance.sprite2 = SPR2_FLY_
				if stance.taunt != 5
					stance.page = 0	
				end
			end
			stance.startframe = nil
			stance.endframe = stance.frame
			stance.speed = 0
		end
		if stance.frame != nil
			if stance.sprite2 != nil
				s.sprite2 = stance.sprite2
			end
			s.frame = ($ & ~FF_FRAMEMASK)|stance.frame
		end
	end
	return RETURN --
end

--DoSpindash"
local function XSSpinDash(p,s,xs, CHARGE)
	if p.xstauntstance
		if p.xstauntstance.spinSFX and p.xstauntstance.spinSFX.valid
			P_RemoveMobj(p.xstauntstance.spinSFX)
		end
		p.xstauntstance = nil
	end
	XSSpawnJumpDust(s) XS_QuickDust(s)
	XSon.SwapStretch(p, s, xs)
	s.spritexscale,s.spriteyscale = 1<<15, 3<<15
	s.XSstretch = {timer = 8}
	
	if (CHARGE < 7) and (CHARGE > 2)
		CHARGE = $+1
	end
	S_StartSoundAtVolume(s, sfx_zoom, min(255, 135+(28*CHARGE)) )
	p.powers[pw_nocontrol] = 0
	p.pflags = $|PF_SPINNING|PF_JUMPDOWN & ~(PF_STARTDASH|PF_JUMPED|PF_THOKKED|PF_STARTJUMP)
	s.state = S_PLAY_ROLL
	p.cmd.buttons = $ & ~BT_JUMP
	
	local SPEED = ((CHARGE*4)+27) / (P_IsObjectOnGround(s) and 1 or 2) / ((s.eflags& MFE_UNDERWATER) and 3 or 1)
	P_Thrust(s, s.angle, SPEED*s.scale)
	xs.spin,xs.jump = 999<<16,999<<16
	p.dashspeed,xs.squat = 0,0
	
	--Now some basic effects.
	XSSpawnJumpDust(s) XS_QuickDust(s)
	for i = -2,3,1
		local ghs = P_SpawnMobjFromMobj(s,(-s.momx/2)*i,(-s.momy/2)*i,0,MT_THOK)
		ghs.blendmode,ghs.color = AST_ADD,s.color
		ghs.scale = (s.scale*10) / (7+max(1, i+2))
		ghs.tics,ghs.fuse,ghs.destscale = 9,9,9
	end
end

--Taunt stance lets you swap taunts with directional keys. Needs to be called from a prethinkframe.
XSon.TauntStance = function(p, s, xs)
	--First, cancel conditions.
	if p.powers[pw_carry]
	or (( 
	(p.speed > 11*s.scale) and not (p.xstauntstance and p.xstauntstance.taunt == 9)
	or (p.pflags & (PF_JUMPED|PF_STARTJUMP|PF_SLIDING|PF_THOKKED))
	or (s.eflags & MFE_SPRUNG)
	or s.skin != "xsonic"
	or not leveltime
	or p.XSonicMenu
	or p.panim != PA_IDLE and p.panim != PA_ETC and (s.state != S_PLAY_EDGE)
	) and not p.exiting)
	or s.sprite != SPR_PLAY	

		XSon.SwapStretch(p, s, xs)
		s.spritexoffset,s.spriteyoffset = 0,0
		p.pflags = $ & ~(PF_STARTDASH|PF_SPINNING)
		
		--Get WRECKED when hit during a taunt.
		if P_PlayerInPain(p)
		and not ((s.sprite2 & ~FF_SPR2SUPER) == SPR2_CLNG) and (XS_Super(p) == 0)
		and not (p.xstauntstance
		and (p.xstauntstance.failed and p.xstauntstance.taunt == 10
		or p.xstauntstance.taunt==14)
		)
			local ANGLE = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
			if (p.speed < 26*s.scale)
				P_InstaThrust(s, ANGLE, 26*s.scale)
				P_SetObjectMomZ(s, 3<<16, true)
			end
			XS_Vortex(s)
			XSSpawnJumpDust(s)
			XS_QuickDust(s)
			XS_CraterSpew(s, ANGLE, 10)
			XSon.Quake(s, 62<<16, 11)
			
			P_FlashPal(p, PAL_NUKE, 4)
			S_StartSound(s, sfx_xssfx9)
			S_StartSound(s, sfx_xssfxm)
			xs.painrecovery = 0
			
			xs.zipstretch2 = 5
			s.spritexscale,s.spriteyscale = FRACUNIT-18000,FRACUNIT+21000
			s.spriteyoffset = -9<<16
		elseif leveltime
			S_StartSound(s, sfx_s1b8)
			S_StartSound(s, sfx_s1c0)
		end	
		p.xstauntstance = nil return false --
	elseif (p.cmd.buttons & (BT_CUSTOM1|BT_JUMP)) --Manual taunt cancel buttons.
	and not (p.xstauntstance and p.xstauntstance.taunt == 14)
	and not (p.cmd.buttons & BT_SPIN) and not (p.pflags & PF_STARTDASH)
	and not p.exiting
		p.xstauntstance = nil
		p.pflags = $ & ~(PF_JUMPDOWN|PF_USEDOWN|PF_STARTDASH|PF_SPINNING)
		if not (p.panim == PA_ROLL or p.panim == PA_JUMP or p.panim == PA_SPRING)
			if P_IsObjectOnGround(s)
				s.state = (p.speed) and S_PLAY_RUN or S_PLAY_STND
				S_StopSoundByID(s, sfx_xssfxh)
				XSon.SwapStretch(p, s, xs)
				xs.zipstretch = 5
				s.spritexscale,s.spriteyscale = FRACUNIT-9999,FRACUNIT+17999
				S_StartSound(s, sfx_s1b8)
				S_StartSound(s, sfx_s1c0)
			else
				s.state = (s.momz*P_MobjFlip(s) > 0) and S_PLAY_SPRING or S_PLAY_FALL
			end
			xs.spin = 0
		end
		return false --
	end	
	if s.milnejoin s.milnejoin = nil end --Don't join twice.
	
	--Good to continue taunt stancing!
	local stance = p.xstauntstance	
	local yu = p.xstauntstance
	local TURNANG = (p.cmd.angleturn<<16)-stance.angle
	local SPECIALNEEDS = false
	
	stance.fire = (p.cmd.buttons & BT_ATTACK) and (stance.normalfire or 0)+1 or 0
	stance.normalfire = (p.cmd.buttons & BT_FIRENORMAL) and (stance.normalfire or 0)+1 or 0
	if (p.cmd.buttons & BT_SPIN)
		p.pflags = $|PF_JUMPDOWN|PF_USEDOWN
	end
	if stance.taunt==4 or stance.taunt==8 or stance.taunt==10 or stance.taunt==12 or stance.taunt==14	
		stance.low = true
	else
		stance.low = false
	end
	--You have special needs.
	if (xs.weaponnext and xs.weaponprev and (p.cmd.buttons & BT_TOSSFLAG))
	or stance.lolwhy
		SPECIALNEEDS = true
		if not stance.lolwhy
			stance.tauntswap = true
			stance.delay = nil
			S_StopSoundByID(s, sfx_xsvoco)
			S_StopSoundByID(s, sfx_xsvocp)
			XSon.Sound(s, sfx_xssfxb)			
		end	
		if not S_SoundPlaying(s, sfx_xssfxb)
			XSon.Sound(s, sfx_xssfxb)	
		end
		stance.taunt = 0
		stance.flash = 0
		stance.sprite2 = nil
		stance.frame = (stance.frame < E) and $+1 or A
		stance.startframe,stance.endframe,stance.speed = nil,A,0
		stance.down,stance.up,stance.left,stance.right = 0,0,0,0
		
		local NEWFRAME = (stance.frame!=nil) and stance.frame or A 
		local FLIP = (stance.flip) and FF_HORIZONTALFLIP or 0
		s.sprite2 = SPR2_FLY_
		s.frame = ($ & ~(FF_FRAMEMASK|FF_HORIZONTALFLIP))|NEWFRAME|FLIP
		s.tics,s.anim_duration = 5,5
		p.panim = PA_IDLE
		s.angle,p.drawangle = stance.angle,stance.angle	
		
		if xs.weaponnext and xs.weaponprev and (p.cmd.buttons & BT_TOSSFLAG) --We're holding the Wii.
			stance.lolwhy = (stance.lolwhy < 2) and 7 or $-1
			stance.cooldown = 8
			if xs.custom2==1
				stance.tauntswap = true
				S_StartSound(s, sfx_xssfx7)
				stance.flip = (not stance.flip) and FF_HORIZONTALFLIP or 0
			end
			
		elseif stance.lolwhy --Roll the dice! Rock Paper Scissors! ...whatever the fuck this is!
			
			S_StopSoundByID(s, sfx_xssfxb)
			XSon.Sound(s, sfx_xssfxh)
			stance.lolwhy = 0
			
			--Minor dust
			local ghs = XS_RingBurstDust(p, s, xs, "manual", s.z)
			if ghs and ghs.valid
				ghs.frame = $+3<<16
				ghs.spritexscale,ghs.spriteyscale = $/3,$/3
			end
			
			--A little snap glow!
			ghs = P_SpawnMobjFromMobj(s,0,0, s.height*2, MT_THOK)
			ghs.scale = $/4
			ghs.scalespeed = $*7
			ghs.fuse = 5 ghs.blendmode = AST_ADD
			ghs.renderflags = $|RF_NOCOLORMAPS|RF_FULLBRIGHT
			ghs.destscale = $*99
			ghs.sprite = SPR_XSG1
			ghs.frame = G|FF_TRANS10
			P_SetObjectMomZ(ghs, ghs.scalespeed*25)
			
			--Spawn a number over your head when you're done being "special"!
			local ctable = {SKINCOLOR_RED, SKINCOLOR_ORANGE, SKINCOLOR_YELLOW, SKINCOLOR_EMERALD, SKINCOLOR_SONIKKU}
			local rng = P_RandomRange(1,5) --Diceroll number!
			if xs.picknum and xs.picknum.valid xs.picknum.state = S_NULL end
			xs.picknum = P_SpawnMobjFromMobj(s, 0,0, s.height*2, MT_THOK)
			local ghs = xs.picknum
			ghs.sprite = SPR_DRWN
			ghs.blendmode = AST_ADD
			ghs.tics,ghs.fuse = 45,44
			ghs.renderflags = $|RF_NOCOLORMAPS|RF_FULLBRIGHT
			ghs.scalespeed = $/3
			ghs.destscale = $*99
			P_SetObjectMomZ(ghs, ghs.scalespeed*25)
			ghs.color = ctable[rng]
			ghs.colorized = true
			ghs.frame = (G+rng)|FF_TRANS10
		end
		if xs.custom2
			xs.custom2 = 99
		end
		p.cmd.forwardmove,p.cmd.sidemove,p.cmd.buttons = 0,0,0
	else
		if (p.cmd.buttons & (BT_ATTACK|BT_FIRENORMAL|BT_TOSSFLAG|BT_CUSTOM3)) 
			stance.down,stance.up,stance.left,stance.right = 0,0,0,0
		else --Up, down, left and right inputs!
			local SIDE = p.cmd.sidemove or 0
			local FORWARD = p.cmd.forwardmove or 0
			stance.right, stance.left = (SIDE>39) and $+1 or 0, (SIDE<-39) and $+1 or 0
			stance.up, stance.down = (FORWARD>39) and $+1 or 0, (FORWARD<-39) and $+1 or 0
		end
		--Select a taunt!
		if ((p.cmd.buttons & BT_SPIN) or xs.darkphase) and not stance.lolwhy
			if xs.spin == 1 and not xs.darkphase and not stance.cooldown
				xs.spin = 850
				stance.flash = 5
			end
			stance.page = 1
		else
			stance.page = 0
		end		
	end
	
	local LASTTAUNT = stance.taunt
	if stance.cooldown --Do, uhh....nothing.
		stance.cooldown = $-1
	else
		if (stance.left==1 or stance.right==1 or stance.down==1 or stance.up==1) --Directional presses.
		and not (stance.taunt == 14)
		
			local MOODY = (stance.page==1) and 4 or 0 --Angry poses?
			
			if stance.left==1 
				XS_SetTaunt(p, s, xs, stance, 1+MOODY) --1: Thumbs up to left! --5: Be jelly of Shadow's bitches >:(
			elseif stance.right==1
				XS_SetTaunt(p, s, xs, stance, 2+MOODY) --2: Right thumbs up! --6: Angered power up pose. >:(
			elseif stance.down==1
				XS_SetTaunt(p, s, xs, stance, 3+MOODY) --3: Adventure pose! --7: Spoiled Brat >:(
			elseif stance.up==1 
				XS_SetTaunt(p, s, xs, stance, 4+MOODY) --4: Fist down! --8: Sit down with puffy cheeks >:T
			end
			
		else --Button activated taunts.	
			if (stance.taunt!=14) and (p.cmd.buttons & BT_SPIN) and (p.cmd.buttons & BT_JUMP) and (xs.jump <= 1) and not xs.ExitState
				XS_SetTaunt(p, s, xs, stance, 14) --14: Spindash
			elseif (p.cmd.buttons & BT_TOSSFLAG) and xs.tossflag==1 and not (p.cmd.buttons & (BT_FIRENORMAL|BT_ATTACK|BT_CUSTOM3)) and not xs.weaponnext
				XS_SetTaunt(p, s, xs, stance, 12) --12: Sit pose.
			elseif (p.cmd.buttons & BT_ATTACK) and stance.fire == 1
				XS_SetTaunt(p, s, xs, stance, 9) --9: Kick your legs like a Russian drunkard.
			elseif (p.cmd.buttons & BT_FIRENORMAL) and stance.normalfire == 1
				XS_SetTaunt(p, s, xs, stance, 11) --11: Victory pose.
			else--if not (p.cmd.buttons & BT_TOSSFLAG)
				if xs.custom3==1 and not (xs.weaponprev or xs.weaponnext) 
					XS_SetTaunt(p, s, xs, stance, 10)			
				elseif xs.weaponnext==1 and not xs.weaponprev
					XS_SetTaunt(p, s, xs, stance, 13) --13: Shrug pose
				elseif xs.weaponprev==1 and not xs.weaponnext
					XS_SetTaunt(p, s, xs, stance, 0) --0: Promotional X art thumbs up
				end
			end
		end	
		--Page 0 has very simple static frames, so use global failsafe settings for it.
/*		if stance.page == 0 
		and not (p.cmd.buttons & BT_SPIN) and not stance.lolwhy and (stance.taunt < 5) 
			stance.sprite2 = SPR2_FLY_ 
			stance.startframe = nil
			stance.speed = 0
			stance.endframe = stance.frame			
		end */		
	end
	
	--Do a stretch anim and play voiceline.
	if stance.tauntswap
		S_StopSoundByID(s, sfx_xssfxh)
		XSon.SwapStretch(p, s, xs)
		xs.zipstretch = (stance.tauntswap == 2) and 4 or 5
		s.spritexscale,s.spriteyscale = FRACUNIT-9999,FRACUNIT+17999
		stance.flash = 0
		if stance.spinSFX and stance.taunt != 14
			if stance.spinSFX.valid
				P_RemoveMobj(stance.spinSFX)
			end
			stance.spinSFX = nil
		end
		if not (stance.lolwhy or SPECIALNEEDS)
			if stance.frame != nil
				s.frame = ($ & ~FF_FRAMEMASK)|stance.frame
			end		
			if stance.tauntswap == 3
				S_StopSoundByID(s, sfx_xssfxh)
				ShutUp(s)
			elseif stance.tauntswap == 2 --Swapping sides, not taunts.
				XSon.Sound(s, sfx_xssfx7, 155)
			else
				if LASTTAUNT == 10 --We JUST stood up.
					ShutUp(s)
					S_StartSound(s, sfx_xssfxi)
				else
					local TAUNT = stance.taunt
					if LASTTAUNT == 9 and p.speed
						s.momx,s.momy = $/9,$/9
					end
					if TAUNT == 13 --uhh, hehehe...
						if not stance.vocCD
							ShutUp(s)
							XSVoice(p, s, xs, sfx_xsvoco)
							stance.vocCD = 65
						end
					else
						XSon.Sound(s, sfx_xssfxh, 135)
						S_StopSoundByID(s, sfx_xsvoco)
						if TAUNT == 12
							if not stance.vocCD
								ShutUp(s)
								XSVoice(p, s, xs, sfx_xsvocp)
								stance.vocCD = 80
							end
						elseif stance.timer == 0 and (TAUNT <= 5 or TAUNT == 9)
							HEY(p,s,xs)
						end
					end
				end
			end
		--	if netgame and (stance.tauntswap != 2)
		--		stance.cooldown = max($, 10) 
		--	end
		end
		stance.tauntswap = false
		
	--flash white to signify spin actually does something.
	elseif stance.flash
		stance.flash = $-1
		if (stance.flash%2)
			local ghs = P_SpawnGhostMobj(s)
			ghs.scale = s.scale
			ghs.fuse,ghs.tics = 2,2
			ghs.colorized = true ghs.color = SKINCOLOR_SUPERSILVER1
			ghs.renderflags = $|RF_SEMIBRIGHT|RF_NOCOLORMAPS
			ghs.dispoffset = 3
			ghs.momx,ghs.momy,ghs.momz = s.momx,s.momy,s.momz
			if (p != displayplayer)
				ghs.flags2 = $|MF2_DONTDRAW
			end
		end
	end
	if stance.vocCD
		stance.vocCD = $-1
	end
	if stance.taunt != 14
		p.pflags = $ & ~(PF_SPINNING|PF_STARTDASH)
	end
	
	if SPECIALNEEDS return end --
	
	--Animate current taunt.
	if stance.delay
		stance.delay = max($-1,0)
	elseif stance.speed and (leveltime%stance.speed == 0)
		if (stance.frame & FF_FRAMEMASK) >= stance.endframe
			if stance.startframe != nil
				stance.frame = stance.startframe --Loop!
			end
		else
			stance.frame = $+1 --Advance frame.
		end
	end
	s.sprite2 = (stance.sprite2 != nil) and stance.sprite2 or SPR2_FLY
	if s.state != S_PLAY_EDGE
		p.panim = PA_IDLE
	end
	if xs.custom2==2 and not xs.custom3 and not xs.weaponnext and not xs.weaponprev 
		if stance.taunt != 12
			stance.tauntswap = 2 --Flip sides?
			stance.flip = (not stance.flip) and FF_HORIZONTALFLIP or 0
		end
	end
	if TURNANG
		if not (abs(p.cmd.sidemove) > 25)
			stance.angle = (p.cmd.angleturn<<16)
		end
	end
	local NEWFRAME = (stance.frame!=nil) and stance.frame or A
	local FLIP = (stance.flip) or 0
	
	if stance.taunt == 14 --Spindash taunt is special.
		local CHARGE = stance.spincharge or 0
		if not (p.cmd.buttons & BT_SPIN)
			XSSpinDash(p,s,xs, CHARGE) return false --
		else
			p.pflags = $|PF_STARTDASH|PF_SPINNING
			if (p.cmd.buttons & BT_JUMP) and xs.jump <= 1 --Can rev up!
				local SPINSFX = min(sfx_s3kabf, sfx_s3kab+CHARGE)
				stance.spincharge = min(7, CHARGE+1)
				
				s.spritexoffset,s.spriteyoffset = 0,FRACUNIT
				s.spritexscale = FRACUNIT-5000-(800*CHARGE)
				s.spriteyscale = FRACUNIT+12500+(1500*CHARGE)
				s.XSstretch = {timer = 3, Xspeed = 3100, Yspeed = 7000}	
				
				P_SpawnSkidDust(p, (21+CHARGE*3)*s.scale)
				if stance.spinSFX and stance.spinSFX.valid
					P_RemoveMobj(stance.spinSFX)
				end
				local SFX = P_SpawnMobjFromMobj(s,0,0,0,MT_THOK)
				SFX.flags2 = MF2_DONTDRAW SFX.tics,SFX.fuse = 66,66
				S_StartSound(SFX, SPINSFX)
				stance.spinSFX = SFX
				xs.jump = 99<<16
			else
				P_SpawnSkidDust(p, 9*s.scale)
			end
			p.speed = 0
			FLIP = 0
			if (p.cmd.buttons & (BT_JUMP|BT_SPIN)) and (abs(p.cmd.sidemove)>3)
				local ANG = (ANG1/8)*p.cmd.sidemove
				stance.angle = $-ANG
			else
				stance.angle = s.angle
			end
			p.dashspeed = ((CHARGE*5)+16)<<16
		end
	elseif stance.taunt == 12 --Sitting anim is special.
		stance.sittime = (not (stance.sittime)) and 97 or $-1
		FLIP = 0
		if (stance.sittime <= 50) --A little breathing animation.
			local SHIELD = (p.powers[pw_shield] & SH_NOSTACK)
			if not ( ((s.eflags & MFE_UNDERWATER) or p.powers[pw_spacetime]) and not (SHIELD & SH_PROTECTWATER)) --No breathing underwater/in space!
				NEWFRAME = (stance.sittime < 6) and K or (stance.sittime > 44) and I or J
			end
		end
		
		if stance.fixangle != nil --This is the only 3D taunt.
			if xs.custom2==1
				if P_IsObjectOnGround(s)
					XSon.SwapStretch(p, s, xs)
					s.spritexscale = FRACUNIT-8400
					s.spriteyscale = FRACUNIT+22500
					s.spriteyoffset = 5<<16
					s.XSstretch = {timer = 3}
					
					local ghs = P_SpawnMobjFromMobj(s,FixedMul(11*s.scale, cos(stance.fixangle)),FixedMul(11*s.scale, sin(stance.fixangle)),-4<<16, MT_SPINDUST)
					ghs.state = S_SPINDUST2 ghs.tics = $/2 ghs.anim_duration = $/2
					ghs.destscale = 99<<16 ghs.fuse = 25 ghs.flags2 = $|MF2_SHADOW
				end
				XSon.Sound(s, sfx_ngjump, 95)
				stance.fixangle = (p.cmd.sidemove>0) and $-ANGLE_45 or $+ANGLE_45
			elseif (p.cmd.buttons & BT_TOSSFLAG) and ((xs.direct or 0)>25) and (p.pflags & PF_ANALOGMODE) and (xs.turnang!=nil)
				stance.fixangle = xs.turnang
			end
			xs.forceangle = {angle = stance.fixangle, timer = 3, nosangle = true}
			p.drawangle = stance.fixangle
		end
	elseif stance.taunt == 9 --Russian kickdance is also special
		if ((xs.direct or 0) > 4) and (NEWFRAME < D)  --Can move around a bit with this one.
			P_InstaThrust(s, xs.turnang, min(50, xs.direct*2)*(s.scale/5))
			stance.kickmoved = 8
		elseif stance.kickmoved
			stance.kickmoved = $-1
			if p.speed
				s.momx,s.momy = FixedDiv(FixedMul($, 7),8),FixedDiv(FixedMul($, 7),8)
				if NEWFRAME == E and (p.speed > 4*s.scale) 
					local ghs = P_SpawnMobjFromMobj(s,0, 0,-4<<16, MT_SPINDUST)
					ghs.state = S_SPINDUST2 ghs.tics,ghs.anim_duration = $/2,$/2
					ghs.destscale = 99<<16 ghs.fuse = 25 ghs.flags2 = $|MF2_SHADOW
				end
			end
		end		
	end

	stance.timer = $+1
	s.frame = ($ & ~(FF_FRAMEMASK|FF_HORIZONTALFLIP))|NEWFRAME|FLIP 
	s.tics,s.anim_duration = 6,6
	p.cmd.forwardmove,p.cmd.sidemove,p.cmd.buttons = 0,0,0
	s.angle,p.drawangle = stance.angle,stance.angle
	xs.edgeanimcd = 3
	xs.ringburstcd = 3
	xs.rollcd = 2	
	s.XS_lastNC = 99<<16
	p.powers[pw_nocontrol] = 2
	if p.exiting
		p.XSscalecam = 99<<16
		p.camerascale = 32500
	end	
end

local FULL = 999<<16 
XSon.StartTaunts = function(p, s, xs, fail)
	XSon.CancelFlight(p,s,xs)
	p.xsringburst = nil
	if xs.darkphase or p.powers[pw_super] or s.skin != "xsonic" 
		p.xstauntstance = nil xs.skydive = 0 xs.rollcd = 2 
		return --
	end

	--Make the tauntstance table!
	p.xstauntstance = {
	timer = 0, --How long we've been in taunt stance
	taunt = 0, --Which taunt we're current doing.
	page = 0, --What "page" of selectable taunts we're on.
		
	sprite2 = SPR2_FLY_, --Sprite2 we're using
	frame = 0, --Current frame of current taunt.
	startframe = nil, --Startframe. Will loop if it has one, otherwise keep it nil.
	endframe = A, --Final frame of current taunt.
	speed = 1, --Speed of animation in tics.
	flip = 0, --Horizontal frame flip
		
	angle = (p.cmd.angleturn<<16), --Angle Sonic is forced to face.			
	flash = 0, --flash white for a sec?
	tauntswap = true, --Swapped taunt this frame?
	up = 0,
	down = 0,
	left = 0, --controls
	right = 0,
	lolwhy = 0, --dice
	cooldown = 0,
	}
	local stance = p.xstauntstance
	local PANIM = p.panim
	local HITFLOOR = (s.eflags & MFE_JUSTHITFLOOR) and true or false
	local LASTMOMZ = xs.lastmomz*P_MobjFlip(s)
	
	if fail==77 --auto-exit?
		if not xs.skydive or p.cmd.buttons or p.cmd.sidemove or p.cmd.forwardmove or (LASTMOMZ > -14*s.scale)
			p.cmd.buttons = $|BT_TOSSFLAG
			p.pflags = $ & ~(PF_SPINNING|PF_SLIDING)
		elseif not (xs.skydive or (LASTMOMZ <= -32*s.scale))
			p.xstauntstance = nil return --
		end
	end	
	
	if s.state != S_PLAY_EDGE
		s.state = S_PLAY_STND
	end
	s.eflags = $ & ~MFE_JUSTHITFLOOR	
	s.tics = 8	
	s.momx,s.momy = p.cmomx,p.cmomy
	p.cmd.forwardmove,p.cmd.sidemove = 0,0
	p.speed = 0
	
	--Graceful landing.
	if ( 
	fail or
	(LASTMOMZ < -14*s.scale) and (xs.skydive or HITFLOOR==true or (p.pflags & (PF_JUMPED|PF_THOKKED)) or (PANIM>PA_DASH) or PANIM==PA_ETC)
	)
	and (p.cmd.buttons & BT_TOSSFLAG) and not (p.pflags & (PF_SPINNING|PF_SLIDING)) and not s.XS_comeback
		ShutUp(s)
		XS_SetTaunt(p, s, xs, stance, 11)
		stance.tauntswap = false
		stance.cooldown = 18 --Victory for Sonic!
		if (fail!=77)
			S_StartSoundAtVolume(s, sfx_cgot, 68)
			S_StartSoundAtVolume(s, sfx_token, 99)
			XSon.Quake(s, 12<<16, 2, 100<<16)
			P_RadiusAttack(s, s, 99*s.scale)
		end
		S_StartSound(s, sfx_xssfx7)
		XSSpawnJumpDust(s)
		xs.custom3 = FULL
	elseif fail or s.XS_comeback --Oh boy, are we failing terrible?	
		ShutUp(s)
		S_StopSoundByID(s, sfx_xssfxj)
		XS_SetTaunt(p, s, xs, stance, 10)
		stance.cooldown = 10 --EVEN WITHOUT WINGS, I CAN STILL---!! *thump*
		XSon.Sound(s, sfx_xssfxh, 135)
		S_StartSound(s, sfx_xssfx9) S_StartSound(nil, sfx_xssfx9, p)
		XSon.Quake(s, 80<<16, 4)
		stance.failed = true
		XSSpawnJumpDust(s)
		xs.custom3 = FULL
	else
		xs.custom3 = (p.cmd.buttons & BT_TOSSFLAG) and FULL or $
		s.sprite2 = SPR2_FLY_ --Thumbs up to left!
		s.frame = $ & ~FF_FRAMEMASK	
	end
	p.pflags = $|PF_JUMPDOWN|PF_USEDOWN
	xs.jump,xs.tossflag,xs.weaponnext,xs.weaponprev = FULL,FULL,FULL,FULL
	xs.rollcd = 2
	xs.skydive = 0 --No, we ain't.
end

addHook("NetVars", function(network) --The most important thing to sync ever, even tho' sounds don't sync.
	Hey = network($)
end)