addHook("MobjThinker", function(s)
if not s.player
return end
local p = s.player
//Grant SMS a "speed ticket" whenever he's going fast enough, spawning the speed lines behind him.
//....this poor guy will be drowning in debt
	if s
		if p.hmshascome and G_GametypeHasSpectators()
		s.smsglowticket = 2 //Glow in the dark, becoming a target for HMS.
		end
		if s.nrollanga
			if s.rollangle and not ((s.state >= S_PLAY_NIGHTS_STUN) and (s.state <= S_PLAY_NIGHTS_ATTACK))
			s.rollangle = 0
			end
			s.fboostgfx = 0
			s.nrollanga = false
		end
		if (s.skin == "sms")
		
	//Revert into a custom base Sonic for NiGHTs when you have SMS selected as a skin
	
			if (p.powers[pw_carry] == CR_NIGHTSMODE) 
				if p.powers[pw_flashing] and (s.state == S_PLAY_NIGHTS_STUN or s.state == S_PLAY_NIGHTS_PULL)
					if p.drillmeter and (p.drillmeter >= 3)
					p.drillmeter = $-3 //As a downside for your boost, you lose drill meter when you get hurt 
					else
					p.drillmeter = 0
					end
				end
				if (p.cmd.buttons & BT_CUSTOM1) and not (p.sms_tapnothold and p.sms_tapnothold > 1)
				and not s.fboostgfx and (s.state >= S_PLAY_NIGHTS_STAND and s.state <= S_PLAY_NIGHTS_DRILL)
					if (p.drillmeter and (p.drillmeter > 200)) 
					s.fboost = P_SpawnMobj(s.x+s.momx, s.y+s.momy, s.z+s.momz, MT_NIGHTSBUMPER)
					s.fboost.sprite = SPR_NULL
					s.fboost.scale = $*3/2
						if (p.cmd.sidemove < 0)
						s.fboost.threshold = $-185 //Seems about right
						end
					s.fboost.nsonicb = s
					s.fboost.fuse = 1
					s.fboostgfx = 30
					S_StartSound(s, sfx_zoom)
					S_StartSound(s, sfx_bkpoof)
					A_SMSquake(s, 90*FRACUNIT, 12, 1100)
					P_FlashPal(p, PAL_MIXUP, 3)
					p.drillmeter = $-200
						for d = 0,15
						P_SpawnParaloop(s.x, s.y, s.z+FixedMul(20*FRACUNIT, s.scale), 10*FRACUNIT, 16, MT_NIGHTSPARKLE, d*ANGLE_22h, S_SMSTSPARK1, false)
						end
					else
					S_StartSound(s, sfx_cdfm70)
					s.flags2 = $|MF2_DONTDRAW
					end
				end
				if s.fboostgfx
					p.camerascale = FRACUNIT*3/2 //Zoom the camera out.
					s.bhlcamtimer = 70
					if (s.fboostgfx > 19)
						if not p.powers[pw_nights_helper]				
						p.powers[pw_nights_helper] = 105 
						end
					s.state = S_SMS_AIRBOOST
					p.smsarboost = P_SpawnMobj(s.x, s.y, s.z+((20*FRACUNIT)*(P_MobjFlip(s))), MT_SMSAIRBOOST)
					p.smsarboost.color = s.color
					p.smsarboost.scale = $+P_RandomRange(5000, 50000) 
					p.smsarboost.state = $+P_RandomRange(0,2)
					s.frame = $|FF_FULLBRIGHT
					else
						if (s.fboostgfx == 19)
						p.bumpertime = 0
						A_SMSquake(s, 36*FRACUNIT, 16, 400)
						S_StartSound(s, sfx_s3k66)
							for d = 0,15 
							P_SpawnParaloop(s.x+s.momx, s.y+s.momy, s.z+s.momz+s.height*2, 10*FRACUNIT, 16, MT_NIGHTSPARKLE, d*ANGLE_22h, S_SMSTSPARK1, false)
							end
						end
					s.frame = $ & ~FF_FULLBRIGHT
					p.smsarboost = P_SpawnMobj(s.x, s.y, s.z+((20*FRACUNIT)*(P_MobjFlip(s))), MT_SMSAIRBOOST)
					p.smsarboost.color = SKINCOLOR_SKY
					p.smsarboost.state = $+P_RandomRange(0,2)
					end
				s.fboostgfx = $-1
				P_SpawnGhostMobj(s)
				end
				if (s.state == S_PLAY_STND or s.state == S_PLAY_NIGHTS_STAND)
				s.state = S_PLAY_NIGHTS_FLOAT
				end
				if not s.nrollangle
				s.nrollangle = FixedAngle(39*FRACUNIT)
				else
				s.nrollangle = $+FixedAngle(39*FRACUNIT)
				end
			end
			
		//Yes, those wind lines around SMS' body when he runs are actually speed tickets. Guy's drowning in debt.
			
			if s.smsspeedticket	
			 if not (p.smsgraphix and p.smsgraphix == 2)
			  if not p.smsdivetimer and not (p.sms_ringburstfly and p.sms_ringburstfly == 1) and s.health
			  and not p.sms_afterstompthok and not p.sms_stompanim and not p.powers[pw_carry]
			  and not (s.hms_jumprisen and s.hmsspinpass and (s.momz > 10*FRACUNIT or s.momz < -10*FRACUNIT))
			  
			  	if not (s.smssoundobj3 and s.smssoundobj3.valid and s.smssoundobj3.health)
				and not (s.smssoundobj2 and s.smssoundobj2.valid and s.smssoundobj2.health) //Harsh wind takes priority.
					s.smssoundobj3 = P_SpawnMobj(s.x, s.y, s.z, MT_SMSSOUNDOBJ)
					s.smssoundobj3.master = s
					s.smssoundobj3.health = 1
					S_StartSound(s.smssoundobj3, sfx_machw)
					s.smssoundobj3.smsmwtim = 74 //51 for harsh
				end
			    if P_IsObjectOnGround(s) and s.standingslope
				s.sprintlin = P_SpawnMobj(s.x+FixedMul((P_RandomRange(9, 35)*FRACUNIT), cos(s.angle+ANGLE_90)), s.y+FixedMul((P_RandomRange(9, 35)*FRACUNIT), sin(s.angle+ANGLE_90)), s.z+(P_RandomRange(1, 58)*P_MobjFlip(s))*FRACUNIT, MT_SMSSPRINTLINE)
				else
			    s.sprintlin = P_SpawnMobj(s.x+(s.momx/2)+FixedMul((P_RandomRange(9, 35)*FRACUNIT), cos(s.angle+ANGLE_90)), s.y+(s.momy/2)+FixedMul((P_RandomRange(9, 35)*FRACUNIT), sin(s.angle+ANGLE_90)), s.z+s.momz+(P_RandomRange(1, 58)*P_MobjFlip(s))*FRACUNIT, MT_SMSSPRINTLINE)
				end
					s.sprintlin.scale = s.scale
					s.sprintlin.eflags = s.eflags
					s.sprintlin.angle = R_PointToAngle2(s.x, s.y, (s.x+s.momx), (s.y+s.momy))-(ANG2*3)
					s.sprintlin.momx = s.momx/4
					s.sprintlin.momy = s.momy/4
					s.sprintlin.momz = s.momz-(s.momz/2)
					if ((s.momz*P_MobjFlip(s)) < -4*FRACUNIT)
					P_Thrust(s.sprintlin, s.angle+ANGLE_90, 1*FRACUNIT)
					else
					P_Thrust(s.sprintlin, s.angle+ANGLE_90, 3*FRACUNIT)
					end
				 if (p.sms_boostlevel < 33) and not p.hypermysticsonic
					s.sprintlin.state = S_SMSSPRINTLINE1S
					s.sprintlin.flags = $|MF_SCENERY
				 else		
				 	s.sprintlin.target = s
					s.sprintlin.color = SKINCOLOR_KETCHUP
				 	if not P_RandomRange(0, 2)
					s.sprintlin.state = S_SMSSPRINTLINE2M
					else
					s.sprintlin.state = S_SMSSPRINTLINE1M
					end
				 end
				if s.sprintlin and s.sprintlin.valid and (s.sprintlin.eflags & MFE_UNDERWATER)
				s.sprintlin.fuse = 7
				s.sprintlin.state = P_RandomRange(S_SMALLBUBBLE, S_MEDIUMBUBBLE)
				end
			    if P_IsObjectOnGround(s) and s.standingslope
			    s.sprintlin = P_SpawnMobj(s.x+FixedMul((P_RandomRange(-9, -35)*FRACUNIT), cos(s.angle+ANGLE_90)), s.y+FixedMul((P_RandomRange(-9, -35)*FRACUNIT), sin(s.angle+ANGLE_90)), s.z+(P_RandomRange(1, 58)*P_MobjFlip(s))*FRACUNIT, MT_SMSSPRINTLINE)
				else					
				s.sprintlin = P_SpawnMobj(s.x+(s.momx/2)+FixedMul((P_RandomRange(-9, -35)*FRACUNIT), cos(s.angle+ANGLE_90)), s.y+(s.momy/2)+FixedMul((P_RandomRange(-9, -35)*FRACUNIT), sin(s.angle+ANGLE_90)), s.z+s.momz+(P_RandomRange(1, 58)*P_MobjFlip(s))*FRACUNIT, MT_SMSSPRINTLINE)
				end
					s.sprintlin.scale = s.scale
					s.sprintlin.eflags = s.eflags
					s.sprintlin.angle = R_PointToAngle2(s.x, s.y, (s.x+s.momx), (s.y+s.momy))+(ANG2*3)
					s.sprintlin.momx = s.momx/4
					s.sprintlin.momy = s.momy/4
					s.sprintlin.momz = s.momz-(s.momz/2)
					if ((s.momz*P_MobjFlip(s)) < -4*FRACUNIT)
					P_Thrust(s.sprintlin, s.angle+ANGLE_90, -1*FRACUNIT)
					else
					P_Thrust(s.sprintlin, s.angle+ANGLE_90, -3*FRACUNIT)
					end

				  if (p.sms_boostlevel < 33) and not p.hypermysticsonic
					s.sprintlin.state = S_SMSSPRINTLINE1S
					s.sprintlin.flags = $|MF_SCENERY
				  else
				    s.sprintlin.target = s
					s.sprintlin.color = SKINCOLOR_KETCHUP
				    if not P_RandomRange(0, 2)
					s.sprintlin.state = S_SMSSPRINTLINE2
					end
				  end
				end
				if s.sprintlin and s.sprintlin.valid and (s.sprintlin.eflags & MFE_UNDERWATER)
				s.sprintlin.fuse = 7 //Become bubbles underwater
				s.sprintlin.state = P_RandomRange(S_SMALLBUBBLE, S_MEDIUMBUBBLE)
				end
			 end
			end
			s.smsspeedticket = false
		end

//Glowing ticket here! Glow ticket makes the shine appear.

			if s and ( ( ((s.color >= SKINCOLOR_SUPERSILVER1) or p.shinyglosscoat) and (s.skin == "sms")) or s.smsglowticket)
			and s.subsector and s.subsector.sector and not (p.powers[pw_carry] == CR_NIGHTSMODE) and s.health
			 if s.cooldownlight
			 s.cooldownlight = $+1
			    if (s.cooldownlight > 23)
				s.cooldownlight = 0
				end
			 end
			 p.smsrlightsec = s.subsector.sector.lightlevel
			  for fof in s.subsector.sector.ffloors()
					if fof and (fof.flags & FF_EXISTS) 
						if not (fof.flags & FF_NOSHADE) and not (fof.flags & FF_DOUBLESHADOW)
						and (s.z < fof.bottomheight)
						p.smsrfoflight = fof.toplightlevel

						elseif (fof.flags & FF_CUTSPRITES) and ((s.z >= fof.bottomheight) and (s.z+(s.height/2) < fof.topheight))
						p.smsrfoflight = fof.toplightlevel+20
						end
					end
			  end
				if p.smsrfoflight
					p.smsrlightsec = p.smsrfoflight
				else
					p.smsrlightsec = s.subsector.sector.lightlevel
				end
				if (p.smsrlightsec > 179) and (s.eflags & MFE_UNDERWATER)
					p.smsrlightsec = 155
					s.cooldownlight = 0
					s.smsgoldenshine = true
				elseif (p.smsrlightsec > 179) and s.smsgoldenshine
					if not s.cooldownlight
					s.cooldownlight = 1
					end
					s.smsgoldenshine = false
				end
				if (p.smsrlightsec < 180)
					s.cooldownlight = 0
					s.smsgoldenshine = true
				end
				
					if p.hypermysticsonic and (p.smsrlightsec < 210)
					and not (p.smsgraphix and p.smsgraphix == 2)
			  	  		s.hshinelin = P_SpawnMobj(s.x, s.y, s.z+(s.height/2)+FixedMul((11*FRACUNIT*P_MobjFlip(s)), s.scale), MT_THOK)
						s.hshinelin.sprite = SPR_AURA
						s.hshinelin.frame = S|TR_TRANS90|FF_FULLBRIGHT
				 		s.hshinelin.color = s.color
						s.hshinelin.flags = $|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP
						if s.sqaang != nil
				  		s.hshinelin.rollangle = s.sqaang*ANG1
						end
					  	s.hshinelin.scale = s.scale*2
				  		s.hshinelin.tics = 2
				  		s.hshinelin.momx = s.momx
				 		s.hshinelin.momy = s.momy
				  		s.hshinelin.momz = s.momz
				 		s.hshinelin.scalespeed = $+P_RandomRange(-500, 1000)				  
				  		s.hshinelin.destscale = s.hshinelin.scalespeed+1
			  		end	
				
			  if s.health and ((p.smsrlightsec != nil and (p.smsrlightsec < 180)) or s.cooldownlight) and not p.hypermysticsonic
			  and not (p.smsgraphix and p.smsgraphix == 2)
			  	  s.shinelin = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_THOK)
				  s.shinelin.sprite = SPR_OILF
				  
				  if s.cooldownlight
				      if not ((s.scale-(s.cooldownlight*1000)) < 0)
					  s.shinelin.scale = s.scale-(s.cooldownlight*1000)
					//  if s.hshinelin and s.hshinelin.valid
					//	s.hshinelin.scale = s.scale-(s.cooldownlight*1000)
					//	end
					  else
					  s.shinelin.scale = s.scale/2
					//  if s.hshinelin and s.hshinelin.valid
					//	s.hshinelin.scale = s.scale/2
					//	end
					  end
				  else
				    if p.hypermysticsonic
				    s.shinelin.scale = s.scale*4/3
						if (P_MobjFlip(s) >= 1)
						s.shinelin.z = $+11*FRACUNIT
						end
					else
					s.shinelin.scale = s.scale
					end
				  end
				  
				  s.shinelin.frame = A|TR_TRANS90|FF_FULLBRIGHT
				  
				  if (p.smsrlightsec < 100)
			  	  s.shinelin.tics = 4
				  elseif (p.smsrlightsec < 150)
				  s.shinelin.tics = 3
				  else
				  s.shinelin.tics = 2
				  end
				  
			//	  s.shinelin.eflags = s.eflags
				  s.shinelin.momx = s.momx
				  s.shinelin.momy = s.momy
				  s.shinelin.momz = s.momz
				  s.shinelin.scalespeed = $+P_RandomRange(-500, 1000)				  
				  s.shinelin.destscale = 9
				  s.shinelin.flags = MF_NOCLIP|MF_NOCLIPHEIGHT
				  if not s.cooldownlight
				  s.smsgoldenshine = true
				  end
			  end
			  p.smsrfoflight = nil
		    end
		   if s.smsglowticket and (s.skin != "sms" or not ((s.color >= SKINCOLOR_SUPERSILVER1) or p.shinyglosscoat or p.hypermysticsonic))
		   s.smsglowticket = $-1
		      if not s.smsglowticket
			  s.frame = $ & ~FF_FULLBRIGHT
			  end
		   end
		
		
		//WHY IS THIS HERE?! ...WHY NOT?!
		//SMS can pick up items that are considered pushable objects!

		if p.smspickup
			if p.smspickup and p.smspickup.valid
			p.smspickup.eflags = s.eflags
			p.smspickup.rollangle = s.rollangle
				if (p.smspickup.type == MT_PLAYER)
				p.smspickup.state = S_PLAY_PAIN
					if p.smspickup.player
					p.smspickup.player.powers[pw_nocontrol] = 2
						if (p.smspickup.player.cmd.buttons & BT_JUMP) or p.sms_intoship or p.smspickup.player.sms_intoship
						s.whoopsnope = true
						P_DoJump(p.smspickup.player, true)
						p.smspickup.player.pflags = $|PF_JUMPED|PF_JUMPDOWN
						p.smspickup.state = S_PLAY_ROLL
							if p.smspickup.smspickupflags
							p.smspickup.flags = p.smspickup.smspickupflags
							p.smspickup.smspickupflags = nil
							end
						p.smspickup.lemmego = 2
						end
					end
				end
				
			end
			if (s and s.valid and not s.skin == "sms")
			or ((p.smspickup and not p.smspickup.valid) or (p.smspickup and p.smspickup.valid and not p.smspickup.health))
			or (s and not (s.valid or s.health)) or P_PlayerInPain(p)
			or (leveltime == 2) or p.exiting or s.whoopsnope
			or ((p.cmd.buttons & BT_TOSSFLAG) and not (p.sms_tossflaghold and p.sms_tossflaghold > 1))
			or ( ((p.cmd.buttons & BT_WEAPONPREV) and not (p.weaponprevhold and p.weaponprevhold > 1)) and not p.hypermysticsonic)
			or (p.cmd.buttons & BT_ATTACK) and not (p.sms_flamebuttonhold and p.sms_flamebuttonhold > 1)
			or (p.cmd.buttons & BT_FIRENORMAL) and not p.sms_nflamehold
				s.whoopsnope = nil
				if p.smspickup and p.smspickup.valid and not p.smspickup.lemmego
					P_InstaThrust(p.smspickup, s.angle, 7*FRACUNIT)
					P_SetObjectMomZ(p.smspickup, 5*FRACUNIT)
					p.smspickup.smspickedup = nil
					p.smspickup.rollangle = 0
						if ((p.cmd.buttons & BT_TOSSFLAG) and not (p.sms_tossflaghold and p.sms_tossflaghold > 1))
						or ( ((p.cmd.buttons & BT_WEAPONPREV) and not (p.weaponprevhold)) and not p.hypermysticsonic)
						or ((p.cmd.buttons & BT_FIRENORMAL) or (p.cmd.buttons & BT_ATTACK))
							if (p.speed < 5*FRACUNIT)
							p.powers[pw_nocontrol] = $+7
							end
						P_InstaThrust(s, s.angle, -7*FRACUNIT)
						p.sms_flamedelay = 28
						p.sms_nflamehold = 10
						if p.sms_ringburstfly
							s.momx = $/4
							s.momy = $/4
							s.momz = $/4
							p.sms_ringburstfly = 0
							p.sms_ringburstdrain = 0
						end
						s.hms_jumphold = 10
						s.smsthrowcd = 17 //Half a second of no more throwing!
						p.sms_flamebuttonhold = 11
						p.hmsthrownnorise = true
						p.pflags = $ & ~PF_JUMPED
							if p.hypermysticsonic and ((p.cmd.buttons & BT_ATTACK) or (p.cmd.buttons & BT_FIRENORMAL)) and s.skin == "sms"
							s.state = S_HMSCOMETHAYMAKER2
							s.hms_readyriseboost = 0
							p.novafire = 0
							p.powers[pw_nocontrol] = 11
							s.whshu = P_SpawnMobj(s.x, s.y, s.z, MT_SMSTHROWTRACKER)
							s.whshu.hmsthrow = 1
							s.whshu.hmsthrowaim = p.aiming
							s.whshu.hmsthrowang = s.angle
							s.whshu.hmsthrowog = p
							s.whshu.target = p.smspickup
							
							S_StartSound(s, sfx_beflap)
							S_StartSound(s, sfx_s3k83)
							elseif not p.hypermysticsonic and ((p.cmd.buttons & BT_ATTACK) or (p.cmd.buttons & BT_FIRENORMAL)) and s.skin == "sms"
							s.state = S_SMSHUGEFLAMETOSS
							p.sms_flamebuttonhold = 10
							s.tics = $+3
							p.powers[pw_nocontrol] = 11
							s.whshu = P_SpawnMobj(s.x, s.y, s.z, MT_SMSTHROWTRACKER)
							s.whshu.smsthrow = 1
							s.whshu.smsthrowaim = p.aiming
							s.whshu.smsthrowang = s.angle
							s.whshu.smsthrowog = p
							s.whshu.target = p.smspickup
							P_SetObjectMomZ(s, 5*FRACUNIT)
							P_Thrust(s, s.angle, -9*FRACUNIT)
							S_StartSound(s, sfx_wepfir)
								if (p.cmd.buttons & BT_ATTACK) and (P_LookForEnemies(p, false, true)) //Use fire to do a homing throw!
								s.whshu.smsthrowguy = P_LookForEnemies(p)
								end
							
							elseif not p.hypermysticsonic
							s.state = S_PLAY_GASP //Other skins can throw too, but not the strong throw since they have no sprites for it.
							end
							if p.smspickup and p.smspickup.valid
								if s.whshu and s.whshu.valid and s.whshu.smsthrowguy and s.whshu.smsthrowguy.valid
									s.forcesmsangletimer = 10
									s.forcesmsangle = R_PointToAngle2(s.x, s.y, s.whshu.smsthrowguy.x, s.whshu.smsthrowguy.y)
								else
									s.forcesmsangletimer = 10
									s.forcesmsangle = s.angle							
								end
							end
						end
						if (p.smspickup.type == MT_GARGOYLE) and p.smspickup.smspickupflags
							p.smspickup.flags = p.smspickup.smspickupflags|MF_PUSHABLE
							p.smspickup.smspickupflags = nil
						elseif not p.smspickup.pickedupmonitor and p.smspickup.smspickupflags
							p.smspickup.flags = p.smspickup.smspickupflags
							p.smspickup.smspickupflags = nil
						end

						if p.smspickup.pickedupmonitor
						s.whshu = P_SpawnMobj(s.x, s.y, s.z, MT_SMSTHROWTRACKER)
						s.whshu.throwntracker = true
						s.whshu.ogsms = s
						s.whshu.target = p.smspickup
							if not p.smspickup.smspickupflags
							p.smspickup.smspickupflags = p.smspickup.flags
						//	p.smspickup.flags = p.smspickup.smspickupflags
							p.smspickup.flags = $|MF_NOCLIPTHING & ~MF_MONITOR & ~MF_SHOOTABLE & ~MF_NOGRAVITY
							end
						end
						
						if p.smspickup and p.smspickup.valid and (p.smspickup.type == MT_PLAYER)
						p.smspickup.state = S_PLAY_PAIN
							if p.smspickup.player
							p.smspickup.player.powers[pw_carry] = 0
							p.smspickup.player.powers[pw_nocontrol] = 22
							end
						end

						p.smspickup = nil
						p.sms_tossflaghold = 5
						p.weaponprevhold = 5
					if p.smspickup and not (p.smspickup.valid or p.smspickup.health) //Failsafe.
						p.smspickup = nil
						p.sms_tossflaghold = 5
						p.weaponprevhold = 5
					end
				else
					p.smspickup = nil
				end
			end
		end
		if s.smpktarget and s.smpktarget.valid and s.smpktarget.health
		local zm = s.smpktarget
		  if not p.smspickup
		  S_StartSound(s, sfx_cdfm17)
		  S_StartSound(s, sfx_s251)
		  s.novawave = P_SpawnMobj(zm.x, zm.y, zm.z, MT_HMSNOVAWAVE)
		  s.novawave.scale = zm.scale/12
		  s.novawave.tics = 2
		  s.novawave.destscale = s.novawave.scalespeed+1
		  s.novawave.color = SKINCOLOR_BLUE
		  s.novawave = P_SpawnMobj(zm.x, zm.y, zm.z+zm.height/2, MT_HMSNOVAWAVE)
		  s.novawave.scale = zm.scale/12
		  s.novawave.tics = 2
		  s.novawave.destscale = s.novawave.scalespeed+1
		  s.novawave.color = SKINCOLOR_BLUE
		  zm.rollangle = 0
			if (zm.flags & MF_MONITOR)
				if zm.smspickupflags
				zm.flags = zm.smspickupflags
				zm.smspickupflags = nil
				end
				zm.smspickupflags = zm.flags
				zm.pickedupmonitor = true
				zm.flags = $ & ~MF_MONITOR
				zm.flags = $ & ~MF_SHOOTABLE
				p.smspickup = zm
				zm.smspickedup = true
				zm.flags = $|MF_NOCLIPTHING
				p.sms_tossflaghold = 5
			else
				if not ( (zm.type == MT_GARGOYLE) and ((zm.subsector.sector.floorpic == "DSTRACK2") or (zm.subsector.sector.floorpic == "DSTRACK1")) )
					if zm.smspickupflags
					zm.flags = zm.smspickupflags
					zm.smspickupflags = nil
					end
					p.smspickup = zm
					zm.smspickupflags = zm.flags
					zm.smspickedup = true
					zm.flags = $ & ~MF_PUSHABLE
					zm.flags = $ & ~MF_SOLID
					zm.flags = $|MF_NOCLIPTHING|MF_NOCLIPHEIGHT
					p.sms_tossflaghold = 5
				end
			end
		  end
			s.smpktarget = nil
		end

		if (gametype == GT_COOP) //G_PlatformGametype()
		and (s and s.skin == "sms") and s.health and not (p.pflags & PF_SPINNING) // and P_IsObjectOnGround(s)
			if p.hypermysticsonic
				s.eymon = P_SpawnMobj(s.x+FixedMul(119*FRACUNIT,cos(s.angle)), s.y+FixedMul(119*FRACUNIT,sin(s.angle)), s.z-60*FRACUNIT, MT_SMSECHECK)
				if s.eymon and s.eymon.valid
				s.eymon.justcheckin = true
				s.eymon.smsepickup = true
				s.eymon.target = s
				s.eymon.radius = 120*FRACUNIT
				s.eymon.height = 120*FRACUNIT
				end
			else
				s.eymon = P_SpawnMobj(s.x+FixedMul(49*FRACUNIT,cos(s.angle)), s.y+FixedMul(49*FRACUNIT,sin(s.angle)), s.z-60*FRACUNIT, MT_SMSECHECK)
				if s.eymon and s.eymon.valid
				s.eymon.justcheckin = true
				s.eymon.smsepickup = true
				s.eymon.target = s
				s.eymon.radius = 50*FRACUNIT
				s.eymon.height = 120*FRACUNIT
				end
			end
			if ( (p.cmd.buttons & BT_TOSSFLAG) //Throw monitors! ..and other stuff, like players and pushables!
			and not (p.sms_tossflaghold and p.sms_tossflaghold > 1) and not p.powers[pw_nocontrol]
			or ((p.cmd.buttons & BT_WEAPONPREV) and not (p.weaponprevhold and p.weaponprevhold > 1))
			or (p.cmd.buttons & BT_ATTACK) and not (p.sms_flamebuttonhold and p.sms_flamebuttonhold > 1)
			or (p.cmd.buttons & BT_FIRENORMAL) and not p.sms_nflamehold)
			and not p.smspickup
			and not p.exiting
				if p.hypermysticsonic
					s.eymon = P_SpawnMobj(s.x+FixedMul(119*FRACUNIT,cos(s.angle)), s.y+FixedMul(119*FRACUNIT,sin(s.angle)), s.z-60*FRACUNIT, MT_SMSECHECK)
					if s.eymon and s.eymon.valid
					s.eymon.smsepickup = true
					s.eymon.target = s
					s.eymon.radius = 120*FRACUNIT
					s.eymon.height = 120*FRACUNIT
					end
				else
					s.eymon = P_SpawnMobj(s.x+FixedMul(49*FRACUNIT,cos(s.angle)), s.y+FixedMul(49*FRACUNIT,sin(s.angle)), s.z-60*FRACUNIT, MT_SMSECHECK)
					if s.eymon and s.eymon.valid
					s.eymon.smsepickup = true
					s.eymon.target = s
					s.eymon.radius = 50*FRACUNIT
					s.eymon.height = 120*FRACUNIT
					end
				end
			//	A_SMSFindTarget(s, 80*FRACUNIT, 15) //Find it and pick it up.
			end
		end
		//Execute SMS ssxa aura		
		
		if s and s.health and s.ssxaticket
			if not p.smsgraphix
				if (p.powers[pw_carry] == CR_NIGHTSMODE)
				s.ssxaticket = false
				return
				end
			  
			//	s.ssxa = P_SpawnMobj(s.x+FixedMul((P_RandomRange(9, 22)*FRACUNIT), cos(s.angle+ANGLE_90)), s.y+FixedMul((P_RandomRange(9, 22)*FRACUNIT), sin(s.angle+ANGLE_90)), s.z+(P_RandomRange(0, 54))*FRACUNIT, MT_SSXA)
				if p.hypermysticsonic
					if (leveltime % 2 == 0)
					s.ssxa = P_SpawnMobj(s.x+P_RandomRange(6, 20)*FRACUNIT, s.y+P_RandomRange(6, 20)*FRACUNIT, s.z+P_RandomRange(0, 79)*FRACUNIT, MT_SSXA)
					else
					s.ssxa = P_SpawnMobj(s.x-P_RandomRange(6, 20)*FRACUNIT, s.y+P_RandomRange(6, 20)*FRACUNIT, s.z+P_RandomRange(0, 79)*FRACUNIT, MT_SSXA)
					end
				else
					if (leveltime % 2 == 0)
					s.ssxa = P_SpawnMobj(s.x+P_RandomRange(6, 20)*FRACUNIT, s.y+P_RandomRange(6, 20)*FRACUNIT, s.z+P_RandomRange(0, 54)*FRACUNIT, MT_SSXA)
					else
					s.ssxa = P_SpawnMobj(s.x-P_RandomRange(6, 20)*FRACUNIT, s.y+P_RandomRange(6, 20)*FRACUNIT, s.z+P_RandomRange(0, 54)*FRACUNIT, MT_SSXA)
					end
				end
				s.ssxa.eflags = s.eflags
				s.ssxa.sprite = SPR_SMST		
				if P_RandomRange(0,1)
				s.ssxa.mcd = P_RandomRange(2, 4) 
				s.ssxa.frame = (P_RandomRange(3, 6))|FF_FULLBRIGHT|TR_TRANS30
				else
				s.ssxa.mcd = P_RandomRange(2, 4) 
				s.ssxa.frame = (P_RandomRange(3, 6))|FF_FULLBRIGHT|TR_TRANS40
				end
				if p.hypermysticsonic
				s.ssxa.scalespeed = $*P_RandomRange(1, 3)
				else
				s.ssxa.scalespeed = $/P_RandomRange(1, 5)
				end
				s.ssxa.destscale = $*7
				P_SetObjectMomZ(s.ssxa, 32555+P_RandomRange(-20000, 40000))
				
			//	s.ssxa = P_SpawnMobj(s.x+(s.momx/2)-FixedMul((P_RandomRange(9, 22)*FRACUNIT), cos(s.angle+ANGLE_90)), s.y+(s.momy/2)-FixedMul((P_RandomRange(9, 22)*FRACUNIT), sin(s.angle+ANGLE_90)), s.z+s.momz+(P_RandomRange(1, 54)*P_MobjFlip(s))*FRACUNIT, MT_SSXA)
				if (leveltime % 2 == 0)
				s.ssxa = P_SpawnMobj(s.x+P_RandomRange(-6, -20)*FRACUNIT, s.y+P_RandomRange(-6, -20)*FRACUNIT, s.z+P_RandomRange(0, 54)*FRACUNIT, MT_SSXA)
				else
				s.ssxa = P_SpawnMobj(s.x+P_RandomRange(-6, -20)*FRACUNIT, s.y-P_RandomRange(-6, -20)*FRACUNIT, s.z+P_RandomRange(0, 54)*FRACUNIT, MT_SSXA)
				end
				s.ssxa.eflags = s.eflags
				s.ssxa.sprite = SPR_SMST
				if P_RandomRange(0,1)
				s.ssxa.frame = (P_RandomRange(3, 6))|FF_FULLBRIGHT|TR_TRANS30
				else
				s.ssxa.frame = (P_RandomRange(3, 6))|FF_FULLBRIGHT|TR_TRANS10
				end
				if p.hypermysticsonic
				s.ssxa.scalespeed = $*P_RandomRange(1, 3)
				else
				s.ssxa.scalespeed = $/P_RandomRange(1, 5)
				end
				s.ssxa.destscale = $*7
				P_SetObjectMomZ(s.ssxa, 32555+P_RandomRange(-20000, 40000))
			end
		s.ssxaticket = false
		end	
	end
end, MT_PLAYER)

//Put SMS into the toss position! If people get close, toss them!

addHook("MobjCollide", function(s, t)
		if s and ((s.state == S_SMSTOSSING) or (s.state == S_SMSTOSSREADY)) and t and t.player and (t.player.pflags & PF_CANCARRY)
		return false
		else
		   if t and t.valid and t.player and not t.player.powers[pw_carry]
		   and s and s.valid and (s.skin == "sms") and s.player
		local p = s.player
			if ( (p.cmd.buttons & BT_TOSSFLAG) or ((p.cmd.buttons & BT_WEAPONPREV) and not p.hypermysticsonic) )
			and  (p.speed < 3*FRACUNIT)
			and P_IsObjectOnGround(s)
			and ((t.type == MT_PLAYER) and not (t.skin == "sms" and ( (t.player.cmd.buttons & BT_TOSSFLAG) or ((t.player.cmd.buttons & BT_WEAPONPREV) and not t.player.hypermysticsonic) )))
			and not (s.state == S_SMSTOSSING) and not (s.state == S_PLAY_GASP)
			and not p.powers[pw_nocontrol]
			and not (p.pflags & PF_SPINNING) 
			s.target = t
				if s.target
				local st = s.target
					if ((st.player.cmd.buttons & BT_CUSTOM3) or (st.player.speed > FRACUNIT))
				//	and ((st.color == s.color) or (gametype == GT_COOP))
						if not ((s.x > st.x+st.radius+9*FRACUNIT) or (s.x < st.x-st.radius-9*FRACUNIT))
						and not ((s.y > st.y+st.radius+9*FRACUNIT) or (s.y < st.y-st.radius-9*FRACUNIT))
						and not ((s.z > st.z+st.height+9*FRACUNIT) or (s.z < st.z-st.height-9*FRACUNIT))
						and not (st.skin == "sms" and ( (st.player.cmd.buttons & BT_TOSSFLAG) or ((st.player.cmd.buttons & BT_WEAPONPREV) and not st.player.hypermysticsonic) ))
							P_SetObjectMomZ(st, 24*FRACUNIT, false)
							P_Thrust(st, s.angle+ ANGLE_180, 23*FRACUNIT)
							S_StartSound(st, sfx_bljp)
							P_SpawnGhostMobj(st)
							st.player.pflags = $|PF_JUMPED
								if not (st.player.charflags & SF_NOJUMPSPIN)
								st.state = S_PLAY_ROLL
								else
								st.state = S_PLAY_SPRING
								
								end
								s.state = S_SMSTOSSING
								if p.hypermysticsonic
								s.hmsoframe = F
								end
							end
    					end
    				end		
    			end
		   end
		end
end, MT_PLAYER)

addHook("MobjMoveBlocked", function(s)
	if not ((s.skin == "sms") and s.player and (s.player.speed > 80*FRACUNIT))
	return end
		local p = s.player
		local newangle = 0
		local oldangle = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
		s.smsmovesuccess = false
						if diff != nil
							if (diff > ANGLE_180)
							diff = InvAngle(InvAngle(diff)/8)
 							else
							diff = $/8
							end
							newsmsang = s.angle+diff
            			end
			
			if (p.cmd.sidemove or p.cmdforwardmove) and P_IsObjectOnGround(s) 
			and not (p.pflags & PF_SPINNING)
			and ( p.hypermysticsonic or (s.state == S_PLAY_WALK) or (s.state == S_PLAY_RUN) or ((s.state >= S_SMS_BOOST01) and (s.state <= S_SMS_BOOST04)) )
				for d = -4,4
					if not s.smsmovesuccess
						if (P_TryMove(s, s.x+FixedMul(50*FRACUNIT, cos(s.angle+(ANG10*d))), s.y+FixedMul(50*FRACUNIT, sin (s.angle+(ANG10*d))), false) )
							s.smsmovesuccess = true
							newangle = s.angle+(ANG10*d)
						end
					end
				end
				if s.smsmovesuccess --We found the solution!
				local diff = (newangle-oldangle)
					for d = 1,20
						s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_MINECARTSPARK)
						local t = s.missilelight
						t.scale = s.scale/12
						t.fuse = 30
						P_InstaThrust(t, newangle, s.player.speed*2)
						t.momz = P_RandomRange(4,7)*FRACUNIT
					end
					
					if P_RandomRange(0,1)
					S_StartSound(s, sfx_s3k7e)
					A_BossScream(s, 0, MT_EXPLODE)
					else
					A_BossScream(s, 0, MT_WATERZAP)
					S_StartSound(s, sfx_s3k9a)
					end
					
					if diff != nil --Now we go further.
					s.angle = $+diff
					return true	
					end
            	end
		   end
end, MT_PLAYER)

//Old Super Tails' 2.1 Whirlwind ability!

addHook("JumpSpinSpecial", function(p)
	if p.mysticsuper and p.mo
		if (p.charability == CA_FLY) and not p.powers[pw_tailsfly]
		and not (p.spinhold and (p.spinhold > 1)) and not (p.pflags & PF_THOKKED)
			p.pflags = $ & ~PF_SHIELDABILITY
			P_DoJumpShield(p)
			p.mo.momz = $*2
			p.pflags = $|PF_SHIELDABILITY
		end
	end
end)

//Gain an analog homing thok in directionchar. Seems to fit the playstyle, I think.

addHook("AbilitySpecial", function(p)
	//Make sure HMS never glides or climbs. He needs an ability only for breaking walls.
	if p.hypermysticsonic or p.secondjump == 167
	return true
	end
	if p.mo and (p.mo.skin == "sms")
	  if (p.charability == CA_THOK) and not (p.pflags & PF_THOKKED)
		 p.sms_readyairboost = 0
	 	 p.sms_jumphold = 10
		 p.mo.atomdiveusebuffer = 0
		 p.mo.smsthokanim = true
		 	if p.hometrickanim
			p.hometrickanim = false
			p.mo.state = S_PLAY_ROLL
			end
	  elseif (p.charability == CA_HOMINGTHOK)
	  	 if (p.charflags & SF_MULTIABILITY)
	  	 p.mo.smsthokanim = true
		 end
	  	 if not (p.pflags & PF_THOKKED)
	 	 p.sms_readyairboost = 0
		 p.mo.atomdiveusebuffer = 0
	 	 p.sms_jumphold = 10
		 	if p.hometrickanim
			p.hometrickanim = false
			p.mo.state = S_PLAY_ROLL
			end
		 end
	   if p.smsanaloghome and not (p.pflags & PF_ANALOGMODE) and not p.homecamfly
			if (p.cmd.forwardmove > 0) and not (p.cmd.sidemove)
			return false
			elseif (p.cmd.forwardmove > 0) and (p.cmd.sidemove < 0)
			p.mo.angle = $+ANGLE_45-ANG2-ANG2-ANG2
			p.drawangle = p.mo.angle
			elseif (p.cmd.forwardmove > 0) and (p.cmd.sidemove > 0)
			p.mo.angle = $-ANGLE_45+ANG2+ANG2+ANG2
			p.drawangle = p.mo.angle
			elseif not (p.cmd.forwardmove) and (p.cmd.sidemove > 0)
			p.mo.angle = $-ANGLE_90+ANG15
			p.drawangle = p.mo.angle
			p.homecamfly = 7
			elseif not (p.cmd.forwardmove) and (p.cmd.sidemove < 0)
			p.mo.angle = $+ANGLE_90-ANG15
			p.drawangle = p.mo.angle
			p.homecamfly = 7
			elseif (p.cmd.forwardmove < 0) and (p.cmd.sidemove < 0)
			p.mo.angle = $+ANGLE_135-ANG15
			p.drawangle = p.mo.angle
			p.homecamfly = 14
			elseif (p.cmd.forwardmove < 0) and (p.cmd.sidemove > 0)
			p.mo.angle = $-ANGLE_135+ANG15
			p.drawangle = p.mo.angle
			p.homecamfly = 14
			elseif (p.cmd.forwardmove < 0) and not (p.cmd.sidemove)
			p.mo.angle = $-ANGLE_180
			p.drawangle = p.mo.angle
			p.homecamfly = 11
			end
			p.pflags = $ & ~PF_JUMPDOWN
			p.cmd.buttons = $ & ~BT_JUMP
			if not p.homecamfly			
			p.homecamfly = 3
			end
			return true
		end
	 end
	end
end)

addHook("ShieldSpecial", function(p)
	if p.mysticsuper and leveltime //Simple and clean.
	return true
	end
end)

//Now you can play as Toilet Paper and SMS on the run from hoarders! Okay, okay, TP stands for True Player in this case.
//SMS is actually quite a useful partner. Good at fighting, giving you a boost, powersharing, and can open inaccessible areas for you

addHook("BotTiccmd", function(p, cmd)
if not (players[0] and players[0].valid and players[0].mo)
return
end
local tp = players[0]
if (tp.powers[pw_carry] == CR_PLAYER) and (tp.cmd.buttons & BT_CUSTOM3)
and p.bot == 1 and p.powers[pw_tailsfly] and (tp.mo and tp.mo.skin == "sms")
	cmd.forwardmove = tp.cmd.forwardmove
	if not (tp.transformdown and tp.transformdown > 2)
	cmd.buttons = $|BT_CUSTOM3
	end
	return
end
if not (p.mo and p.mo.skin == "sms" and p.bot == 1)
return
end
local s = p.mo
local tp = players[0]
	if s
		if p.powers[pw_shield]
			if (tp.powers[pw_shield] == SH_PINK or tp.powers[pw_shield] == SH_PITY or tp.powers[pw_shield] == 0) 
			and not (tp.powers[pw_shield] == SH_PINK and p.powers[pw_shield] == SH_PINK)
			tp.powers[pw_shield] = p.powers[pw_shield]
			P_SpawnShieldOrb(tp)
			P_FlashPal(tp, PAL_MIXUP, 4)
			CONS_Printf(tp, "\x83"+"SMS gave you his shield!")
			p.powers[pw_shield] = 0
			end
		end
		if not tp.powers[pw_invulnerability] and p.powers[pw_invulnerability] and (p.powers[pw_invulnerability] > 95)
		tp.powers[pw_invulnerability] = p.powers[pw_invulnerability]
		P_FlashPal(tp, PAL_MIXUP, 4)
		CONS_Printf(tp, "\x83"+"SMS is sharing his invulnerability powers!")
		end
		if not tp.powers[pw_sneakers] and p.powers[pw_sneakers] and (p.powers[pw_sneakers] > 95)
		tp.powers[pw_sneakers] = p.powers[pw_sneakers]
		P_FlashPal(tp, PAL_MIXUP, 4)
		CONS_Printf(tp, "\x83"+"SMS is sharing his sneaker powerup")
		end
		if s.smsbothomingspam
			if p.hometrickanim and (s.smsbothomingspam < 5)
			s.smsbothomingspam = 19
			else
			s.smsbothomingspam = $-1
			end
		cmd.buttons = $|BT_USE|BT_CUSTOM1
		cmd.forwardmove = 22
		  if not p.homing
			if (s.smsbothomingspam > 29)
			cmd.buttons = $|BT_JUMP
				if P_IsObjectOnGround(s)
				s.smsbothomingspam = 29
				end
			elseif (s.smsbothomingspam % 6 == 0)
			cmd.buttons = $|BT_JUMP
			else
			cmd.buttons = $ & ~BT_JUMP
			end

			searchBlockmap("objects",function (s,mo)
				if not (mo and mo.valid and mo.health)
				return true
				elseif (mo.flags & (MF_BOSS|MF_ENEMY))
				and P_CheckSight(s,mo) and not (mo.z > s.z+s.height)
					s.angle = R_PointToAngle2(s.x, s.y, mo.x, mo.y)
					return true
				end
		  	end,s, s.x-600*FRACUNIT,s.x+600*FRACUNIT, s.y-600*FRACUNIT,s.y+600*FRACUNIT)			
			
		  end
		return true
		end
		
		if p.smspickup and (tp.cmd.buttons & BT_TOSSFLAG)
			cmd.buttons = $|BT_TOSSFLAG
			s.smsbottf = 0
		return true
		end
		if (tp.cmd.buttons & BT_TOSSFLAG)
		or (tp.pflags & PF_STARTDASH) and (tp.cmd.buttons & BT_JUMP)
		or (tp.cmd.buttons & BT_USE) and (tp.pflags & PF_JUMPED) and (tp.spinhold != nil) and (tp.spinhold < 2)
		s.smsbottf = 0
			if (P_IsObjectOnGround(s) or (p.pflags & PF_JUMPED) or p.hometrickanim or (s.state == S_PLAY_SPRING) or (s.state == S_SMS_ADVFALL1) or (s.state == S_SMS_ADVFALL2))
			and not p.footsweepanim //Attack in this direction
				cmd.buttons = $|BT_CUSTOM1|BT_JUMP|BT_USE
				cmd.forwardmove = 25
				cmd.sidemove = 0
				if (p.pflags & PF_JUMPED) or p.hometrickanim
				s.smsbothomingspam = 29
				else
				s.smsbothomingspam = 40
				end
				return true
			end		
		end
		if (tp.cmd.buttons & BT_CUSTOM1)
		cmd.buttons = $|BT_CUSTOM1
		s.smsbottf = 0
		end
		if (tp.cmd.buttons & BT_CUSTOM2)
		cmd.buttons = $|BT_CUSTOM2
		s.smsbottf = 0
			if P_IsObjectOnGround(s) or p.footsweepanim
				if not (p.sms_boostlevel and p.sms_boostlevel > 64)
				cmd.forwardmove = 0
				cmd.sidemove = 0
				end
				
				searchBlockmap("objects",function (s,mo)
					if mo and mo.valid and (mo.flags & (MF_BOSS|MF_ENEMY)) and mo.health
					and P_CheckSight(s,mo) and not (mo.z > s.z+(200*FRACUNIT*P_MobjFlip(s)))
						p.botsmst = mo
						p.sweepangle = R_PointToAngle2(s.x, s.y, mo.x, mo.y)
						s.angle = R_PointToAngle2(s.x, s.y, mo.x, mo.y)
						return true
					end
		  		end,s, s.x-900*FRACUNIT,s.x+900*FRACUNIT, s.y-900*FRACUNIT,s.y+900*FRACUNIT)	
		  		if p.botsmst
				p.botsmst = nil
				else
				s.angle = tp.mo.angle
				p.sweepangle = tp.mo.angle
				p.botsmst = nil				
				end
			p.sweepspeed = 65*FRACUNIT
			end
		end
		if (tp.cmd.buttons & BT_WEAPONPREV)			
		cmd.buttons = $|tp.cmd.buttons & ~BT_CUSTOM3 & ~BT_TOSSFLAG
		s.smsbottf = 0
		end	
		if (FixedHypot(s.x-tp.mo.x, s.y-tp.mo.y) < 200*FRACUNIT) and not p.smspickup
			if ((tp.cmd.buttons & BT_CUSTOM3) or tp.readyforpowershare) and P_IsObjectOnGround(s)
			cmd.buttons = $|BT_CUSTOM3
			cmd.forwardmove = 0
			cmd.sidemove = 0
			s.smsbottf = 0
			elseif s.smsbottf and (s.smsbottf > 45)
			s.angle = R_PointToAngle2(s.x, s.y, tp.mo.x, tp.mo.y)
			p.drawangle = R_PointToAngle2(s.x, s.y, tp.mo.x, tp.mo.y)
			cmd.buttons = $|BT_TOSSFLAG
			cmd.forwardmove = 0
			cmd.sidemove = 0
				if (tp.cmd.buttons & BT_JUMP) and (tp.pflags & PF_JUMPED)
				cmd.buttons = $|BT_JUMP & ~BT_TOSSFLAG	
				s.smsbottf = 0
				end
			end
			return true 
		end
		if p.footsweepanim
			cmd.forwardmove = 0
			cmd.sidemove = 0	
			return true
		end
	end
end)