--===================================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*FRACUNIT)
			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 = $+1
		if (s.state != S_PLAY_PAIN)
			p.fusrodah = 0
		end
	end	
	--SMS skin check starts here!	
	if (s.skin == "sms")
		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*FRACUNIT)*s.sms_sideroll
							else
								s.rollangle = $+FixedAngle(20*FRACUNIT)*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
		
		--SMS skin check is still on-going!

--========================================================================
//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 G_GametypeHasSpectators() --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*FRACUNIT,cos(ANGLE)),
							s.y+FixedMul(1100*FRACUNIT,sin(ANGLE)),
							s.z-1400*FRACUNIT,
							MT_SMSECHECK)
							if ghs and ghs.valid
								ghs.cmphhms = true
								ghs.target = s
								ghs.height = 2800*FRACUNIT
								ghs.radius = 1300*FRACUNIT
							end
						else
							local ghs = P_SpawnMobj(
							s.x+FixedMul(570*FRACUNIT,cos(ANGLE)),
							s.y+FixedMul(570*FRACUNIT,sin(ANGLE)),
							s.z-600*FRACUNIT,
							MT_SMSECHECK)
							if ghs and ghs.valid
								ghs.cmphsms = true
								ghs.target = s
								ghs.height = 1200*FRACUNIT
								ghs.radius = 660*FRACUNIT
							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*FRACUNIT or 1640*FRACUNIT
							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*FRACUNIT, 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*FRACUNIT)) --Distance checks.
							and not (s.z > z.mo.z+475*FRACUNIT)
					 		and not (s.z < z.mo.z-435*FRACUNIT)
					 		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*FRACUNIT)
										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*FRACUNIT)
					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 G_GametypeHasSpectators()
					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*FRACUNIT)
								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*FRACUNIT)
								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!

		if p.smsatomdivestun != nil --We're currently stunned, when should we cancel it?
			p.sms_flamedelay = max($,2)
			if (s.state != S_SMS_ATOMLAND1)
			and (s.state != S_SMS_ATOMLAND2)
			and (s.state != S_HMS_ATOMLAND)
			and not (p.smsdivetimer and not p.hypermysticsonic)
			and not s.sdodgeoh
				p.smsatomdivestun = nil
			end
		end
		if ((s.state == S_SMS_ATOMLAND1) or (s.state == S_SMS_ATOMLAND2) or (s.state == S_HMS_ATOMLAND))
		or (p.smsdivetimer and not p.hypermysticsonic) --HMS retains control during the Atom Dive!
		or s.sdodgeoh

			if (s.state == S_SMS_ATOMLAND1)
			or (s.state == S_SMS_ATOMLAND2)
			or (s.state == S_HMS_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)
						local ghs = P_SpawnMobj(s.x+FixedMul(24*s.scale, cos(p.drawangle+ANGLE_90)),s.y+FixedMul(24*s.scale, sin(p.drawangle+ANGLE_90)), s.z, MT_SPINDUST)
						ghs.frame = P_RandomRange(0,2)
						ghs = P_SpawnMobj(s.x+FixedMul(24*s.scale, cos(p.drawangle-ANGLE_90)),s.y+FixedMul(24*s.scale, sin(p.drawangle-ANGLE_90)), s.z, MT_SPINDUST)
						ghs.frame = P_RandomRange(0,2)
					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
				if p.hypermysticsonic
					p.camerascale =  FRACUNIT*24 --Explosion cam.
				else
					p.camerascale =  FRACUNIT*3
				end
				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
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)

--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
				if t.smspickupflags
					t.flags = t.smspickupflags
					t.smspickupflags = nil
				end
				t.cmphttimer = nil
				P_KillMobj(s)
			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
					P_InstaThrust(t, s.ogsms.angle, 0)
					t.flags = $|MF_MONITOR|MF_SHOOTABLE & ~(MF_NOCLIPTHING|MF_NOGRAVITY)
					P_KillMobj(s)
				end
			else
				P_KillMobj(s)
			end
			return --
			
//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)*FRACUNIT
			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
		
			if (t.momx < 0)
				s.lmomx = t.momx*-1
			else
				s.lmomx = t.momx
			end
			if (t.momy < 0)
				s.lmomy = t.momy*-1
			else
				s.lmomy = t.momy
			end
			
			s.momtotal = s.lmomy+s.lmomx
				
			if (s.smsthrow == 2)
			S_StartSound(s, sfx_mswing)
			S_StartSound(s, sfx_mswing)
			t.momz = FixedMul(FixedMul(45*FRACUNIT, 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*FRACUNIT), FixedDiv(132*FRACUNIT, 3*FRACUNIT/2))
					t.momy = FixedMul(FixedDiv(s.smsthrowguy.y-t.y, 450*FRACUNIT), FixedDiv(132*FRACUNIT, 3*FRACUNIT/2))
					t.momz = FixedMul(FixedDiv(s.smsthrowguy.z-t.z, 450*FRACUNIT), FixedDiv(132*FRACUNIT, 3*FRACUNIT/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 (t.momx < 0)
					s.lmomx = t.momx*-1
				else
					s.lmomx = t.momx
				end
				if (t.momy < 0)
					s.lmomy = t.momy*-1
				else
					s.lmomy = t.momy
				end
				if s.momtotalfirst == nil //Set our first known speed!
					s.momtotalfirst = s.lmomy+s.lmomx
				end
				t.angle = R_PointToAngle2(t.x, t.y, t.x+t.momx, t.y+t.momy)
				s.momtotal = s.lmomy+s.lmomx
			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)*FRACUNIT
						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*FRACUNIT)
				t.momx = 0
				t.momy = 0
				if t.player
					t.z = $+(10*t.scale)*P_MobjFlip(t)
					t.eflags = $ & ~MFE_JUSTHITFLOOR
					t.state = S_PLAY_PAIN
					t.player.powers[pw_flashing] = 90 
					A_SMSquake(t, 45*FRACUNIT, 4, 900)
				end
				if s.smsthrowog and s.smsthrowog.mo
					A_SMSquake(s.smsthrowog.mo, 45*FRACUNIT, 4, 100, true)
				end
				
				local ghs = P_SpawnMobjFromMobj(t, 0,0,0, MT_BURSTWAVE)
				ghs.tracer = t
				ghs.renderflags = $|RF_SEMIBRIGHT|RF_NOCOLORMAPS
				ghs.spriteyscale = $*3/2
				ghs.spritexscale = $*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*FRACUNIT
				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
					P_DamageMobj(t, s.smsthrowog.mo, 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
				if t.smspickupflags
					t.flags = t.smspickupflags
					t.smspickupflags = nil
				end
				t.rollangle = 0		
				if s.valid
					P_KillMobj(s)
				end
			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
			if s.momx == 0 s.momx = 8 end
			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*FRACUNIT
						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
					if (t.skin == "sms")
						t.state = S_PLAY_PAIN
					else
						t.state = S_PLAY_DEAD
					end
				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.spriteyscale = $*2
					ghs.spritexscale = $*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*FRACUNIT)
					S_StartSound(t, sfx_spld)
					S_StartSound(t, sfx_nuexp)
				end
				
				t.momz = 0
				t.momx = 0
				t.momy = 0
				
				s.alreadyexploded = true
				if (t.flags & (MF_ENEMY|MF_MISSILE)) and s.hmsthrowog.mo
					t.rollangle = 0
					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) or (t.eflags & MFE_GOOWATER))
			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.momz = $/3
					t.momx = $/3
					t.momy = $/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 = $-1
						end
						t.rollangle = ANGLE_180
						if not s.hmsthrow or s.hmsthrow < 3
							t.rollangle = 0
						end
						t.state = S_PLAY_PAIN
					else
						s.hmsthrow = $-1
						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.rollangle = 0
						t.state = S_PLAY_ROLL
						if t.smspickupflags
							t.flags = t.smspickupflags
							t.smspickupflags = nil
						end
						if s.valid
							t.rollangle = 0
							s.state = S_NULL
							return --
						end
					end
				elseif s.valid and s.playeranim == 0
					if t
						t.rollangle = 0
						if t.smspickupflags
							t.flags = t.smspickupflags
							t.smspickupflags = nil
						end
					end
					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*FRACUNIT)*t.rollhdecide)
				
				if not s.hmsthrow
				or (s.hmsthrow < 3)
				and not s.homingbounce
					t.rollangle = 0
				else
					t.rollangle = $+FixedAngle(45*FRACUNIT)*t.rollhdecide
				end

				if (leveltime % 2 == 0)
					local ghs = P_SpawnGhostMobj(s)	
					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*FRACUNIT, t.y+150*FRACUNIT, t.z, MT_SMSGROUNDBOOST)
					ghs.tracer = s.hmsthrowog.mo
					ghs = P_SpawnMobj(t.x-150*FRACUNIT, t.y-150*FRACUNIT, t.z, MT_SMSGROUNDBOOST) 
					ghs.tracer = s.hmsthrowog.mo
					ghs = P_SpawnMobj(t.x, t.y, t.z+150*FRACUNIT, MT_SMSGROUNDBOOST) 
					ghs.color = SKINCOLOR_FLAME 
					ghs = P_SpawnMobj(t.x, t.y, t.z-150*FRACUNIT, MT_SMSGROUNDBOOST)
					ghs.color = SKINCOLOR_SUPERGOLD5
				end
			  end	
				if (t.momx < 0)
					s.lmomx = t.momx*-1
				else
					s.lmomx = t.momx
				end
				if (t.momy < 0)
					s.lmomy = t.momy*-1
				else
					s.lmomy = t.momy
				end
				s.momtotal = s.lmomy+s.lmomx	
				
				if (s.hmsthrow == 2)
					if not s.homingbounce
						t.rollangle = 0
					end
				t.momz = FixedMul(FixedMul(125*FRACUNIT, FRACUNIT), sin(s.hmsthrowaim))
				P_InstaThrust(t, s.hmsthrowang, 125*FRACUNIT)
					if (t.momx < 0)
						s.lmomx = t.momx*-1
					else
						s.lmomx = t.momx
					end
					if (t.momy < 0)
						s.lmomy = t.momy*-1
					else
						s.lmomy = t.momy
					end
					s.momtotal = s.lmomy+s.lmomx
					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*FRACUNIT, FRACUNIT), sin(s.hmsthrowaim))
				P_InstaThrust(t, s.hmsthrowang, 200*FRACUNIT)
					if (t.momx < 0)
						s.lmomx = t.momx*-1
					else
						s.lmomx = t.momx
					end
					if (t.momy < 0)
						s.lmomy = t.momy*-1
					else
						s.lmomy = t.momy
					end
					s.momtotal = s.lmomy+s.lmomx
					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*FRACUNIT
			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.
			if t.battlemodsms
				P_NukeEnemies(t, t, 400*FRACUNIT)
			else
				P_NukeEnemies(s, t, 400*FRACUNIT)
			end
			if not (t.player and t.player.smsgraphix == 2)
				A_SMSquake(t, 55*FRACUNIT, 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*FRACUNIT, 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*FRACUNIT, MT_THOK)
				ghs.renderflags = RF_PAPERSPRITE|RF_FULLBRIGHT|RF_NOCOLORMAPS
				P_SetObjectMomZ(ghs, 4*FRACUNIT)
				ghs.angle = (FixedAngle(367627)*i)+ANGLE_90
				P_InstaThrust(ghs, (FixedAngle(367627)*i), 11*FRACUNIT)
				ghs.fuse = 73 ghs.tics = 74
				ghs.scale = t.scale*3
				ghs.destscale = $*99
				ghs.sprite = SPR_PWBM
				ghs.frame = A|TR_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*FRACUNIT, 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*FRACUNIT)
				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|TR_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*FRACUNIT)
				A_SMSSTOMPSMOKE(s, 4, MT_BOSSEXPLODE, 45*FRACUNIT)
				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*FRACUNIT, 35, 5000)
					s.color = SKINCOLOR_KETCHUP
					if t.battlemodsms
						P_NukeEnemies(t, t, 800*t.scale) //Welp. Screw you too, Battlemod
					else
						P_NukeEnemies(s, t, 800*t.scale)
					end
					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*FRACUNIT)
						A_SMSSTOMPSMOKE(s, 12, MT_EXPLODE, 75*FRACUNIT)
						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*FRACUNIT						
					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 t.battlemodsms
						P_NukeEnemies(t, t, 1800*t.scale) //Battlemod is an ass.
					elseif G_PlatformGametype()
						P_NukeEnemies(s, t, 2250*t.scale)
					else
						P_NukeEnemies(s, t, 1800*t.scale)
					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*FRACUNIT
					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|TR_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)*FRACUNIT)
						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*FRACUNIT, 1250*FRACUNIT, t)
				end
			
				A_SMSSTOMPSMOKE(s, 7, MT_BOSSEXPLODE, 70, 36*FRACUNIT, 9*FRACUNIT)			
				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*FRACUNIT, 4*FRACUNIT)
					A_SMSSTOMPSMOKE(s, 15, MT_BOSSEXPLODE, nil, 3*FRACUNIT, 6*FRACUNIT)
					A_SMSSTOMPSMOKE(s, 14, MT_HMSPBC, nil, nil, 2*FRACUNIT)			
				end
				if s.thrownnucl
					A_SMSSTOMPSMOKE(s, 5, MT_HMSPBC, 0, -10*FRACUNIT)
					A_SMSSTOMPSMOKE(s, 3, MT_HMSPBC, 0, -20*FRACUNIT)
				end
				
			s.scale = FRACUNIT*3
			P_StartQuake(200*FRACUNIT, 30) --Quake for EVERYONE.
			P_InstaThrust(s, t.angle, -9) --Stop, scoundrel.
			P_SpawnMobj(s.x, s.y+350*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x+350*FRACUNIT, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x-350*FRACUNIT, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-350*FRACUNIT, s.z, MT_HMSPBC)

			P_SpawnMobj(s.x+55*FRACUNIT, s.y+120*FRACUNIT, s.z+300*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x-80, s.y-110*FRACUNIT, s.z+450*FRACUNIT*(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*FRACUNIT)
						ghs.fuse = 98 ghs.tics = 99
						ghs.scale = t.scale*5
						ghs.destscale = $*99
						ghs.scalespeed = $*3
						ghs.sprite = SPR_PWBM
						ghs.frame = A|TR_TRANS70
						ghs.color = SKINCOLOR_CLOUDY
					end
					--Top ring
					for i = 1,64,SKIP+1
						local ghs = P_SpawnMobjFromMobj(s, 0,0,200*FRACUNIT, 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*FRACUNIT)
						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|TR_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*FRACUNIT, 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*FRACUNIT)
						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|TR_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*FRACUNIT) //Battlemod is a dick			
				elseif t.player and t.player.hypermysticsonic
					P_NukeEnemies(s, t, 4000*FRACUNIT)
				end
			
				P_SpawnMobj(s.x+700*FRACUNIT, s.y+700*FRACUNIT, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-700*FRACUNIT, s.y-700*FRACUNIT, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x-700*FRACUNIT, s.y+700*FRACUNIT, s.z, MT_HMSPBC)
				P_SpawnMobj(s.x+700*FRACUNIT, s.y-700*FRACUNIT, s.z, MT_HMSPBC)

				P_SpawnMobj(s.x, s.y, s.z+700*FRACUNIT, MT_HMSPBC)
				P_SpawnMobj(s.x, s.y, s.z+1150*FRACUNIT, MT_HMSPBC)
				s.phase = 2
			
			--Whoops.
		
		elseif s.state == S_HMSPOWERBOMB1C
			if not (s.phase >= 3)
		
			P_SpawnMobj(s.x, s.y+1250*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x+1250*FRACUNIT, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x-1250*FRACUNIT, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-1250*FRACUNIT, s.z, MT_HMSPBC)

			P_SpawnMobj(s.x, s.y, s.z+1500*FRACUNIT, MT_HMSPBC)
			P_SpawnMobj(s.x, s.y, s.z+1850*FRACUNIT, 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*FRACUNIT, 150)
			P_SpawnMobj(s.x+1650*FRACUNIT, s.y+1650*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x-1650*FRACUNIT, s.y-1650*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x-1650*FRACUNIT, s.y+1650*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x+1650*FRACUNIT, s.y-1650*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x, s.y+1650*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-1650*FRACUNIT, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x-1650*FRACUNIT, s.y, s.z, MT_HMSPBC)
			P_SpawnMobj(s.x+1650*FRACUNIT, s.y, s.z, MT_HMSPBC)

			P_SpawnMobj(s.x, s.y, s.z+2500*FRACUNIT, MT_HMSPBC)
			P_SpawnMobj(s.x+600*FRACUNIT, s.y+400*FRACUNIT, s.z+1900*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x-600*FRACUNIT, s.y+400*FRACUNIT, s.z+1850*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x+600*FRACUNIT, s.y-400*FRACUNIT, s.z+1900*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x-600*FRACUNIT, s.y-400*FRACUNIT, s.z+1850*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)

			P_SpawnMobj(s.x+350*FRACUNIT, s.y, s.z+2250*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x-350*FRACUNIT, s.y, s.z+2200*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-350*FRACUNIT, s.z+2250*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-350*FRACUNIT, s.z+2200*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			s.phase = 4
			end
		elseif s.state == S_HMSPOWERBOMB3
		and not (s.phase >= 5)
			P_StartQuake(20*FRACUNIT, 70)
			P_SpawnMobj(s.x, s.y, s.z+2575*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x, s.y, s.z+2000*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x+800*FRACUNIT, s.y, s.z+2300*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x-800*FRACUNIT, s.y, s.z+2350*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x, s.y-800*FRACUNIT, s.z+2300*FRACUNIT*(P_MobjFlip(s)), MT_HMSPBC)
			P_SpawnMobj(s.x, s.y+800*FRACUNIT, s.z+2350*FRACUNIT*(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*FRACUNIT)
			s.momz = $+6*FRACUNIT*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 = $/5
				s.momy = $/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)*/