--===================================SUPER MOVES===================================================
--Alot of the flashier and more unique moves are located here. The Atom Dive, Comet Haymaker, 
--but the ability to pick up items too.
--=================================================================================================

//When the time comes....DODGE!!
//SMS' dodgeroll might come in use, but you still have to be ready to time it right!

addHook("MobjThinker", function(s) if not s.player return end local p = s.player
	if p.cmphwarning
		p.cmphwarning = $-1
		if not P_IsObjectOnGround(s)
		and not (p.panim == PA_ROLL)
			s.state = S_PLAY_ROLL
		end
		if (p.cmd.buttons & BT_JUMP)
		and (p.cmd.buttons & BT_SPIN)
		and not (p.spinhold > 8)
		and not P_PlayerInPain(p)
		and not p.cmphdodge
		
			P_SetObjectMomZ(s, 12<<16)
			P_SpawnMobj(s.x, s.y, s.z, MT_EXPLODE)
			p.cmphdodge = 55
			
			if p.smpawncher
				print("\x83"+p.name+" dodged "+p.smpawncher.name+"'s haymaker.")
				p.smpawncher = nil
			end
			s.state = S_PLAY_ROLL
			p.pflags = $|PF_JUMPED & ~PF_THOKKED
			p.secondjump = 0
			p.powers[pw_nocontrol] = $+20
			S_StartSound(s, sfx_s3kab)
			S_StartSound(s, sfx_s3kb6)
			S_StartSound(s, sfx_s3k76)
			p.powers[pw_flashing] = max($,35)
			

			if (p.cmd.forwardmove > 0)
				P_InstaThrust(s, s.angle, 45*s.scale)
			elseif (p.cmd.sidemove > 0)
				P_InstaThrust(s, s.angle+ANGLE_90, -45*s.scale)
			elseif (p.cmd.sidemove <= 0)
				P_InstaThrust(s, s.angle-ANGLE_90, -45*s.scale)
			else
				P_InstaThrust(s, s.angle, -45*s.scale)
			end
		end	
	end
	if p.hmsbpunch
		s.flags = $|MF_BOUNCE
		s.angle = $+ANG30
		if not (P_PlayerInPain(p))
			p.hmsbpunch = false
			s.flags = $ & ~MF_BOUNCE
		end
	end
	if p.cmphdodge
		local ghs = P_SpawnGhostMobj(s)
		ghs.rollangle = s.rollangle
		p.cmphdodge = $-1
	end
	if p.fusrodah
		p.fusrodah = max($+1,0)
		if (s.state != S_PLAY_PAIN)
			p.fusrodah = 0
		end
	end	
	
	if (s.skin != "sms") return end --SMS-only from here on out!	
	
	if s.atomdiveheld
		s.atomdiveheld = $-1
	elseif p.smsdivefloat
		if (p.cmd.buttons & (BT_TOSSFLAG|BT_WEAPONPREV|BT_WEAPONNEXT))
			p.smsdivefloat = max($-1, 0)
		else
			p.smsdivefloat = 0
		end
	end
	if p.smsatomicdivefail
		p.powers[pw_nocontrol] = $+1
		p.smsatomicdivefail = $-1
	end	
	if s.sdodgecd
		s.sdodgecd = $-1
		if not s.sdodgecd and s.sdodgelvl
			s.sdodgelvl = 0
		end
	end
	if s.smpkclosest
		s.smpkclosest = nil
	end
			
	--========================================================================
	//Remember those flying rings jumps from Sonic X? ...no?
	//Well, here's the RING BURST. It consumes a whole load of rings,
	//but holy crap, it is ridiculously powerful
	--========================================================================

	if not p.hypermysticsonic --Next 2 abilities are SMS-only
	
		if (p.sms_ringburstready or p.sms_ringburst or p.sms_ringburstfly)
		and (p.pflags & PF_DIRECTIONCHAR) //Let's not have directionchar screw us...
			p.drawangle = s.angle
		end

		if p.sms_ringburstfly --We're currently using the Ring Burst to fly!
	
			p.sms_ringburstfalltimer = $+1			
			SMS_RingBurstFlight(s, p) --Main flight behaviour!			
			p.sms_ringburstready = 0

			if p.sms_ringburstdrain
				p.sms_ringburstdrain = $+1
				if (p.sms_ringburstdrain > 4) --Reset!
					p.sms_ringburstdrain = 1
				elseif (p.sms_ringburstdrain == 2) --Drain ring!
					if p.rings 
						P_GivePlayerRings(p, -1)
					end
				end
			end
	
			if s.waitforforward
				if not (p.cmd.forwardmove > 40)
					s.waitforforward = false
				end
			end	
	
		else --NOT ring Burst flying yet, so let's prep!
	
			if p.sms_ringburstready
				if (p.rings < 10) or P_PlayerInPain(p)
					p.sms_ringburstready = 0
				else
					p.sms_ringburstready = $-1
				end
			end
			if s.sms_sideroll
				if (s.state == S_SMS_SIDEDODGE1)
					if (s.tics > 4)
						s.rollangle = $+FixedAngle(6<<16)*s.sms_sideroll
					else
						s.rollangle = $+FixedAngle(20<<16)*s.sms_sideroll
					end
				else
					s.sms_sideroll = 0
					if not s.airboostroll
						s.rollangle = 0
					end
				end
			end
			if s.truelsmsat --Fake analog stat.
			s.truelsmsat = $-1
				if (p.pflags & PF_JUMPED)
					s.truelsmsat = 0
				end
			end		
			--Perform SMS' dodge manuevre?
			if p.sms_dodging
				SMS_Dodging(s, p) --Currently dodging!
			elseif SMS_DodgeInput(s, p) --Did input?
				SMS_SwiftDodge(s, p) --Then Swift Dodge!
			else --Ring Burst check then!
				if p.sms_ringburst
					p.sms_ringburst = $-1
				end			
				if (p.rings > 9) --if NOT flying and we have the rings to activate this power, then...
				and not SMS_Locked(s, p, true) 
	
					if s.sms_tapnothold2
						s.sms_tapnothold2 = $-1
					end	
					SMS_RingBurstPrep(s, p)
				end
			end
		end
	end
	--========================================================================
	//One of SMS' supermoves, the Comet Haymaker. When you reach incredible
	//speeds, turn your kinetic energy into one deadly punch, sending
	//your enemies flying into the walls like comets.
	--========================================================================

	--Aftereffects after a confirmed haymaker landed.
		
	if s.cmphlanded
			if (s.cmphlanded > 1)
				if (s.cmphlanded > 4)
					s.angle = p.sweepangle
					p.drawangle = p.sweepangle
					p.powers[pw_noautobrake] = max($, 4)
				end
				p.sms_comethaymaker = 0 --We're done chasing.
				s.eflags = $ & ~MFE_JUSTHITFLOOR
				p.charflags = $|SF_NOSKID & ~SF_RUNONWATER
				p.sms_boostlevel = 0
				s.sms_boostloss = 0
				
				--Remain in the correct animation, pls.	
				local hstate = SMSHayMakerState(p, 1)
				if (s.state != hstate)
				and (p.panim == PA_IDLE or p.panim == PA_WALK or p.panim == PA_FALL)
				and P_IsObjectOnGround(s)
				and not (p.pflags & (PF_JUMPED|PF_SPINNING|PF_STARTJUMP|PF_THOKKED|PF_STARTDASH|PF_SLIDING))
				and not p.powers[pw_carry]
				and (p.speed < 33*s.scale)
					s.state = hstate
					s.eflags = $ & ~MFE_JUSTHITFLOOR
					s.tics = s.cmphlanded
					s.anim_duration = s.cmphlanded
					s.momx = $/2
					s.momy = $/2
				end
			else
				p.charflags = $ & ~SF_NOSKID
				if P_IsObjectOnGround(s) --Revert to a crouch.
				and (s.state == SMSHayMakerState(p, 1))
				and (p.speed < 32*s.scale)
					s.state = S_SMSTOSSREADY
				end
			end

		s.cmphlanded = $-1

	elseif p.sms_comethaymaker --We're chasing!
		
		s.rollangle = 0
		p.sms_comethaymaker = max($-1, 0)
		SMS_HayMakerChase(s, p)
	end

	--Haymaker input and conditions met?
	if SMS_HayMakerInput(s, p)
	
		if not SMS_NerfedMode(p) --Aim for enemies and bosses in most gamemodes!				
			local ANGLE = ((p.pflags & PF_ANALOGMODE) and (p.speed > 4*s.scale)) and R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy) or s.angle
			--Use object collision to determine enemy to punch!
			if p.hypermysticsonic --Far larger range.
				local ghs = P_SpawnMobj(
				s.x+FixedMul(1100<<16,cos(ANGLE)),
				s.y+FixedMul(1100<<16,sin(ANGLE)),
				s.z-1400<<16,
				MT_SMSECHECK)
				if ghs and ghs.valid
					ghs.cmphhms = true
					ghs.target = s
					ghs.height = 2800<<16
					ghs.radius = 1300<<16
				end
			else
				local ghs = P_SpawnMobj(
				s.x+FixedMul(570<<16,cos(ANGLE)),
				s.y+FixedMul(570<<16,sin(ANGLE)),
				s.z-600<<16,
				MT_SMSECHECK)
				if ghs and ghs.valid
					ghs.cmphsms = true
					ghs.target = s
					ghs.height = 1200<<16
					ghs.radius = 660<<16
				end
			end

			--Does our object's findings match our target?
			if (s.cmphtarget == s.target) and s.smshmcheck
			and s.target and s.target.valid --Got a target?
			
			local t = s.target
			local cancel = false
			
				--Range sanity checks.
				local maxrange = p.hypermysticsonic and 3400<<16 or 1640<<16
				if (FixedHypot(t.x-s.x, t.y-s.y) > maxrange)
				or t.fusrodah 
				or not s.target.health
					local cancel = true
					s.cmphtarget = nil
				end
			
			  if cancel != true --Ready?
			  
				s.smshmcheck = 0
				s.cmphclosest = nil
				s.cmphtarget = nil
				
				if (t.type == MT_METALSONIC_BATTLE) --Fuck you in particular.
					t.flags = $|MF_BOSS|MF_SHOOTABLE & ~MF_NOCLIPTHING & ~MF_NOCLIP
				elseif (t.type == MT_EGGGUARD) --Yeah? What shield?
					if t.tracer and t.tracer.valid
					and t.tracer.health and (t.tracer.type == MT_EGGSHIELD)
						t.tracer.state = S_NULL
						t.flags = $|MF_SHOOTABLE|MF_ENEMY
					end
				elseif (t.type == MT_MINUS) --Get out of the floor RIGHT now...
					t.state = S_MINUS_AERIAL1
					t.z = $+(20*t.scale*P_MobjFlip(t))
					P_SetObjectMomZ(t, 3<<16, true)
					t.flags = $|MF_SHOOTABLE|MF_ENEMY|MF_SPECIAL & ~MF_NOCLIPTHING
				end
				
				p.pflags = $ & ~PF_JUMPED & ~PF_SPINNING & ~PF_STARTDASH & ~PF_STARTJUMP
				P_HomingAttack(s, t) //Use the default homing attack code the first tic.
				p.sms_comethaymaker = 25
				s.HayMakerGFXTable = nil
				
				p.sms_ringburst = 0
				s.cmphlanded = 1
				p.cmd.forwardmove = max($,1)
				p.charflags = $|SF_NOSKID
				
				S_StopSoundByID(s, skins["sms"].soundsid[SKSSPIN])
				
				if not p.hypermysticsonic --SMS haymaker
				
					s.state = S_SMSCOMETHAYMAKER1
					s.momx = 0 
					s.momy = 0
					S_StopSoundByID(s, sfx_sarb)
					S_StopSoundByID(s, sfx_cmph) --Don't overlap these sounds.
					for i = 0,4
						S_StopSoundByID(s, (sfx_smsha1+i))
					end
					SMS_WallJumpGFX(s, true)
					SMS_DustLayers(s, true, s.angle)
					S_StartSound(s, sfx_cmph)
					S_StartSound(s, sfx_smsfx8)
					local ghs = SMS_SparkleFlash(s, 18*s.scale, 1)
					ghs.colorized = true
					ghs.color = SKINCOLOR_FLAME
					
					local DIST = FixedHypot(FixedHypot(s.x-t.x, s.y-t.y), s.z-t.z)
					if (DIST <= 300*s.scale) --Shift back a bit if you're able to.
						local ANGLE = R_PointToAngle2(s.x, s.y, t.x, t.y)
						for i = 1,8
							if not P_TryMove(s, s.x+FixedMul(-DIST*(s.scale/8), cos(ANGLE)), s.y+FixedMul(-51*(s.scale/8), sin(ANGLE)), true)
								break --
							end
						end
					end
					
				else --HMS haymaker!
					
					s.state = S_HMSCOMETHAYMAKER1  --Teleport into the enemy for an instant victory.
					
					local SUCCESS = false


					local HMSTRAILTABLE = {SKINCOLOR_SMS3R, SKINCOLOR_ORANGE, SKINCOLOR_RED, SKINCOLOR_RUBY, SKINCOLOR_BLUEBELL, SKINCOLOR_SKY, SKINCOLOR_SMS2R, SKINCOLOR_SMS3R, SKINCOLOR_ORANGE, SKINCOLOR_RED,SKINCOLOR_RUBY}
					local FIRSTCOLOR = 0
					for i = 0,4,2
						if i == 0
							local ghs = HMS_RollWaves(s, nil, 17, HMSTRAILTABLE[SMS_TimeFrame(7, 1)], FRACUNIT-11000, nil, s)
							ghs.frame = ($ & ~FF_TRANSMASK)|FF_TRANS30
							ghs.scalespeed = $+(FRACUNIT/9)
							ghs.tracer = nil
						else
							local ghs = HMS_RollWaves(s, nil, 17, HMSTRAILTABLE[SMS_TimeFrame(7, 1)+FIRSTCOLOR], FRACUNIT-11000) //,FRACUNIT-7000-(6900*i))
							ghs.tracer = nil
							ghs.frame = $+(FRACUNIT*i)
							ghs.sttroll = $*i
						end
						FIRSTCOLOR = $+1
					end
					
					local ghs = P_SpawnMobjFromMobj(s, 0,0,0,MT_THOK)							
					
					
					if (t.subsector != s.subsector) 
					and P_CheckPosition(s, t.x+FixedMul(-65*s.scale, cos(s.angle)), t.y+FixedMul(-65*s.scale, sin(s.angle)), t.z)
						P_MoveOrigin(s, t.x+FixedMul(-65*s.scale, cos(s.angle)), t.y+FixedMul(-65*s.scale, sin(s.angle)), t.z )
						SUCCESS = true
					elseif (t.z < s.floorz) or (t.z > s.ceilingz) 
						if P_TryMove(s, t.x+FixedMul(-65*s.scale, cos(s.angle)), t.y+FixedMul(-65*s.scale, sin(s.angle)), true)
							s.z = t.z --Order matters.
							SUCCESS = true
						end
					else
						s.z = t.z
						if P_TryMove(s, t.x+FixedMul(-65*s.scale, cos(s.angle)), t.y+FixedMul(-65*s.scale, sin(s.angle)), true)
							SUCCESS = true
						end
					end
					if SUCCESS
						for z in players.iterate
							if z.mo
								if z == p 
								or (FixedHypot(s.x-z.mo.x, s.y-z.mo.y) <= 400*s.scale)
									P_FlashPal(z, 0, 2)
								end
							end
						end
						S_StartSound(s, sfx_nerf)
						if ghs and ghs.valid
							SMS_LightningStrike(ghs, SKINCOLOR_RED, R)
								
							ghs.sprite = s.sprite
							ghs.skin = s.skin
							ghs.sprite2 = s.sprite2
							ghs.frame = (s.frame & ~FF_TRANSMASK)|FF_TRANS80
							ghs.scale = s.scale*5/4
							ghs.spinspecial = true
							ghs.renderflags = RF_SEMIBRIGHT
							ghs.blendmode = AST_ADD
							ghs.color = s.color
							ghs.colorized = true
							ghs.fuse = 14 ghs.tics = 99
							ghs.scalespeed = FRACUNIT/14
							ghs.destscale = 1
							SMS_DrawTrail(s, ghs) --Now draw the trail.
								
							local ths = SMS_LightClash(ghs, SKINCOLOR_CRIMSON, ghs)
							ths.angle = s.angle+ANGLE_90
							ths.frame = $+FF_TRANS20
							ths.scalespeed = $*2
							ths.fuse = $-4
							ths.tracer = nil
								
							ths = SMS_FollowCircle(ghs, SKINCOLOR_SUPERSKY2)
							ths.frame = $+FF_TRANS20
						end
						SMS_AngledLightning(s, SKINCOLOR_SMS3R, 53, 6-(SMS_Graphix(s)*2))
					end
					s.momx = 0 
					s.momy = 0
					
				end
				s.rollangle = 0
				s.HayMakerRoll = -(ANG1*12)
				SMS_HayMakerChase(s, p)	--Give chase right away!
			  end
			end
			
	   elseif not G_PlatformGametype() or s.battlemodsms
	   
	 	  --Target players in match gamemodes!
	   		for z in players.iterate
		 		if z.mo
				and not (s == z.mo)
				and not (FixedHypot(s.x-z.mo.x, s.y-z.mo.y) < (750<<16)) --Distance checks.
				and not (s.z > z.mo.z+475<<16)
		 		and not (s.z < z.mo.z-435<<16)
		 		and not (p.ctfteam and p.ctfteam == z.ctfteam)
				and P_CheckSight(s, z.mo)
				and not z.powers[pw_flashing]
				
				s.target = z.mo
		 		p.sms_flamedelay = 36
				
				local t = s.target
				
					if t.valid 
					
						p.sms_ringburst = 0
						p.pflags = $ & ~PF_JUMPED & ~PF_SPINNING
						
						--Oops, they've been attacked recently. Give them extra time.
						if t.player.cmphspamreduce
						and not p.hypermysticsonic
						
							s.cmphdelayjump = 19
							p.sms_comethaymaker = 0
							p.sms_flamedelay = 55
							s.momx = $/8
							s.momy = $/8
							P_SetObjectMomZ(s, 44<<16)
							s.state = S_PLAY_ROLL
							p.powers[pw_nocontrol] = 2
							S_StartSound(s, sfx_s255)
							S_StartSound(s, sfx_s255)
							
							local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_BURSTLIGHT)
							ghs.color = s.color
							ghs.blendmode = AST_ADD
						
						else
						
							P_HomingAttack(s, t) //Home into our chosen player.
							S_StartSound(s, sfx_cmph)
							p.sms_comethaymaker = 36
							SMS_WallJumpGFX(s, true)
							SMS_HayMakerChase(s, p)
							SMS_DustLayers(s, true, s.angle)
						
							if not p.hypermysticsonic
								s.state = S_SMSCOMETHAYMAKER1
								t.player.cmphspamreduce = 900
								if s.battlemodsms and not p.powers[pw_flashing]
									p.powers[pw_flashing] = 50
									s.flags2 = MF2_DONTDRAW
								end
							else
								s.state = S_HMSCOMETHAYMAKER1
							end
						end
						
						z.smpawncher = p //Pre-emptive warning
						z.cmphwarning = 8 --When this is active, shows a warning on the target's HUD.
					end
		  		end
	     	end
		end
	end	
		
	--AoE effect from being in the punching state.
	if (s.state == SMSHayMakerState(p, 1))
		if s.HayMakerRoll != nil
			if (s.HayMakerRoll < -1)
				s.HayMakerRoll = -1
			else
				s.HayMakerRoll = $+1
				if (s.HayMakerRoll > 28)
					s.HayMakerRoll = 28
				end
				s.rollangle = FixedAngle(s.HayMakerRoll<<16)
			end
		end
		p.powers[pw_noautobrake] = max($, 5)
		s.cmphdelayjump = 0
		if (p.pflags & (PF_DIRECTIONCHAR|PF_ANALOGMODE))
	 		p.drawangle = s.angle
		end
		if not s.cmphlanded
		and s.target and s.target.valid 			
		local t = s.target
			s.momx,s.momy,s.momz = 0,0,0
	 		p.sms_comethaymaker = 0
		
			if SMS_NerfedMode(p)
			and (P_FaceStabCheckMeleeRange(s) or P_CheckSight(s, t))			
				if p.hypermysticsonic --HMS version
					if t.player.powers[pw_invulnerability]
						t.player.powers[pw_invulnerability] = 0  //No defense
						P_RestoreMusic(t.player)
					end
					if not s.battlemodsms --Pierce shields.
						P_RemoveShield(t.player)
					end							
					t.player.losstime = 2000
					P_FlashPal(t.player, PAL_MIXUP, 5)
					P_DamageMobj(t, s, s)
					P_SpawnMobjFromMobj(t, 0,0,0, MT_BURSTWAVE)
					P_InstaThrust(t, s.angle, 125*s.scale)
					S_StartSound(t, sfx_nerf)
					p.powers[pw_nocontrol] = 8
					s.cmphlanded = 14
					if t.health
						P_SetObjectMomZ(t, 12<<16)
						t.state = S_PLAY_PAIN
						t.player.hmsbpunch = true
					end
				elseif not (t.player and (t.player.cmphdodge or t.player.sms_dodging) ) and (s.tics == 10) --SMS version
					if not s.battlemodsms --Pierce shields.
						P_RemoveShield(t.player)
					end	
					P_FlashPal(t.player, PAL_MIXUP, 4)
					P_DamageMobj(t, s, s)
					P_InstaThrust(t, s.angle, 125*s.scale)
					S_StartSound(t, sfx_nerf)
					t.player.cmphspamreduce = 900
					s.cmphlanded = 14
					if not s.battlemodsms
						P_RemoveShield(t.player)
					end

					if t.health //I COULD stop momentum on dead people, but it's funny.
						P_SetObjectMomZ(t, 12<<16)
						t.state = S_PLAY_PAIN
					end
				end
		 	end
		end
			
	else --Not in HAYMAKER2 state.
	
		if s.HayMakerRoll
			if not p.sms_comethaymaker
				s.HayMakerRoll = nil
				s.rollangle = 0
			end
		end		
		if s.cmphdelayjump --What to do if players dodge us?
		
			s.cmphdelayjump = $-1
			P_SpawnGhostMobj(s)
			p.powers[pw_nocontrol] = max($, 2) --Stop our controls from fucking up while we home into our target
			
			if P_PlayerInPain(p)
				s.cmphdelayjump = 0
				s.target = nil
			elseif s.state != S_PLAY_ROLL
				s.state = S_PLAY_ROLL
			end
			
			if s.target and s.target.valid and s.target.player and s.target.health and (s.target != s)
			local t = s.target
				P_HomingAttack(s, t)
				s.momz = $*4/5
				A_FaceTarget(s)
				
				if s.cmphdelayjump == 1 //Enough stalling, chaaaarge!
				s.cmphdelayjump = 0
					p.pflags = $ & ~PF_JUMPED
					P_HomingAttack(s, t) //Home into our chosen player.
					S_StartSound(s, sfx_cmph)
					p.sms_comethaymaker = 36
					p.sms_ringburst = 0
					t.player.cmphspamreduce = 900
					if not p.hypermysticsonic
						s.state = S_SMSCOMETHAYMAKER1
						if s.battlemodsms and not p.powers[pw_flashing]
							p.powers[pw_flashing] = 50
							s.flags2 = $|MF2_DONTDRAW
						end
					else
						s.state = S_HMSCOMETHAYMAKER1
					end
				elseif (t.player.cmphdodge or t.player.sms_dodging) //They dodged already?!
				
					s.cmphdelayjump = 0
					p.sms_comethaymaker = 0
					P_HomingAttack(s, t)
					s.target = nil
					s.state = SMSHayMakerState(p, 1)
					
				elseif not (t.player.cmphwarning and t.player.cmphwarning > 1) //Give them a dodge prompt
				and not t.player.cmphdodge
				and not (t.player.ctfteam and (t.player.ctfteam == t.player.ctfteam))
				
					t.player.smpawncher = p
					t.player.cmphwarning = 3
					if t.player.powers[pw_tailsfly]
						t.state = S_PLAY_FALL
						t.player.powers[pw_tailsfly] = 0
						t.player.fly1 = 0
						t.player.secondjump = 0
					end			

				end
			else
				s.momz = $/3 //Oops, target stopped existing, cancel that ticket.
				s.cmphdelayjump = 0
				s.target = nil
			end
		end
	end

	//SMS' momentum is his greatest weapon to cause insane damage. 
	//In this move, the Atomic Dive, SMS charges downward with explosive power.
	//The more speed you pick up, the grander the devastation!
	//Use it wisely!
	local ATOMland = false
	if (s.state == S_SMS_ATOMLAND1) or (s.state == S_SMS_ATOMLAND2) or (s.state == S_HMS_ATOMLAND)
		ATOMland = true
	end

	if p.smsatomdivestun != nil --We're currently stunned, when should we cancel it?
		p.sms_flamedelay = max($,2)
		if not ATOMland
		and not (p.smsdivetimer and not p.hypermysticsonic)
		and not s.sdodgeoh
			p.smsatomdivestun = nil
		end
	end
	if ATOMland
	or p.smsdivetimer and not p.hypermysticsonic --HMS retains control during the Atom Dive!
	or s.sdodgeoh
		if ATOMland
			if not p.hypermysticsonic
				p.sms_flamedelay = max($,2)
			end
		--	p.powers[pw_nocontrol] = 2
			if not (s.SMS_ControlAlter and s.SMS_ControlAlter.buttons == 0) --Remove most controls here too.
				s.SMS_ControlAlter = {
				timer = 2,
				forwardmove = 0,
				sidemove = 0,
				removebuttons = (BT_JUMP|BT_SPIN|BT_CUSTOM1|BT_CUSTOM2|BT_CUSTOM3|BT_TOSSFLAG|BT_ATTACK|BT_WEAPONNEXT|BT_WEAPONPREV)
				}
			end	
		end
		if s.sdodgeoh
		and (P_IsObjectOnGround(s) or s.dodgespinslide)
		and not (p.sms_dodging and not P_IsObjectOnGround(s))
		and not (p.panim == PA_SPRING or p.panim == PA_PAIN or (s.state == S_SMS_SIDEDODGE1))
		and not p.powers[pw_carry]
			--We're currently sliding across the floor after a dodge, spinning in circles.
			if s.sliderollang == nil
				s.sliderollang = (p.pflags & PF_ANALOGMODE) and p.drawangle or s.angle
			end
			--Spin speed is based on sliding speed!
			if P_IsObjectOnGround(s) --Spin speed is based on sliding speed!
				p.drawangle = s.sliderollang-FixedAngle(p.speed)
				s.sliderollang = $-FixedAngle(p.speed)
				--Spawn dust and make sliding sound if we have any speed at all!
				if (p.speed > 4*s.scale)
					S_StartSound(s, sfx_s3k7e)
					for i = -1,1,2
						local ghs = P_SpawnMobj(
						s.x+FixedMul(24*s.scale*i, cos(p.drawangle+ANGLE_90)),
						s.y+FixedMul(24*s.scale*i, sin(p.drawangle+ANGLE_90)), s.z, MT_SPINDUST)
						ghs.frame = P_RandomRange(0,2)
					end
				end					
			else
				p.drawangle = s.sliderollang-FixedAngle(p.speed/2) --Spin slower in midair!
				s.sliderollang = $-FixedAngle(p.speed/2)
			end
			if (s.eflags & MFE_JUSTHITFLOOR) and not s.SMS_squashtable
				s.spritexscale = FRACUNIT+7400
				s.spriteyscale = FRACUNIT-6100
				s.SMS_squashtable = {timer = 4, Xspeed = 3500, Yspeed = 2500, ground = true}
			end
			s.state = S_SMS_DODGELAND
			if (p.speed > 3*s.scale) --Allow minor control over trajectory.
				s.SMS_ControlAlter = {
				timer = 2,
				maxforwardmove = 10,
				minforwardmove = -10,
				maxsidemove = 10,
				minsidemove = -10,
				removebuttons = 0,--Remove all buttons!
				}
			else
				p.powers[pw_nocontrol] = 2				
			end
		end
		if p.smsatomdivestun == nil
			p.smsatomdivestun = s.angle
		elseif not s.sdodgeoh
			s.angle = p.smsatomdivestun
		end
	end
	if s.hmspowerbombcam
		s.hmspowerbombcam = $-1
		if not P_IsObjectOnGround(s)
		or (p.pflags & (PF_SPINNING|PF_STARTDASH|PF_SLIDING|PF_THOKKED|PF_STARTJUMP))
			s.hmspowerbombcam = 0
		else
			p.camerascale =  (p.hypermysticsonic) and 24<<16 or 3<<16 --Explosion cam.
			s.bhlcamtimer = 2
		end
	end
	 --Accounts for both SMS and HMS! Return 1 if SMS, 2 if HMS, 0 if failed.
	local ADinput = SMS_AtomDiveInput(s, p)
	if ADinput
		SMS_AtomDiveStart(s, p)	 --Do appropriate style AtomDive!
	end
	if p.smsdivetimer or p.smsdivefloat or p.smsatomicdivefail or (ADinput == 2)
		SMS_AtomDiveTransition(s, p) --We're moving into the Atom Dive state! (Probably!)
		if (s.state == S_SMS_ATOMLAND1) or (s.state == S_SMS_ATOMLAND2) or (s.state == S_HMS_ATOMLAND)
			s.SMS_ControlAlter = {
			timer = 2,
			forwardmove = 0,
			sidemove = 0
			}
		end
		
		if (s.state == S_SMS_ADVFALL1) or (s.state == S_SMS_ADVFALL2)
		or s.dcadsms
			s.state = S_PLAY_ROLL --Swap to correct animation.
			p.panim = PA_ROLL
			s.eflags = $ & ~MFE_JUSTHITFLOOR
			if not s.dcadsms 
				s.dcadsms = true
			else
				s.dcadsms = false
			end

		else --Cancel conditions!

			if not ((p.panim == PA_ROLL) or p.hypermysticsonic)
			and not ((s.state == S_SMS_ATOMDIVE) or (p.panim == PA_ROLL) or (p.panim == PA_FALL))
			and not (s.eflags & MFE_JUSTHITFLOOR)
				p.smsdivetimer = 0 p.smsdivefloat = 0 p.smsdivedelay = 0
				p.smsatomicdivefail = 0 s.smsdropdash = false		
			elseif (P_IsObjectOnGround(s) and not (s.eflags & MFE_JUSTHITFLOOR) and not (s.momz*P_MobjFlip(s) > 0))
			or ((s.state == S_PLAY_PAIN) or (s.eflags & MFE_UNDERWATER) or not s.health) and not p.hypermysticsonic
			or p.powers[pw_carry]
			or A_HMSCheckDeathPit(s)
				p.smsdivetimer = 0 p.smsdivefloat = 0 p.smsdivedelay = 0
				p.smsatomicdivefail = 0 s.smsdropdash = false
			end
		end
		--We're in the downwards flinging diving phase! From an Atom Dive, do we do a Drop Dash Landing or an explosive impact?
		if p.smsdivetimer
			if not p.smsdivedelay
				p.smsdivetimer = $+1
				if p.hypermysticsonic
				and not (p.smsdivetimer == 36 or p.smsdivetimer == 57)
					if (s.z > s.ceilingz-600*s.scale)
						p.smsdivetimer = $+1
					end
					if (s.z > s.ceilingz-300*s.scale)
					and not (p.smsdivetimer == 36 or p.smsdivetimer == 57)
						p.smsdivetimer = $+1
					end
				end
			end			
			if s.smsdropdash --Landing on the ground with the dropdash flag? Do a dropdash!
			and P_IsObjectOnGround(s)
				SMSDropDash(s, p)	
			else --No dropdash landing? Then we're still atom diving!
	  	 		SMSatomdiving(s, p)	--Execute code here!
			end
		end
	else
		if p.atomdiveaim
			if (s.state == S_SMS_ATOMDIVE)
				SMS_AtomDiveFloat(s, p, true)
			end
			p.atomdiveaim = false
			p.smsdivedelay = 0
			p.atomdivetargetspin = 0
			p.aiming = 0 //Revert cam when not in atomdive state.
		end

		//If NOT atomdiving, do the remaining misc SMS code!	
		if p.sms_autoboosthold  --Remove autoboosthold
			if (p.cmd.buttons & BT_CUSTOM1) or p.sms_dodging or p.footsweepanim
			or (p.hypermysticsonic and ((s.hms_jumprisen or s.hmsroflstomped) or ((p.speed < 15*s.scale) and abs(p.cmd.sidemove) < 5 and abs(p.cmd.forwardmove) < 5)))
			or SMS_Locked(s, p)
			
				p.sms_autoboosthold = (tonumber(p.sms_autoboosthold) != nil) and max($-2,0) or 0
			
			elseif P_IsObjectOnGround(s) and not p.sms_ringburst
			
				if p.skidtime
					s.SMS_LoseC1Hold = s.SMS_LoseC1Hold and $+3 or 3
				elseif (abs(p.cmd.sidemove) < 4 and abs(p.cmd.forwardmove) < 4)
					s.SMS_LoseC1Hold = s.SMS_LoseC1Hold and $+1 or 1		
				else
					s.SMS_LoseC1Hold = 0
				end
				if (s.SMS_LoseC1Hold > 6)
					p.sms_autoboosthold = (tonumber(p.sms_autoboosthold) != nil) and max($-2,0) or 0
				end
			end
		end	
		SMSpickup(s, p) --SMS can pick up items and players!			
	end
	if s.sms_lastboost != nil
		if s.sms_boostplustimer
			s.sms_boostplustimer = $-1
			if not s.sms_boostplustimer
				s.sms_boostplus = nil
			end
		end
		if not (p.sms_boostlevel > 94)
			if p.sms_boostlevel-s.sms_lastboost != 0
				s.sms_boostplus = p.sms_boostlevel-s.sms_lastboost
				s.sms_boostplustimer = 9
			end
		end
	end
	s.sms_lastboost = p.sms_boostlevel		
	if s.SMS_WJauto
		s.SMS_WJauto = $-1
		if P_IsObjectOnGround(s)
			s.SMS_WJauto = 0
			SMS_WallJumpDelete(s, true)
		end	
	end
end, MT_PLAYER)

//Does our punch radius collide with an enemy? Send them flying!
--CMPHcollide. Cmphcollission. CmphRadiusCollide.
local function CMPHrad(s, v)
	if not (v and v.valid and s.valid)
		return false
	elseif ((v.z > s.z+s.height) or (v.z+v.height < s.z-s.height)) --Height checks!
	or v.fusrodah --Already hit them.
	or s.bkhl 
	or (v.info.mass == 2006)
	or (v.trackerspawn and v.trackerspawn.valid)
		return false --
	else
		SMS_AssignPunchTracker(s, v) return false --
	end
end
addHook("MobjCollide", CMPHrad, MT_CMPHRADIUS)
addHook("MobjMoveCollide", CMPHrad, MT_CMPHRADIUS)

addHook("MobjThinker", function(s)
	if s.cmphflung
		s.cmphflung = $-1
		if s.cmphflung == 6	
			P_Thrust(s, s.angle, 125*s.scale)
		end
	end
end, MT_FLINGRING)

--S is the tracker. T is the target being hurt.
local function ResetThrowValues(t)
	if t and t.valid
		if t.smspickupflags != nil
			t.flags = t.smspickupflags
			t.smspickupflags = nil
		end	
		t.rollangle = 0
	end
end
local function ThrowDamage(s,t, SPECIALTARGET)
	if t and t.valid
		ResetThrowValues(t)
		if t.health or (t.flags & MF_SHOOTABLE)
			local SMS,HMS = s.smsthrowog,nil
			if s.hmsthrow and s.hmsthrowog and s.hmsthrowog.valid
				HMS = s.hmsthrowog
			end
			if not ((t.flags & MF_MONITOR) or t.info.deathstate == S_BOX_POP1)
				P_KillMobj(t, s, (SPECIALTARGET) and SPECIALTARGET or (HMS) and HMS or SMS)
			end
		end
	end
end

--Thrown object tracker. (Not the haymaker's tracker, that's CMPHTRACKER!)
--NOTE: ...fuck, this code is ESPECIALLY a mess, I'm not gonna be able to fix this one for 3.0....
addHook("MobjThinker", function(s)
	if not (s.target and s.target.valid) s.state = S_NULL return end --
	local t = s.target
	
	if s.CDbounce
		s.CDbounce = $-1
	end
	
	if s.cdtracker //Cooldown tracker
		if t.cmphttimer
			t.cmphttimer = $-1
		else
			ResetThrowValues(t)
			t.cmphttimer = nil
			s.state = S_NULL return --
		end
		return --
		
	//Monitor thrown tracker
	elseif s.throwntracker and s.ogsms //For thrown monitors.
		if t.valid and t.health and s.ogsms and s.ogsms.valid
			if P_IsObjectOnGround(t) and not (t.momz*P_MobjFlip(t) > 0)
				t.rollangle = 0
				t.momx,t.momy = 0,0
				t.flags = $|MF_MONITOR|MF_SHOOTABLE & ~(MF_NOCLIPTHING|MF_NOGRAVITY)
				s.state = S_NULL return --
			end
		else
			s.state = S_NULL return --
		end
		
	//SMS throwing	
	
	elseif s.smsthrow and s.smsthrowaim != nil and s.smsthrowang != nil and t.valid and s.smsthrowog and not t.SMS_lemmego
	
		s.smsthrow = $+1
		if t.cmphttimer == nil or t.cmphttimer
			if not (t.cttt and t.cttt.valid and t.cttt.health == 3)
				t.cttt = P_SpawnMobjFromMobj(t, 0,0,0, MT_SMSTHROWTRACKER)
				t.cttt.cdtracker = true
				t.cttt.target = t
				t.cttt.health = 3
			end
			t.cmphttimer = 5 //Generous emergency timer.
		end
		if not s.smsthrowdecideroll
			s.smsthrowdecideroll = (SMSLocalRNG(-12, 12,s) or 4)<<16
		end
		
		s.flags = $|MF_SOLID & ~MF_NOCLIP
		s.radius = t.radius*20/19
		s.height = t.height
		t.ibethrownbysmshelp = 2
		P_MoveOrigin(s, t.x, t.y, t.z)
		t.rollangle = $+FixedAngle(s.smsthrowdecideroll)
		
		local p = s
		
		s.momtotal = abs(t.momx)+abs(t.momy)
			
		if (s.smsthrow == 2)
			S_StartSound(s, sfx_mswing)
			S_StartSound(s, sfx_mswing)
			t.momz = FixedMul(FixedMul(45<<16, FRACUNIT), sin(s.smsthrowaim))
			if s.smsthrowguy and s.smsthrowguy.valid and s.smsthrowguy.health
				t.momx = FixedMul(FixedDiv(s.smsthrowguy.x-t.x, 450<<16), FixedDiv(132<<16, 3<<16/2))
				t.momy = FixedMul(FixedDiv(s.smsthrowguy.y-t.y, 450<<16), FixedDiv(132<<16, 3<<16/2))
				t.momz = FixedMul(FixedDiv(s.smsthrowguy.z-t.z, 450<<16), FixedDiv(132<<16, 3<<16/2))
			elseif s.smsthrowaim != nil and (((s.smsthrowaim/FRACUNIT)/2200) != 0) and not (s.smsthrowaim < 0)
				P_InstaThrust(t, s.smsthrowang, 70*t.scale/((s.smsthrowaim/FRACUNIT)/2200))
			else
				P_InstaThrust(t, s.smsthrowang, 70*t.scale)
			end
			if s.momtotalfirst == nil //Set our first known speed!
				s.momtotalfirst = abs(t.momx)+abs(t.momy)
			end
			t.angle = R_PointToAngle2(t.x, t.y, t.x+t.momx, t.y+t.momy)
			s.momtotal = abs(t.momx)+abs(t.momy)
		else
			if (s.smsthrow > 5) and (s.smsthrow < 22) 
				local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_THOK)
				ghs.state = S_SPINDUST1+P_RandomRange(0,2)
				ghs.colorized = true
				ghs.color = (SKINCOLOR_SUPERGOLD5+5)-(s.smsthrow*2)
				ghs.fuse = 32
				ghs.frame = ($ & FF_FRAMEMASK)|FF_TRANS60
				ghs.scale = (t.scale*s.smsthrow)/7
				ghs.scalespeed = FRACUNIT/25
				ghs.destscale = 99*FRACUNIT
				if (s.smsthrow < 13)
					ghs.flags2 = $|MF2_SHADOW
				end
			end		
		
		end
		if (t.type == MT_PLAYER)
			if not s.alreadyexploded and t.health
				t.state = S_PLAY_PAIN
				if t.player
					if not s.pdrawangleh
						s.pdrawangleh = P_RandomRange(-18, 18)<<16
					end
					if s.pdrawangle == nil
						s.pdrawangle = 0
					else
						t.player.drawangle = $+FixedAngle(s.pdrawangleh)
					end
					t.player.powers[pw_nocontrol] = 2
				end
			end
		end
		if s.homingbounce == 1
			P_SetObjectMomZ(t, 11<<16)
			t.momx,t.momy = 0,0
			if t.player
				t.z = $+(9*t.scale*P_MobjFlip(t))
				t.eflags = $ & ~MFE_JUSTHITFLOOR
				t.state = S_PLAY_PAIN
				t.player.powers[pw_flashing] = 90 
				A_SMSquake(t, 45<<16, 4, 900)
			end
			if s.smsthrowog and s.smsthrowog.mo
				A_SMSquake(s.smsthrowog.mo, 45<<16, 4, 100, true)
			end
			
			local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_BURSTWAVE)
			ghs.tracer = t
			ghs.renderflags = $|RF_SEMIBRIGHT|RF_NOCOLORMAPS
			ghs.spritexscale,ghs.spriteyscale = $*3/2,$*3/2
			
			ghs = P_SpawnMobjFromMobj(t,0,0,0, MT_EXPLODE)
			ghs = t.height/24 
			S_StartSound(t, sfx_s3k5d)
			P_NukeEnemies(t, s, 0)
			if s.smsthrowdecideroll
				s.smsthrowdecideroll = $*(SMSLocalRNG(-3,3,s) or -2)
			end
			s.alreadyexploded = true
			s.homingbounce = 2
			
		elseif not s.alreadyexploded --Wall collide!
		and (s.smsthrow > 3)
		and not P_IsObjectOnGround(t)
		
		and ( s.BlockedByLine
		or (t.z+t.momz >= t.ceilingz) and not (t.eflags & MFE_VERTICALFLIP)
		or ( (t.z+t.momz <= t.floorz) and (t.eflags & MFE_VERTICALFLIP) )
		
		or s.momtotal != nil and s.momtotalfirst and (s.momtotal < s.momtotalfirst/4) and t.type != MT_ROLLOUTROCK
		
		)
			
			s.BlockedByLine = nil
			local ghs = SMS_WallJumpGFX(t, "simple")
			ghs.color = SKINCOLOR_SILVER
			ghs.spriteyoffset = $-4<<16
			ghs.renderflags = $|RF_SEMIBRIGHT
			ghs.spriteyscale = $/2
			ghs.spritexscale = $/2
			
			local ghs = P_SpawnMobjFromMobj(t, 0, 0, 0, MT_EXPLODE)
			ghs.renderflags = $|RF_SEMIBRIGHT|RF_NOCOLORMAPS
			ghs.scale = t.height/24 
			s.alreadyexploded = true
			
			S_StartSound(t, sfx_s1bb) //Thud
			if (t.type == MT_PLAYER)
				t.state = S_PLAY_FALL
			end
			if t.player
				t.player.powers[pw_nocontrol] = 0
				t.player.powers[pw_flashing] = 16
			end
			if s.smsthrowdecideroll
				s.smsthrowdecideroll = ($/2)*-1
			end
			if (t.flags & (MF_ENEMY|MF_MISSILE)) and s.smsthrowog.mo and not (t.flags & MF_MONITOR)
				ThrowDamage(s,t, s.smsthrowog.mo)
				return --
			end
		end
		if (s.smsthrow > 3) and P_IsObjectOnGround(t)
		or (s.smsthrow > 450) //Stop at some point incase it gets stuck.
		or (s.eflags & MFE_GOOWATER) or (t.eflags & MFE_GOOWATER)	
			
			if P_IsObjectOnGround(t)
				if s.homingbounce and not s.alreadyexploded and not (s.smsthrow > 450)
					s.smsthrow = $+200 return --
				end
				S_StartSound(t, sfx_s1bb)
				A_SMSSTOMPSMOKE(t, 16, MT_SPINDUST)
			end
			ResetThrowValues(t)
			s.state = S_NULL return --
		end
		return -- //Cancel, you're only dedicated to the SMS throw.
		
		
	//HMS throwing

	elseif s.hmsthrow and s.hmsthrowaim != nil and s.hmsthrowang != nil and t.valid and s.hmsthrowog and not t.SMS_lemmego
		s.hmsthrow = $+1
		
		local p = s
	
		s.flags = $|MF_SOLID & ~MF_NOCLIP
		s.momx = (s.momx==0) and 8 or $
		s.radius = t.radius*20/19
		s.height = t.height
		P_MoveOrigin(s, t.x, t.y, t.z)
		t.ibethrownbysmshelp = 2
		
		if (t.type == MT_PLAYER) and not s.playeranimstart
			if t.player
				t.player.powers[pw_nocontrol] = 2
			end
			if not s.alreadyexploded and t.health
				t.state = S_PLAY_PAIN
				if t.player
					if not s.pdrawangleh
						s.pdrawangleh = 45<<16
					end
					if s.pdrawangle == nil
						s.pdrawangle = 0
					else
						t.player.drawangle = $+FixedAngle(s.pdrawangleh)
					end
				t.player.powers[pw_nocontrol] = 2
				end
			elseif s.alreadyexploded
				if t.player
					if (leveltime % 2 == 0)
						t.flags2 = $|MF2_DONTDRAW
					end
					t.player.powers[pw_nocontrol] = 2
				end
				t.state = ((t.skin == "sms") or (t.skin == "adventuresonic")) and S_PLAY_PAIN or S_PLAY_DEAD
				A_BossScream(s, 0, MT_SMOKE)
				s.playeranim = 70
				s.playeranimstart = true
			end
		end	
		
		if not s.alreadyexploded and (s.hmsthrow > 3)
		and 
		( P_IsObjectOnGround(t)
		or s.homingbounce
		or s.BlockedByLine
		or (t.z+t.momz >= t.ceilingz) and not (t.eflags & MFE_VERTICALFLIP)
		or (t.z+t.momz <= t.floorz) and (t.eflags & MFE_VERTICALFLIP)
		or s.momtotal != nil and s.momtotalfirst and (s.momtotal < s.momtotalfirst/4) and t.type != MT_ROLLOUTROCK
		)
			s.BlockedByLine = nil
			local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_EXPLODE)
			ghs.scale = t.height/24
			
			if not (s.hmsthrow >= 18) and s.hmsthrowog and s.hmsthrowog.mo
				P_FlashPal(p.hmsthrowog, 4, 4)
				
				local ghs = P_SpawnMobjFromMobj(t, 0, 0, 0, MT_BURSTWAVE)
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.spritexscale,ghs.spriteyscale = $*2,$*2
				
				s.homingbounce = 2
				if s.hmsthrowog and s.hmsthrowog.valid and s.hmsthrowog.mo
					local ghs = P_SpawnMobj(t.x, t.y, t.z, MT_SMSPOWERBOMB)
					ghs.target = s.hmsthrowog.mo
					ghs.dontbustmonitors = true
					
					local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_ATOMDIVEPOP)
    				ghs.tracer = s.hmsthrowog.mo
					ghs.dontbustmonitors = true
				end
				S_StartSound(t, sfx_spld)
				S_StartSound(t, sfx_pwbmb)
			
			elseif s.hmsthrowog and s.hmsthrowog.mo	and s.hmsthrowog.mo.valid
			
				P_FlashPal(s.hmsthrowog, 4, 10)
				
    			local ghs = P_SpawnMobjFromMobj(t, 0,0,0,MT_ATOMDIVEPOP)
    			ghs.scale = $*2
    			ghs.tracer = s.hmsthrowog.mo	
				ghs.dontbustmonitors = true
				
				local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_TNTDUST)
				ghs.fuse = 70
				ghs.destscale = $*50
				
				local ghs = P_SpawnMobj(t.x, t.y, t.z, MT_HMSPOWERBOMB) --Careful scaling this...
				ghs.thrownnucl = true
				ghs.dontbustmonitors = true
				ghs.target = s.hmsthrowog.mo
				P_NukeEnemies(t, s.hmsthrowog.mo, 1<<16)
				S_StartSound(t, sfx_spld)
				S_StartSound(t, sfx_nuexp)
				if t.player
					t.bhlcamtimer = 65
					t.hmspowerbombcam = 104
					t.player.camerascale = FRACUNIT*24				
				end
			end
			t.momx,t.momy,t.momz = 0,0,0
			
			s.alreadyexploded = true
			if (t.flags & (MF_ENEMY|MF_MISSILE)) and s.hmsthrowog.mo
				t.rollangle = 0
				ThrowDamage(s,t, s.hmsthrowog.mo)
			--	P_KillMobj(t, s.hmsthrowog.mo, s.hmsthrowog.mo) 
				return --
			end
		end
		
		if P_IsObjectOnGround(t) and (s.hmsthrow > 3) --We hit the ground or a wall! Now stop!
		or (s.hmsthrow > 150)
		or (s.eflags & (MFE_GOOWATER|MFE_UNDERWATER))
		or s.playeranim //Stop at some point incase it gets stuck.
			if P_IsObjectOnGround(t) and not s.didthrowlanding //and s.retmhtsfx and s.alreadyexploded and s.playeranim)
				A_SMSSTOMPSMOKE(t, 16, MT_SPINDUST)
				S_StartSound(t, sfx_s1bb)
				s.didthrowlanding = true
				if t.player and not s.playeranim and not s.alreadyexploded
					s.playeranim = 70
					s.alreadyexploded = true
					s.hmsthrow = 4
					if not SMS_Graphix(s)
						SMS_SmokeCircle(s)
						SMS_InflictFlameHUD(s,444*t.scale, 55, FF_TRANS30, SKINCOLOR_LAVENDER)
						SMS_FireCircle(s, 3, DIST, nil, SCALE, TIMER)
					end			
					return --
				end
			end
			if not s.momact
				t.momx,t.momy,t.momz = $/3,$/3,$/3
				s.momact = true
				t.rollangle = 0
			end
			if s.playeranim and not (s.hmsthrow > 150)
				s.playeranimstart = true
				A_BossScream(s, 0, MT_SMOKE)
				A_BossScream(s, 0, MT_SMOKE)
				if t.player
					t.player.powers[pw_nocontrol] = 2
					t.player.drawangle = t.angle
				end
				if P_IsObjectOnGround(t)
					s.playeranim = $-1 
					if (leveltime % 5 == 0)
						s.hmsthrow = max($-1,0)
					end
					t.state = S_PLAY_PAIN
					
				/*	if P_IsValidSprite2(s, SPR2_FAIL)
						s.sprite2 = SPR2_FAIL
						t.rollangle = 0
					elseif P_IsValidSprite2(s, SPR2_SHIT)
						t.rollangle = 0
						s.sprite2 = SPR2_SHIT
					else */
						t.rollangle = ANGLE_180
						if not s.hmsthrow or s.hmsthrow < 3
							t.rollangle = 0
						end
				//	end
				else
					s.hmsthrow = max($-1,0)
					t.rollangle = $-(ANG20*t.rollhdecide)
					if t.skin == "sms" or t.skin == "adventuresonic" or t.skin == "samus" or t.skin == "basesamus"
						t.state = S_PLAY_PAIN
					else
						t.state = S_PLAY_DEAD
					end
					if not s.hmsthrow or (s.hmsthrow < 3)
						t.rollangle = 0
					end
				end
				if not s.playeranim or s.playeranim == 1
					if t.player
						if P_IsObjectOnGround(s)
							P_DoJump(t.player, true)
						end
						t.player.powers[pw_nocontrol] = 0
					end
					t.state = S_PLAY_ROLL
					ResetThrowValues(t)
					s.state = S_NULL return --
				end
			elseif s.valid and s.playeranim == 0
				ResetThrowValues(t)
				if not s.player
					s.state = S_NULL
				end
				return --
			end
		end
		
		if not s.alreadyexploded and not s.playeranimstart		
			if s.hmsthrowog and s.hmsthrowog.valid and s.hmsthrowog.mo	
				if not t.rollhdecide
					t.rollhdecide = (SMSLocalRNG(8,9,s) == 9) and 1 or -1
				end
				t.angle = $+(FixedAngle(45<<16)*t.rollhdecide)
				
				if not s.hmsthrow
				or (s.hmsthrow < 3)
				and not s.homingbounce
					t.rollangle = 0
				else
					t.rollangle = $+FixedAngle(45<<16)*t.rollhdecide
				end
		
				if (leveltime % 2 == 0)
					local ghs = P_SpawnGhostMobj(s)
					ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
					ghs.blendmode = AST_ADD
					ghs.colorized = true
					ghs.rollangle = s.rollangle
				else
					local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_SMSGROUNDBOOST)
					ghs.tracer = s.hmsthrowog.mo
				end
				if (s.hmsthrow >= 27)
					if s.hmsthrow == 27
						P_FlashPal(s.hmsthrowog, PAL_NUKE, 3)
						S_StartSound(t, sfx_s3k83)
						S_StartSound(t, sfx_beeyow)
					end
					local ghs = P_SpawnMobj(t.x+150<<16, t.y+150<<16, t.z, MT_SMSGROUNDBOOST)
					ghs.tracer = s.hmsthrowog.mo
					ghs = P_SpawnMobj(t.x-150<<16, t.y-150<<16, t.z, MT_SMSGROUNDBOOST) 
					ghs.tracer = s.hmsthrowog.mo
					ghs = P_SpawnMobj(t.x, t.y, t.z+150<<16, MT_SMSGROUNDBOOST) 
					ghs.color = SKINCOLOR_FLAME 
					ghs = P_SpawnMobj(t.x, t.y, t.z-150<<16, MT_SMSGROUNDBOOST)
					ghs.color = SKINCOLOR_SUPERGOLD5
				end
			end
		  
			s.momtotal = abs(t.momx)+abs(t.momy)
			
			if (s.hmsthrow == 2)
				if not s.homingbounce
					t.rollangle = 0
				end
				t.momz = FixedMul(FixedMul(125<<16, FRACUNIT), sin(s.hmsthrowaim))
				P_InstaThrust(t, s.hmsthrowang, 125<<16)
				s.momtotal = abs(t.momx)+abs(t.momy)
				s.momtotalfirst = s.momtotal
				t.angle = R_PointToAngle2(t.x, t.y, t.x+t.momx, t.y+t.momy)
				
			elseif (s.hmsthrow == 27)
			
				t.momz = FixedMul(FixedMul(200<<16, FRACUNIT), sin(s.hmsthrowaim))
				P_InstaThrust(t, s.hmsthrowang, 200<<16)
				s.momtotal = abs(t.momx)+abs(t.momy)
				s.momtotalfirst = s.momtotal
			end
		end
		return -- End hook early if we're at this point
	elseif s.valid
		s.state = S_NULL return --
	end
end, MT_SMSTHROWTRACKER)
--Check for line collissions with this hook.
addHook("MobjMoveBlocked", function(s, m, line)
	if line 
	and ((s.smsthrow and s.smsthrowog) or (s.hmsthrow and s.hmsthrowog)) --Not thrown hard enough, ignore.
	and not s.CDbounce
		if s.target and s.target.valid
		local t = s.target
			local x,y = P_ClosestPointOnLine(s.x, s.y, line)
			local BOUNCEANGLE = R_PointToAngle2(s.x, s.y, x, y)
			local ANGSHIFT,PLUS = SMS_AngleDifference(BOUNCEANGLE,R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy), 2, ANGLE_45, 2)
			BOUNCEANGLE = $+(ANGSHIFT*PLUS)	
			S_StartSoundAtVolume(t, sfx_corkh, 104)
			S_StartSoundAtVolume(t, sfx_doord2,46)
			S_StartSoundAtVolume(t, sfx_mswing,69)
				local PRESPEED = max(abs(t.momx)+abs(t.momy), 3*s.scale)
				s.momx = $/4 s.momy = $/4
				t.momx = $/4 t.momy = $/4
				P_SetObjectMomZ(t, -t.scale, true)
				P_Thrust(t, BOUNCEANGLE+ANGLE_180, PRESPEED)	
				local RNG = SMSLocalRNG(2,6,s)
				local ghs = SMS_SmokeCircle(s, 0, 1, s, (FRACUNIT/2)*RNG)
				if ghs and ghs.valid
					if (RNG > 4)
						ghs.ditchtracer = 1
					end
				ghs.fuse = $-6
				ghs.spriteyoffset = -33<<16
			end			
		end
		s.BlockedByLine = line
		s.CDbounce = 3
	end
end, MT_SMSTHROWTRACKER)

//DummyTracker, dummyhbx. The object makes hitbox for enemies that have none. I WILL find you, and I WILL punch you.
addHook("MobjThinker", function(s)
	if s.target and s.target.valid and s.target.health
		local t = s.target
		P_MoveOrigin(s, t.x, t.y, t.z)
	else
		s.state = S_NULL
	end
end, MT_SMSDUMMYTRACKER)

--Disappear if SMS lands on you.
addHook("MobjThinker", function(s)
	if P_FaceStabCheckMeleeRange(s)
	or s.target and s.target.valid and P_IsObjectOnGround(s.target)
		s.state = S_NULL
	end
end, MT_ATOMDIVETARGET)

//The Powerbomb is a slow but large explosion. If seen in time it can be dodged
//but if not, then you'll be in really bad shape. Don't get caught off guard!
addHook("MobjThinker", function(s)
	if s.target and s.target.valid
	local t = s.target
	local ghs
		if s.init == nil	
			SMS_Gore(s, 25)
			s.blendmode = AST_ADD
			s.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			
			ghs = SMSRSpawnGhost(s, 2)
			if ghs and ghs.valid
				ghs.scale = $/2
			end
			s.init = true
		end
		
		if s.state == S_SMSPOWERBOMB1
			s.scale = FRACUNIT*10
			s.color = SKINCOLOR_FLAME
			P_InstaThrust(s, t.angle, -10) //Move real slowly backwards.
			P_NukeEnemies((t.battlemodsms) and t or s, t, 400<<16)
			if not (t.player and t.player.smsgraphix == 2)
				A_SMSquake(t, 55<<16, 4, 6000)
			end
		elseif s.state == S_SMSPOWERBOMB1A
			s.scale = s.scale+9001	
		end
		
		--Now start seperate explosion phases...
		if not s.phase
		
			local ghs = P_SpawnMobjFromMobj(s, 0,0, -25<<16, MT_HMSNOVAWAVE)
			ghs.color = SKINCOLOR_RED
			ghs.followmenoz = s
			s.scale = FRACUNIT
			s.phase = 1
			
			--Shock Waves
			for i = 1,64,2
				local ghs = P_SpawnMobjFromMobj(s, 0,0,135<<16, MT_THOK)
				ghs.renderflags = RF_PAPERSPRITE|RF_FULLBRIGHT|RF_NOCOLORMAPS
				P_SetObjectMomZ(ghs, 4<<16)
				ghs.angle = (FixedAngle(367627)*i)+ANGLE_90
				P_InstaThrust(ghs, (FixedAngle(367627)*i), 11<<16)
				ghs.fuse = 73 ghs.tics = 74
				ghs.scale = t.scale*3
				ghs.destscale = $*99
				ghs.sprite = SPR_PWBM
				ghs.frame = A|FF_TRANS90
				ghs.color = SKINCOLOR_CRIMSON
				ghs.spriteyscale = $/4
				ghs.spritexscale = $*2
			end				
			for i = 1,64,2
				local ghs = P_SpawnMobjFromMobj(s, 0,0,40<<16, MT_THOK)
				ghs.renderflags = RF_PAPERSPRITE|RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.blendmode = AST_ADD
				ghs.angle = (FixedAngle(367627)*i)+ANGLE_90
				P_InstaThrust(ghs, (FixedAngle(367627)*i), 26<<16)
				P_SetObjectMomZ(ghs, FRACUNIT)
				ghs.fuse = 78 ghs.tics = 79
				ghs.scale = t.scale*3
				ghs.destscale = $*99
				ghs.sprite = SPR_PWBM
				ghs.frame = A|FF_TRANS80
				ghs.color = SKINCOLOR_SUPERGOLD5
				ghs.spriteyscale = $/2
				ghs.spritexscale = $*4/3
			end				
			if not (t.player and t.player.smsgraphix == 2)
				A_SMSSTOMPSMOKE(s, 2, MT_EXPLODE, 71<<16)
				A_SMSSTOMPSMOKE(s, 4, MT_BOSSEXPLODE, 45<<16)
				A_SMSSTOMPSMOKE(s, 7, MT_EXPLODE)
			end
		else
			if s.state == S_SMSPOWERBOMB2
				s.scale = s.scale+12500
				if not (s.phase >= 2)
					A_SMSquake(t, 33<<16, 35, 5000)
					s.color = SKINCOLOR_KETCHUP
					P_NukeEnemies((t.battlemodsms) and t or s, t, 800*t.scale) //Welp. Screw you too, Battlemod
					s.phase = 2
				end
			elseif s.state == S_SMSPOWERBOMB3
				s.color = SKINCOLOR_YELLOW
				s.scale = s.scale+25000
				if (s.phase < 3)
					if SMS_Graphix(s) == 0
						A_SMSSTOMPSMOKE(s, 8, MT_BOSSEXPLODE, 120<<16)
						A_SMSSTOMPSMOKE(s, 12, MT_EXPLODE, 75<<16)
						A_SMSSTOMPSMOKE(s, 16, MT_BOSSEXPLODE)
						
						local ghs = SMS_ElectricBody(t, 12, SKINCOLOR_CRIMSON)
						ghs.sttfade = nil ghs.blendmode = 0
						ghs.frame = $ & ~FF_TRANSMASK
						
						ghs = SMS_LightFlash(t, SKINCOLOR_SUPERSKY5)
						ghs.tracer = s
						ghs.fuse = 28
						ghs.scalespeed = FRACUNIT/5
						ghs.spriteyoffset = $-10<<16						
					end
					s.phase = 3
				end
			elseif s.state == S_SMSPOWERBOMB4
				s.color = SKINCOLOR_WHITE
				s.scale = s.scale+41500
				if (s.phase < 4)
					A_SMSkillstuff(s, 2250*t.scale, 1222*t.scale, t, false, true)
					if not t.battlemodsms
						P_NukeEnemies(s, t, G_PlatformGametype() and 2250*t.scale or 1800*s.scale)
					else
						P_NukeEnemies(t, t, 1800*t.scale) //Battlemod is an ass. :T
					end
					if SMS_Graphix(s) != 2
						local ghs = SMS_ElectricBody(t, 34, SKINCOLOR_SKY)
						ghs.sttfade = true
					
						ghs = SMS_LightFlash(t, SKINCOLOR_SMS2R)
						ghs.tracer = s
						ghs.fuse = 28
						ghs.scalespeed = FRACUNIT/8
						ghs.spriteyoffset = $-9<<16
					end
					
					s.phase = 4
				end
			elseif s.state == S_SMSPOWERBOMB5
				s.color = SKINCOLOR_BONE
				s.phase = 6
				s.scale = s.scale+25000
			elseif s.state == S_SMSPOWERBOMB6
				s.color = SKINCOLOR_EMERALD
				s.scale = s.scale+15000
			end
		end
	end
end, MT_SMSPOWERBOMB)

//Spawn so many graphics the camera needs to zoom out to even have a chance to see them all!
//HMS' nuclear explosion!
addHook("MobjThinker", function(s)
	if s.target and s.target.valid
		local t = s.target
		if SMS_Graphix(s) == 0 
			if not s.phase
			or ((leveltime % 6 == 0) and (s.state >= S_HMSPOWERBOMB1) and (s.state <= S_HMSPOWERBOMB2) and not s.thrownnucl)
				if (s.state < S_HMSPOWERBOMB2)
					HMS_BoltStorm(s, SKINCOLOR_RED, 17, nil, 880)
				end
				local COLORTABLE = {SKINCOLOR_RED, SKINCOLOR_SMS3R, SKINCOLOR_SMS5R, SKINCOLOR_ORANGE, SKINCOLOR_CRIMSON, SKINCOLOR_FLAME, SKINCOLOR_RED, SKINCOLOR_SMS4R, SKINCOLOR_RED}
				for d = 1,8
					local FRAME = R|FF_TRANS10 if (d % 2) FRAME = nil end
					for i = 1,8
						local RNG = SMSLocalRNG(1,39,s)
						local RNG2 = SMSLocalRNG(1,9,s)
						local ghs = SMS_LightningStrike(s, SKINCOLOR_SMS3R, FRAME)
						P_SetOrigin(ghs,
						t.x+FixedMul(230*s.scale, cos(s.angle+(ANGLE_22h*d)+(RNG*ANG1)+(ANGLE_45*i))),
						t.y+FixedMul(230*s.scale, sin(s.angle+(ANGLE_22h*d)+(RNG*ANG1)+(ANGLE_45*i))),
						t.z)
						
						ghs.scale = t.scale
						ghs.spriteyscale = $*2+(RNG*15000)/((RNG2/3) or 1)
						ghs.spritexscale = $*2+(RNG*5500)/((RNG2/3) or 1)
						ghs.frame = (i % 2) and $|FF_VERTICALFLIP+FF_TRANS20 or ($|FF_HORIZONTALFLIP|FF_VERTICALFLIP)+FF_TRANS20
						ghs.color = (d % 2) and COLORTABLE[RNG2] or SKINCOLOR_RED
						ghs.fuse = 21
						ghs.rollangle = ANGLE_180
						ghs.sttfirstframe = (ghs.frame & FF_FRAMEMASK)
						ghs.momz = $+(32*t.scale)+(5*s.scale)
						P_Thrust(ghs, R_PointToAngle2(s.x, s.y, ghs.x, ghs.y), ((RNG/6)+6)*t.scale)
						if (s.state == S_HMSPOWERBOMB2) and (s.tics < 40)
							ghs.frame = ($ & ~FF_TRANSMASK)+min(FF_TRANS90, (s.tics/2)<<16)
						end
					end
				end				
			end
		end
		--Initial explosion
		if not s.phase //Otherwise this'd keep spawning clouds for the entirety of the frame.	
			local GORELVL = SMS_Gore(s, 50) --Big boost to gorelvl beforehand.
				if t.player and t.player.hypermysticsonic
					A_SMSkillstuff(s, 4000<<16, 1250<<16, t)
				end
			
				A_SMSSTOMPSMOKE(s, 7, MT_BOSSEXPLODE, 70, 36<<16, 9<<16)			
				A_SMSSTOMPSMOKE(s, 4, MT_HMSLIGHTNING2)
				
				if SMS_Graphix(s) == 0		
					HMS_BoltStorm(s, SKINCOLOR_RED, 17, nil, 880)
					A_SMSSTOMPSMOKE(s, 25, MT_SPARK, 25, 20<<16, 4<<16)
					A_SMSSTOMPSMOKE(s, 15, MT_BOSSEXPLODE, nil, 3<<16, 6<<16)
					A_SMSSTOMPSMOKE(s, 14, MT_HMSPBC, nil, nil, 2<<16)			
				end
				if s.thrownnucl
					A_SMSSTOMPSMOKE(s, 5, MT_HMSPBC, 0, -10<<16)
					A_SMSSTOMPSMOKE(s, 3, MT_HMSPBC, 0, -20<<16)
				end
				
			s.scale = FRACUNIT*3
			P_StartQuake(200<<16, 30) --Quake for EVERYONE.
			P_InstaThrust(s, t.angle, -9) --Stop, scoundrel.
			P_SpawnMobj(s.x, s.y+350<<16, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x+350<<16, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x-350<<16, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-350<<16, s.z, MT_HMSPBC)

			P_SpawnMobj(s.x+55<<16, s.y+120<<16, s.z+300<<16*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x-80, s.y-110<<16, s.z+450<<16*(P_MobjFlip(s)), MT_HMSPBC)
			
			s.phase = 1
			
			if SMS_Graphix(s) != 2 --This one's preeeetty heavy on performance...
			local SKIP = (GORELVL > 230) and 2 or 1
				--Shock Wave rings. All together, 130-something sprites for these alone.
				if not SMS_Graphix(s)
					--Bottom ring. Fastest to come out and travel,but has the most sprites.
					for i = 1,64,SKIP
						local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
						ghs.renderflags = RF_PAPERSPRITE|RF_FULLBRIGHT
						ghs.blendmode = AST_ADD
						ghs.angle = (FixedAngle(367627)*i)+ANGLE_90
						P_InstaThrust(ghs, (FixedAngle(367627)*i), 115<<16)
						ghs.fuse = 98 ghs.tics = 99
						ghs.scale = t.scale*5
						ghs.destscale = $*99
						ghs.scalespeed = $*3
						ghs.sprite = SPR_PWBM
						ghs.frame = A|FF_TRANS70
						ghs.color = SKINCOLOR_CLOUDY
					end
					--Top ring
					for i = 1,64,SKIP+1
						local ghs = P_SpawnMobjFromMobj(s, 0,0,200<<16, MT_THOK)
						ghs.renderflags = RF_PAPERSPRITE|RF_FULLBRIGHT
						ghs.blendmode = AST_ADD
						ghs.angle = (FixedAngle(367627)*i)+ANGLE_90
						P_InstaThrust(ghs, (FixedAngle(367627)*i), 20<<16)
						P_SetObjectMomZ(ghs, FRACUNIT)
						ghs.fuse = 118 ghs.tics = 119
						ghs.scale = t.scale*3
						ghs.destscale = $*99
						ghs.sprite = SPR_PWBM
						ghs.frame = A|FF_TRANS90
						ghs.color = SKINCOLOR_CLOUDY
						ghs.spriteyscale = $/2
						ghs.spritexscale = $*2
					end						
				end
				--Middle ring
				if not s.thrownnucl
					for i = 1,64,SKIP+1
						local ghs = P_SpawnMobjFromMobj(s, 0,0,90<<16, MT_THOK)
						ghs.renderflags = RF_PAPERSPRITE|RF_FULLBRIGHT
						ghs.blendmode = AST_ADD
						ghs.angle = (FixedAngle(367627)*i)+ANGLE_90
						P_InstaThrust(ghs, (FixedAngle(367627)*i), 36<<16)
						P_SetObjectMomZ(ghs, FRACUNIT)
						ghs.fuse = 118 ghs.tics = 119
						ghs.scale = t.scale*3
						ghs.destscale = $*99
						ghs.sprite = SPR_PWBM
						ghs.frame = A|FF_TRANS80
						ghs.color = SKINCOLOR_CLOUDY
						ghs.spriteyscale = $/2
						ghs.spritexscale = $*4/3
					end
				end			
			end
		else
		
			if s.state == S_HMSPOWERBOMB1B
			and not (s.phase >= 2)
			
				if t.battlemodsms and not s.thrownnucl
					P_NukeEnemies(t, t, 4000<<16) //Battlemod is a dick			
				elseif t.player and t.player.hypermysticsonic
					P_NukeEnemies(s, t, 4000<<16)
				end
			
				P_SpawnMobj(s.x+700<<16, s.y+700<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-700<<16, s.y-700<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-700<<16, s.y+700<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x+700<<16, s.y-700<<16, s.z, MT_HMSPBC)

				P_SpawnMobj(s.x, s.y, s.z+700<<16, MT_HMSPBC)
				P_SpawnMobj(s.x, s.y, s.z+1150<<16, MT_HMSPBC)
				s.phase = 2
		
			elseif s.state == S_HMSPOWERBOMB1C
				if not (s.phase >= 3)
			
					P_SpawnMobj(s.x, s.y+1250<<16, s.z, MT_HMSPBC)
					P_SpawnMobj(s.x+1250<<16, s.y, s.z, MT_HMSPBC)
					P_SpawnMobj(s.x-1250<<16, s.y, s.z, MT_HMSPBC)
					P_SpawnMobj(s.x, s.y-1250<<16, s.z, MT_HMSPBC)
		
					P_SpawnMobj(s.x, s.y, s.z+1500<<16, MT_HMSPBC)
					P_SpawnMobj(s.x, s.y, s.z+1850<<16, MT_HMSPBC)
					s.phase = 3
				end
				
			elseif s.state == S_HMSPOWERBOMB2
				if not (s.phase >= 4)
			
					if t and not s.thrownnucl
						t.hudboost = 1
					end
				P_StartQuake(73<<16, 150)
				P_SpawnMobj(s.x+1650<<16, s.y+1650<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-1650<<16, s.y-1650<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-1650<<16, s.y+1650<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x+1650<<16, s.y-1650<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x, s.y+1650<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x, s.y-1650<<16, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-1650<<16, s.y, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x+1650<<16, s.y, s.z, MT_HMSPBC)
	
				P_SpawnMobj(s.x, s.y, s.z+2500<<16, MT_HMSPBC)
				P_SpawnMobj(s.x+600<<16, s.y+400<<16, s.z+1900<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x-600<<16, s.y+400<<16, s.z+1850<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x+600<<16, s.y-400<<16, s.z+1900<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x-600<<16, s.y-400<<16, s.z+1850<<16*(P_MobjFlip(s)), MT_HMSPBC)
	
				P_SpawnMobj(s.x+350<<16, s.y, s.z+2250<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x-350<<16, s.y, s.z+2200<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x, s.y-350<<16, s.z+2250<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x, s.y-350<<16, s.z+2200<<16*(P_MobjFlip(s)), MT_HMSPBC)
				s.phase = 4
				end
			elseif s.state == S_HMSPOWERBOMB3
			and not (s.phase >= 5)
				P_StartQuake(20<<16, 70)
				P_SpawnMobj(s.x, s.y, s.z+2575<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x, s.y, s.z+2000<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x+800<<16, s.y, s.z+2300<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x-800<<16, s.y, s.z+2350<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x, s.y-800<<16, s.z+2300<<16*(P_MobjFlip(s)), MT_HMSPBC)
				P_SpawnMobj(s.x, s.y+800<<16, s.z+2350<<16*(P_MobjFlip(s)), MT_HMSPBC)
				s.phase = 5
			end
		end
	end
end, MT_HMSPOWERBOMB)

//Start the clouds off REALLY small.

addHook("MobjThinker", function(s)
	if s.valid
		if s.state == S_HMSPBC0
		s.scale = FRACUNIT/20
			if s.bkhl
				s.scale = FRACUNIT
				s.scalespeed = $/11
				A_SetScale(s, FRACUNIT/20, 1)
				s.state = S_HMSPBC3
			end
		end
		if (s.state == S_HMSPBC3) and not s.bkhl and not s.riz and (s.z > s.floorz+250<<16)
			s.momz = $+6<<16*P_MobjFlip(s)
			s.riz = true
		end
		if s.bkhl 
			if s.target and (s.target.state == S_HMSBLACKHOLE)
				P_HomingAttack(s, s.target)
			else
				s.momx,s.momy = $/5,$/5
				P_SetObjectMomZ(s, 97377)
				s.bkhl = false
			end
			if P_CheckMeleeRange(s) and not (s.target.info.mass == 2006)
				P_KillMobj(s)
			end
		end
	end
end, MT_HMSPBC)

local function TrackerCollide(s, v)
	if (v and v.valid)
		if v.type == MT_SMSECHECK
			return --
		elseif (v.type == MT_CMPHRADIUS) and s.target and not s.target.fusrodah
			CMPHrad(v, s.target)
			return --
		end
	end
	return false
end

addHook("MobjCollide", TrackerCollide, MT_SMSDUMMYTRACKER)
addHook("MobjMoveCollide", TrackerCollide, MT_SMSDUMMYTRACKER)

//Quick fix to Tails' tails being dumb.

/*addHook("MobjThinker", function(s)
	if s.tracer and s.tracer.valid
		s.rollangle = s.tracer.rollangle
	end
end, MT_TAILSOVERLAY)*/