addHook("MobjMoveCollide", function(s, v)
	if (gametype == GT_COOP)
		if v.player
		and ((v.player.powers[pw_carry] == CR_PLAYER) or v.player.knucklewaving or v.player.iamcarryingsms)
		return false
		end
	end
	if v and (v.flags & MF_MONITOR)
	return false
	end
end, MT_SMSFIREBLAST)

addHook("MobjMoveCollide", function(s, v)
	if (gametype == GT_COOP)
		if v.player
		and ( (v.player.knucklewaving or v.player.iamcarryingsms or v.hmspickedup)
		or ((v.player.powers[pw_carry] == CR_PLAYER) and v.tracer and s.target and (s.target == v.tracer)) )	
		return false
		end
	end
	if v and (v.flags & MF_MONITOR)
	return false
	end
end, MT_HMSFIREBLAST)

addHook("MobjCollide", function(s, v)
	if s and s.target and v and (s.target == v)
		return false
	end
end, MT_SPINFIRE)
addHook("MobjMoveCollide", function(s, v)
	if s and s.target and v and (s.target == v)
		return false
	end
end, MT_SPINFIRE)


addHook("MobjMoveCollide", function(s, v)
	if v and (v.flags & MF_MONITOR)
	return false
	end
end, MT_HMS_NAPALM_FLAMES)

//Let's go do some anti-lag stuff. This prevents people from spamming fire as HMS in the same spot and causing lag.

addHook("MobjCollide", function(s, v)
	if v and v.type == MT_HMSFLAMEREST
		if v.valid and (v.fuse > 255) and s and s.valid
		P_InstaThrust(v, (R_PointToAngle2(s.x, s.y, v.x, v.y)), 20*FRACUNIT)
		elseif v and v.valid
		v.state = S_NULL
		end
	elseif v and (v.flags & MF_MONITOR)
		return false
	elseif v and (v.flags & MF_ENEMY) and (v.flags & MF_SHOOTABLE) and v.health and s.target
	and not (s.z > v.z+v.height) and not (v.z > s.z+s.height)
		P_DamageMobj(v, s, s.target)
		return false
	elseif not (v and v.player)
		return false
	end
end, MT_HMSFLAMEREST)

//Atomdive object pops monitors!

addHook("MobjMoveCollide", function(s, v)
	if s and s.tracer and v and v.health and (v.flags & MF_MONITOR)
		if not (s.z-10*FRACUNIT > v.z+v.height)
		and not (v.z > s.z+s.height)
		P_KillMobj(v, s, s.tracer)
		end
	end
end, MT_ATOMDIVEPOP)

//SMS can dodge, footsweep, stomp or dive through monitors!

addHook("MobjMoveCollide", function(s, m)
	if (s.player.sms_comethaymaker and s.battlemodsms)
	return false
	end
	if s and s.player and s.skin == "sms"
	and (s.player.sms_dodging or s.player.footsweepanim or (s.state == S_SMS_STOMP1 or s.state == S_SMS_STOMP2)
	or s.player.smsdivetimer or s.player.smsatomdivestun or (s.state == S_SMS_ATOMLAND1))
		if (m.valid and m.health and m.flags & MF_MONITOR)
		and not (((s.z > m.z+m.height+5*FRACUNIT) and not (s.state == S_SMS_STOMP1 or s.state == S_SMS_STOMP2)) or ((s.z > m.z+m.height+40*FRACUNIT) and (s.state == S_SMS_STOMP1 or s.state == S_SMS_STOMP2)))
		and not(m.z > s.z+s.height)
			P_KillMobj(m, s, s)
			return false
		elseif (m.player and s.player.sms_dodging)
		return false
		else
		return
		end
	else
	return
	end
end, MT_PLAYER)

//Reflect with third footsweep

addHook("MobjCollide", function(s, v)
	if (s.player.sms_comethaymaker and s.battlemodsms)
	return false
	end
	if not (v and v.valid)
	or (v.z > s.z+s.height)
	or (s.z > v.z+v.height)
	return 
	end
		if s and s.player and ((s.player.footsweep03) and (s.player.footsweep03 > 3)) and s.player.footsweepanim
			if (v.flags & MF_MISSILE) and not (v.target and (v.target == s))
			S_StartSound(s, sfx_kc68) S_StartSound(s, sfx_kc4c)
			s.ghskick = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_THOK)
			s.ghskick.scalespeed = $*24
			s.ghskick.destscale = s.scale*50
			s.ghskick.color = SKINCOLOR_SUPERSILVER2
			if (v.flags & MF_NOGRAVITY)
			v.momx = $*-2
			v.momy = $*-2
			v.momz = $*-2
			else
			v.momx = $*-1
			v.momy = $*-1
			v.momz = $*-1
			end
			P_SpawnGhostMobj(v)
			v.target = s
			return false
			end
		end
		if v.player and s and s.player and s.player.sms_dodging
		return false
		end
end, MT_PLAYER)

//I proudly present the "STUFF THAT DIES WHEN HMS TOUCHES IT" script!
//...also cramming random crap in here.

local function HMSCollide(h, v)
	if not h.player
	return false end
	if h.player.sms_intoship
	return false end
	if not (v and v.valid)
	return end
	if h.battlemodsms and (v.type == MT_FLINGRING)
	and (h.playerhomecharge or h.player.hometrickanim)
	return false
	end
	if v.player and v.hmspickedup //Pickup!
	and (v.state == S_PLAY_RIDE) and not (h.player.smspickup and (v == h.player.smspickup))
	and not ( (v.z > h.z+h.height+(h.height/3)) or (v.z < h.z+((h.height/3)*2)) )
	and not (v.occupiedcarrying and v.occupiedcarrying != h)
		h.hmspickuptarget = v
	end
	if h.battlemodsms and h.skin == "sms" and v and v.player and v.health
		if not (h.z > v.z+v.height)
		and not (v.z > h.z+h.height)
			if (h.player.hypermysticsonic or h.player.ringburstfly)
			P_DamageMobj(v, h, h)
			return false
			elseif h.player.homing and (v.player.charability == CA_GLIDEANDCLIMB) and P_IsObjectOnGround(v)
			v.player.pflags = $|PF_SPINNING
			return
			elseif v.skin == "fang" and P_IsObjectOnGround(v) and (h.player.pflags & (PF_SPINNING|PF_JUMPED))
			and not (v.player.panim == PA_ABILITY2) and not (v.player.panim == PA_RUN)
			v.player.pflags = $|PF_SPINNING
			return
			end
		end
	end	
	if not (h.player.hypermysticsonic or h.player.ringburstfly)
	return end
	if h.player.starthmscombo
	return
	end
	if ((h.state == S_HMSCOMETHAYMAKER2) or (h.state == S_HMSCOMETHAYMAKER1))
	return false
	end
		if ((v.type == MT_SMALLMACE) or (v.type == MT_BIGMACE) or (v.type == MT_EGGMOBILE4_MACE) or (v.type == MT_SPIKEBALL))
		and not (h.z > v.z+v.height)
		and not (v.z > h.z+h.height)
			S_StartSoundAtVolume(v, sfx_brakrx, 175)
			v.flags = $ & ~MF_SOLID & ~MF_PAIN
			v.flags2 = $|MF2_DONTDRAW
			v.benope = P_SpawnMobj(v.x, v.y, v.z, MT_BOSSEXPLODE)
			if v.benope and v.benope.valid
			v.benope.scale = v.scale*3
			end
			A_SMSquake(h, 61*FRACUNIT, 5, 1340, true)
		end
		if (v.type == MT_TURRET) or (v.type == MT_EGGROBO1) or (v.type == MT_SUSPICIOUSFACESTABBERSTATUE) or (v.type == MT_KOOPA)
		or (v.type == MT_CYBRAKDEMON_ELECTRIC_BARRIER)
		or (v.flags & (MF_ENEMY|MF_BOSS)) //Specifically things with these flags die too.
			if not (h.z > v.z+v.height)
			and not (v.z > h.z+h.height)
			and not (v.info.mass == 2006)
			and not (v.type == MT_ROSY) //Wait, don't disintegrate Amy!
			 	if v.type == MT_EGGROBO1 //Who's slapping now?
				v.state = S_EGGROBO1_PISSED
				v.flags = MF_NOGRAVITY|MF_NOCLIP
				P_SpawnMobj(v.x, v.y, v.z, MT_CYBRAKDEMON_VILE_EXPLOSION)
				S_StartSound(h, sfx_brakrx) S_StartSound(h, sfx_bsnipe)
				P_Thrust(v, R_PointToAngle2(h.x, h.y, v.x, v.y), h.player.speed+7*FRACUNIT)
				v.momz = 45*FRACUNIT
				v.fuse = 300
				v.fusrodah = 2
				P_SpawnGhostMobj(v)
				elseif (v.type == MT_SUSPICIOUSFACESTABBERSTATUE) //Did you really think you could defeat me, by transforming into a statue?! /endquote
					if v.health and not (v.state == S_SUSPICIOUSFACESTABBERSTATUE_BURST2) 
					v.state = S_SUSPICIOUSFACESTABBERSTATUE_BURST2
					end
					return false
				elseif v.health and h.player.hypermysticsonic
					if v and v.valid and v.health
						if (v.flags2 & MF2_FRET)
						v.flags2 = $ & ~MF2_FRET
						end
							S_StartSound(v, sfx_cdfm50)
							v.deathsmoke = P_SpawnMobj(v.x, v.y, v.z+v.height/3, MT_TNTDUST)
							v.hmsgodaurad = true
								if v.deathsmoke
								v.deathsmoke.destscale = $*5
								v.deathsmoke.fuse = 43
								v.deathsmoke.tics = 1
								S_StartSound(v.deathsmoke, sfx_kc40)
								P_Thrust(v.deathsmoke, R_PointToAngle2(v.x, v.y, h.x, h.y), -14*FRACUNIT)
								end
							A_SMSquake(h, 25*FRACUNIT, 3, 999, true)
							
					v.health = 1 	
					P_DamageMobj(v, h, h, 1, DMG_INSTAKILL)
					end
					if v and v.valid and v.health
					P_KillMobj(v, h, h) //Some enemies just won't get the message.
					end
					return false
				else
					return false
				end
			end
		end
		if (v.type == MT_EGGROBO1) or (v.type == MT_CANARIVORE_GAS)
			return false
		end
		if (h.state == S_HMS_INSTANTWARP1 or h.state == S_HMS_INSTANTWARP2)
			return false
		end
end
addHook("MobjCollide", HMSCollide, MT_PLAYER)
addHook("MobjMoveCollide", HMSCollide, MT_PLAYER)

local function TurretCollide(s, v)
	if s and s.valid and s.health and v and v.valid 
	 if v.target and v.target.player and v.target.player.hypermysticsonic
		if not (s.z > v.z+v.height+50*FRACUNIT)
		and not (v.z > s.z+s.height+50*FRACUNIT)
		P_KillMobj(s, v, v.target)
		return false
		end
	 end
	end
end
addHook("MobjCollide", TurretCollide,  MT_TURRET)
addHook("MobjMoveCollide", TurretCollide,  MT_TURRET)

local function HMSE2Collide(s, v)
	if s and s.valid and s.health and v and v.valid and v.target and v.target.player and v.target.player.hypermysticsonic
		if not (s.z > v.z+v.height+50*FRACUNIT)
		and not (v.z > s.z+s.height+50*FRACUNIT)
		and not (s.state == S_SUSPICIOUSFACESTABBERSTATUE_BURST2)
		s.state = S_SUSPICIOUSFACESTABBERSTATUE_BURST2
		return false
		end
	end
end
addHook("MobjCollide", HMSE2Collide,  MT_SUSPICIOUSFACESTABBERSTATUE)
addHook("MobjMoveCollide", HMSE2Collide,  MT_SUSPICIOUSFACESTABBERSTATUE)

local function HMSE3Collide(s, v)
	if s and s.valid and s.health and v and v.valid and (v.flags & MF_MISSILE) and v.target and v.target.player and v.target.player.hypermysticsonic
		if not (s.z > v.z+v.height+50*FRACUNIT)
		and not (v.z > s.z+s.height+50*FRACUNIT)
		P_KillMobj(s, v, v.target)
		return false
		end
	end
end
addHook("MobjCollide", HMSE3Collide,  MT_CYBRAKDEMON_ELECTRIC_BARRIER)
addHook("MobjMoveCollide", HMSE3Collide,  MT_CYBRAKDEMON_ELECTRIC_BARRIER)

local function FLAGSMSCollide(s, v)
	if v and v.player and v.skin == "sms"
		if v.player.hypermysticsonic
		return false
		elseif not v.smsflagrg or (v.smsflagrg < 16)
		v.smsflagrgpermission = 7
			if v.flagsmssfx
			S_StartSound(v, sfx_cdfm47)
			v.novawave = P_SpawnMobj(v.x, v.y, v.z+v.height/2, MT_HMSNOVAWAVE)
			v.novawave.scale = v.scale/12
			v.novawave.tics = 2
			v.novawave.destscale = v.novawave.scalespeed+1
			v.novawave.color = v.color
			v.flagsmssfx = false
			end
		return false
		else
		return
		end
	end
end
addHook("MobjCollide", FLAGSMSCollide, MT_REDFLAG)
addHook("MobjMoveCollide", FLAGSMSCollide, MT_REDFLAG)
addHook("MobjCollide", FLAGSMSCollide, MT_BLUEFLAG)
addHook("MobjMoveCollide", FLAGSMSCollide, MT_BLUEFLAG)


//Never collide with players, DO collide with enemies and hurt 'em.

local function SparkCollide(s, v)
	if v and v.player
		return false
	elseif v and ((v.flags & MF_ENEMY) and (v.flags & MF_SHOOTABLE)) and v.health and not (v.flags2 & MF2_FRET) and s and s.target and not (s.target == v)
		if not ((v.z > s.z+(s.height)) and not (s.z > v.z+(v.height)))	
		s.momx = 0 s.momy = 0 P_DamageMobj(v, v, s.target)
		return false
		end
	else 
		return false
	end
end

addHook("MobjCollide", SparkCollide,  MT_HMSLIGHTNING1)
addHook("MobjMoveCollide", SparkCollide,  MT_HMSLIGHTNING1)

//Never exist in the same place, causing lag. Do kill enemies that get too close.

local function Spark2Collide(s, v)
	if v and s and (v.type == s.type) and (s.ltimer and (s.ltimer > 2)) and v.ltimer
	  if not ((v.z > s.z+s.height) and not (s.z > v.z+v.height))	
		if (v.ltimer > s.ltimer) and v.valid
		P_KillMobj(v)
		return false
		elseif (s.ltimer > v.ltimer) and s.valid
		P_KillMobj(s)
		return false
		end
	  end
	elseif v and (v.flags & MF_ENEMY and v.flags & MF_SHOOTABLE) and v.health and not (v.flags2 & MF2_FRET)
	and s and s.valid and (s.target and not (s.target == v))
		if not ((v.z > s.z+s.height) and not (s.z > v.z+v.height))	
		P_DamageMobj(v, v, s.target)
		return false
		end
	else
	return false
	end
end

addHook("MobjCollide", Spark2Collide,  MT_HMSLIGHTNING2)
addHook("MobjMoveCollide", Spark2Collide,  MT_HMSLIGHTNING2)

local function GoreCollide(s, v)
	if v and not (v.type == MT_SMSECHECK)
	return false
	end
end

addHook("MobjCollide", GoreCollide,  MT_SMSRGORE)
addHook("MobjMoveCollide", GoreCollide,  MT_SMSRGORE)

local function RoboCollide2(h, v)
	if (v and v.player and (v.player.sms_comethaymaker or (h.state == S_SMSCOMETHAYMAKER2 or h.state == S_SMSCOMETHAYMAKER1)))
	return false end
	if not (v and (v.flags & MF_MISSILE) and v.target and v.target.player and v.target.player.hypermysticsonic)
	return end
	if h and h.health
	and not (h.z > v.z+v.height)
	and not (v.z > h.z+h.height)
	h.state = S_EGGROBO1_PISSED
	h.flags = MF_NOGRAVITY|MF_NOCLIP
	P_SpawnMobj(h.x, h.y, h.z, MT_CYBRAKDEMON_VILE_EXPLOSION)
	S_StartSound(h, sfx_brakrx) S_StartSound(h, sfx_bsnipe)
	P_Thrust(h, R_PointToAngle2(h.x, h.y, v.x, v.y), 30*FRACUNIT)
	h.momz = 45*FRACUNIT
	h.fuse = 300
	P_SpawnGhostMobj(h)
	return
	end
end

addHook("MobjCollide", RoboCollide2, MT_EGGROBO1)
addHook("MobjMoveCollide", RoboCollide2, MT_EGGROBO1)

addHook("MobjMoveCollide", function(h, v)
if not (h or h.player)
return end
if not (v and v.valid)
return end
local p = h.player
//Don't collide with the thing you're picking up.

	if h.skin == "sms"
	and not (h.z > v.z+v.height)
	and not (v.z > h.z+h.height)
		if (v.flags & MF_SPRING) //Cut a few things out if you've hit a spring.	
			if p.homing
			and ((p.cmd.buttons & BT_CUSTOM1) or (p.autoc1mom and (p.autoc1mom == 1)) or ((p.autoc1mom and (p.autoc1mom == 2)) and (((p.cmd.forwardmove > 25) and not (p.pflags & PF_ANALOGMODE)) or ((p.cmd.sidemove or p.cmd.forwardmove) and (p.pflags & PF_ANALOGMODE))))) //Keep homing momentum
			p.homing = 0
			p.homingtrickcharge = 0
			h.momx = $*3/4
			h.momy = $*3/4
			elseif ( (p.sms_stompanim or p.sms_afterstompthok or p.smsatomdivestun or p.smsdivetimer or (h.state == S_SMS_ATOMLAND1) or (h.state == S_SMS_ATOMLAND2) or (h.state == S_HMS_ATOMLAND)
			or (h.sms_juststomped and h.sms_juststomped > 4) or (h.stompanimburst and h.stompanimburst > 14))
			or (p.hypermysticsonic and h.hmsspinpass) or (v.info.damage and h.state == S_SMS_AIRBOOST and p.speed > 40*FRACUNIT)) and v.info.mass

				h.vertstrongspring = true
				S_StartSound(h, sfx_sprong)
				if v.info.damage
				h.horstrongspring = true
				A_SMSquake(h, 25*FRACUNIT, 8, 350, true)
				else
				A_SMSquake(h, 55*FRACUNIT, 5, 350, true)
				end
				v.novawave = P_SpawnMobj(v.x, v.y, v.z, MT_HMSNOVAWAVE)
		  		v.novawave.scale = v.scale/4
		 		v.novawave.tics = 4
		  		v.novawave.destscale = v.novawave.scalespeed+1
		  		v.novawave.color = v.color
				
			elseif ((p.pflags & PF_SPINNING) and not (p.pflags & PF_JUMPED) or p.footsweepanim or (p.sms_boostlevel and p.sms_boostlevel >= 65))
			and not v.info.mass
				h.vertstrongspring = true
				h.horstrongspring2 = true
				S_StartSound(h, sfx_sprong)
				A_SMSquake(h, 45*FRACUNIT, 7, 350, true)
				v.novawave = P_SpawnMobj(v.x, v.y, v.z, MT_HMSNOVAWAVE)
				v.novawave.rollangle = ANGLE_90
		  		v.novawave.scale = v.scale/8
		 		v.novawave.tics = 4
		  		v.novawave.destscale = v.novawave.scalespeed+1
		  		v.novawave.color = v.color
			end
			h.sdodgeoh = 0
			p.smsrdash = 0
			p.lightdashstart = 0
			h.smsrdash = 0
			h.lastldrx = 0
			h.lastldry = 0
			h.ldclosest = nil
			p.smsdivetimer = 0
			p.smsdivefloat = 0
			p.smsdivedelay = 0
			p.smsatomdivestun = nil
			p.smsatomicdivefail = 0
			p.sms_jumphold = 10
				
			if h.player.footsweepanim
				h.player.footsweep01 = 0
				h.player.footsweep02 = 0
				h.player.footsweep03 = 0
				h.player.footsweepanim = false
				h.player.sweepanimrecovery = 0
				if not (h.player.pflags & PF_SPINNING)
				h.height = P_GetPlayerHeight(h.player)
				end
			end
		end
		if ((v.type == MT_SALOONDOOR) or (v.type == MT_SALOONDOORCENTER))
			if v.valid and v.health and (h.state == S_SMS_AIRBOOST 
			or h.player and (h.player.footsweepanim or h.player.hypermysticsonic or h.player.pflags & PF_SPINNING or (h.player.sms_transformstate and h.player.powers[pw_carry] == CR_MINECART)))
			and not (v.flags & MF_NOCLIP)
				if h.player.hypermysticsonic
				S_StartSound(h, sfx_nerf)
				v.hh = P_SpawnMobj(v.x, v.y, v.z, MT_BOSSEXPLODE)
				v.hh.scale = $*6
				A_SMSquake(h, 85*FRACUNIT, 6, 1999)
				else
				A_SMSquake(h, 75*FRACUNIT, 5, 999)
				S_StartSound(h, sfx_bowl)
				v.hh = P_SpawnMobj(v.x, v.y, v.z, MT_BOSSEXPLODE)
				v.hh.scale = $*2
				end
				if (v.type == MT_SALOONDOOR)
				v.flags = $|MF_NOCLIP
				P_KillMobj(v, h, h)
				elseif (v.type == MT_SALOONDOORCENTER)
				v.flags = $|MF_NOCLIP
				end
				return false
			end
		end
	end
	if h.player.smspickup
		if (v == h.player.smspickup)
			return false
		end
	end
	if not (h.player.hypermysticsonic)
	return end
		if (v.valid and v.type == MT_EGGSHIELD and v.health)
			if not (h.z > v.z+v.height)
			and not (v.z > h.z+h.height)
			and not (v.info.mass == 2006)
				P_KillMobj(v, h, h)
				return false
			end
		end
end, MT_PLAYER)

//If SMS goes reaaally fast or spins, go kill some spikes!

local function SMSSpikeCollide(s, sp)
	if not (s.skin == "sms")
	return
	end
	if not (sp and sp.valid and ((sp.type == MT_SPIKE) or (sp.type ==  MT_WALLSPIKE)))
	return
	end
	//I'd add a speed requirement, but the colission seems to get buggy.
	if not (s.player and ((s.player.pflags & PF_SPINNING or s.player.powers[pw_sneakers] or s.player.footsweepanim or s.player.smsblastboost1 or (s.player.sms_boostlevel > 64)) or s.player.hypermysticsonic))
	return
	end
		if s.player.hypermysticsonic or (sp.type == MT_WALLSPIKE) //HMS' spike collide needs to be different. He can fall through it.
			if (s.z > sp.z+sp.height+111*FRACUNIT)
			or (sp.z > s.z+s.height+111*FRACUNIT)
			return false
			else
			P_KillMobj(sp, s, s)
			return false
			end
			return false
		else
			if (s.z > sp.z+sp.height)
			or (sp.z > s.z+s.height)
			return false
			else
			P_KillMobj(sp, s, s)
			return false
			end
			return false
		end
	return false
end

addHook("MobjCollide", SMSSpikeCollide, MT_PLAYER)
addHook("MobjMoveCollide", SMSSpikeCollide, MT_PLAYER)

//A seperate hitbox to go with thrown items, letting you hurt enemies by throwing crap at them.
local function ThrowTrackerCollide(s, v)
	if not s and ((s.smsthrow and s.smsthrowog) or (s.hmsthrow and s.hmsthrowog))
	return false
	elseif s and s.homingbounce
	return false
	elseif s and not s.target or (s and s.target and v and v == s.target)
	return false
	end
	if v and v.valid and v.health and ((v.flags & (MF_ENEMY|MF_BOSS)) and (v.flags & MF_SHOOTABLE))
	or v and v.valid and (v.flags & MF_MONITOR)
		if (s.z > v.z+v.height+30*FRACUNIT) //Grant a little leeway with the vertical colission
		or (v.z > s.z+s.height+30*FRACUNIT)
		return false
		end
		if (s.target.flags & MF_SPRING) //Extra feature for debug mode.
			s.target.momx = 0
			s.target.momy = 0
			s.target.momz = 0
			s.target.rollangle = 0
			P_InstaThrust(v, s.target.angle, mobjinfo[s.target.type].damage)
			P_SetObjectMomZ(v, mobjinfo[s.target.type].mass, true)
			if mobjinfo[s.target.type].seestate
			s.target.state = mobjinfo[s.target.type].seestate
			end
			if mobjinfo[s.target.type].painsound
			S_StartSound(s.target, (mobjinfo[s.target.type].painsound))
			end
			return false
		else
			s.homingbounce = 1
			v.mhomingbounced = 1
			if s.smsthrowog and s.smsthrowog.mo
				if (v.flags & MF_MONITOR)	
				P_KillMobj(v, s.target, s.smsthrowog.mo)
				else
				P_DamageMobj(v, s.target, s.smsthrowog.mo)
				end
				return false
			elseif s.hmsthrowog and s.hmsthrowog.mo
			P_KillMobj(v, s.target, s.hmsthrowog.mo)		
			end
			return false
		end
		return false
	end
end

addHook("MobjCollide", ThrowTrackerCollide, MT_SMSTHROWTRACKER)
addHook("MobjMoveCollide", ThrowTrackerCollide, MT_SMSTHROWTRACKER)

//Make sure Sonic can only boost himself in NiGHTs.

local function SonicFboost(s, v)
	if s and (s.nsonicb and v and v != s.nsonicb)
	return false
	end
end

addHook("MobjCollide", SonicFboost, MT_NIGHTSBUMPER)
addHook("MobjMoveCollide", SonicFboost, MT_NIGHTSBUMPER)

//Collision check for rings and other fun things.
//Can't use thinkers.iterate or the game'll lag in big levels.

local function smsecheck(s, m)
	if s and s.target and s.target.player 
		if s and m
		 if s.hmsspincheck //Copy of CMPH, only minor differences.
		 	if s.target.player.starthmscombo
			return
			end
			if G_GametypeHasSpectators() and m.player and (((FixedHypot(FixedHypot(m.x-s.x, m.y-s.target.y), m.z-s.target.z)) < 600*FRACUNIT) or s.hmsspincheck2)
			elseif (m.dummyhbx and m.target)
			elseif (m.flags & MF_MONITOR) and not s.hmsspincheck2
			elseif not ( (m.flags & MF_BOSS) or ((m.flags & MF_ENEMY) and m.health) or m.type == MT_EGGGUARD or m.type == MT_CYBRAKDEMON or m.type == MT_MINUS)
			or m.fusrodah
			return
			end
				if not (m.z > s.z+s.height)
				and not (m.z+m.height < s.z)
				and not (m == s.target) and not (m == s) 
				 if s.hmsspincheck2
					if (m.type == MT_BIGMINE) //m.type == MT_GSNAPPER or m.type == MT_DRAGONBOMBER or
					or (m.health <= 0)or not (m.flags & MF_SHOOTABLE) and not m.dummyhbx
				 	return //These cause lag or other issues.
					end
				 end
					if not s.target.hmsspinclosest or ( s.target.hmsspinclosest and ((FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) < s.target.hmsspinclosest) )
						if (P_CheckSight(s.target, m))
							if m.dummyhbx and m.target
							s.target.hmsspinclosest = (FixedHypot(FixedHypot(m.target.x-s.x, m.target.y-s.y), m.target.z-s.z))
								if s.hmsspincheck2
								s.target.hmsspint2 = m.target 	
								else
								s.target.hmsspint = m.target
								end
							
							elseif not m.dummyhbx
							
							s.target.hmsspinclosest = (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z))
								if s.hmsspincheck2
								s.target.hmsspint2 = m 
								else
								s.target.hmsspint = m
								end
							end
						end
					end
				end
			return
		 elseif s.lsasms
			if not (((m.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR)) or (m.type == MT_EGGGUARD) or (((m.type == MT_CYBRAKDEMON) or (m.type == MT_MINUS)))) and m.health and (m.flags & MF_SHOOTABLE 
			or (((m.type == MT_CYBRAKDEMON) or (m.type == MT_MINUS) or (m.type == MT_EGGGUARD)))) and not (m.type == MT_DETON) and not m.fusrodah and not (m.flags2 & MF2_FRET))
			return
			end
				if not (m.z > s.z+s.height)
				and not (m.z+m.height < s.z)
				and (P_CheckSight(s.target, m))
					if s.justcheckin
					s.target.smslsaret = 2
					else
						if not s.target.lsaclosest or ( s.target.lsaclosest and ((FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) < s.target.lsaclosest) )
						s.target.lsaclosest = (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z))
						s.target.smslsacheck = 3
						s.target.target = m
						s.target.lsatarget = m
						end
					end
				end
		elseif s.cmphsms or s.cmphhms
			if m.dummyhbx and m.target
			elseif not (((m.flags & (MF_ENEMY|MF_BOSS)) or (m.type == MT_EGGGUARD) or (((m.type == MT_CYBRAKDEMON) or (m.type == MT_MINUS)))) and m.health and (m.flags & MF_SHOOTABLE 
			or (((m.type == MT_CYBRAKDEMON) or (m.type == MT_MINUS) or (m.type == MT_METALSONIC_BATTLE) or (m.type == MT_EGGGUARD)))) and not (m.type == MT_DETON) and not m.fusrodah and not (m.flags2 & MF2_FRET))
			return
			end
				if not (m.z > s.z+s.height)
				and not (m.z+m.height < s.z)
				and not (m == s.target) and not (m == s) //Not the checker or its player source
				and not (m.info.mass == 2006) //Immunity
				//Can SMS see the mobj?
					if s.justcheckin
						if (P_CheckSight(s.target, m))
						s.target.smscmphret = 1
						end
					else
						if not s.target.cmphclosest or ( s.target.cmphclosest and ((FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) < s.target.cmphclosest) )
						  if (P_CheckSight(s.target, m))
							if m.dummyhbx and m.target // and s.cmphhms --Underground or electrified? Don't care. Punch 'em anyway.
							s.target.cmphclosest = (FixedHypot(FixedHypot(m.target.x-s.x, m.target.y-s.y), m.target.z-s.z))
							s.target.smshmcheck = 2
							s.target.target = m.target
							s.target.cmphtarget = m.target
							elseif not m.dummyhbx
							
							s.target.cmphclosest = (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z))
							s.target.smshmcheck = 2
							s.target.target = m 
							s.target.cmphtarget = m
							end
						  end
						end
					end
				end
			return
		elseif s.smsepickup
			if not (m and (((m.flags & MF_PUSHABLE) and (m.flags & MF_SOLID))
			or (s.target.player.glitchydebugthrow and not m.player) or ( (m.type == MT_LITTLETUMBLEWEED or m.type == MT_BIGTUMBLEWEED or m.type == MT_ROLLOUTROCK or m.type == MT_GARGOYLE or m.type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE
			or m.type == MT_CYBRAKDEMON_NAPALM_BOMB_SMALL or m.type == MT_SHELL or (m.type == MT_MINECART and m.target and m.target.player)) ) or m.smscustompickup or m.carthrust //For custom Lua pickups.
			or (((m.flags & MF_MONITOR) or (m.type == MT_PLAYER and m.iasmsp and m.iasmsp > 101 and not m.hmspickedup and not (m.player and (m.player.hypermysticsonic or m.player.powers[pw_carry] or (m.player.pflags & PF_CANCARRY) or s.target.player.bot)) )) and m.health))
			and not (s.target.player.smspickup and m == s.target.player.smspickup) and not (s == m)) then
			return
			end
			if ((m.type >= MT_PITY_GOLDBOX) and (m.type <= MT_THUNDERCOIN_GOLDBOX)) //Can't carry infinite shields/invincibility with you.
			return //Let's not repeat the same mistake I made with SMSblast
			end

			if not (m == s.target) and not (m == s)
			and (P_CheckSight(s.target, m))
			and not (m.z > s.z+s.height)
			and not (m.z+m.height < s.z)
			and m.valid and m.health // and not m.cmphtimer
			and not (s.target.player.smspickup and s.target.player.smspickup.valid)
			and not s.target.player.powers[pw_carry] and not s.target.DeyCURollin
			and not s.target.iampickedupbysmshelp
			  if s.justcheckin
			  s.target.smspkuret = 1
			  	if (s.target.player.sms_flamedelay <= 2) and not (s.target.state == S_HMSNOVAFIRE2) and not (s.target.player.cmd.buttons & BT_FIRENORMAL)
			  	s.target.player.sms_flamedelay = 2
			  	end
			  	if (s.target.player.hms_gravburstcd == nil or s.target.player.hms_gravburstcd <= 2)
			 	 s.target.player.hms_gravburstcd = 2
			  	end
			  else
			  	if not s.target.smpkclosest or ( s.target.smpkclosest and ((FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z)) < s.target.smpkclosest) )
					s.target.smpkclosest = (FixedHypot(FixedHypot(m.x-s.x, m.y-s.y), m.z-s.z))
					s.target.smpktarget = m
					if (s.target.player.sms_flamedelay <= 2)
			  		s.target.player.sms_flamedelay = 15
			  		end
			  		if (s.target.player.hms_gravburstcd == nil or s.target.player.hms_gravburstcd <= 2)
			 	 	s.target.player.hms_gravburstcd = 15
			  		end
					s.target.player.sms_nflamehold = 10
					s.target.player.sms_flamebuttonhold = 10
					s.target.player.sms_tossflaghold = 10
					s.target.player.weaponprevhold = 10
				end
			  end
			end
		elseif s.hmstornado //Pretty simple code all things considered...
			if not (m and m.valid)
			return false
			elseif not ( (m.flags & (MF_ENEMY|MF_BOSS)) or (m.player and not m.player.hypermysticsonic) or (m.type == MT_METALSONIC_BATTLE) or (m.type == MT_EGGGUARD) or (m.type == MT_SMSDUMMYTRACKER)
			or (m.type == MT_SMSRGORE) or ((m.type >= MT_FLICKY_01) and (m.type < MT_SEED)) or (m.type == MT_DETON) or (m.type == MT_ROSY) or (m.type == MT_CYBRAKDEMON) or (m.type == MT_MINUS) )
			return false
			end
			if m.player and m.health and s.target and not (m == s.target) and (FixedHypot(s.target.x-m.x, s.target.y-m.y) < 1200*FRACUNIT)
					local z = m.player			
							if m.valid //Paranoia
							m.momz = $+76000
								if z.panim == PA_WALK or z.panim == PA_IDLE or z.panim == PA_RUN
								z.pflags = $|PF_JUMPED 
									if not m.hmstorvictim //Help! We're getting sucked in!
									S_StartSound(m, sfx_s3kcel)
									m.momx = $/2
									m.momy = $/2
									m.hmstorvictimang = z.drawangle
									P_Thrust(m, R_PointToAngle2(m.x, m.y, s.target.x, s.target.y), 6*FRACUNIT)
									end
									if (z.charflags & SF_NOJUMPSPIN)
									m.state = S_PLAY_SPRING
									else
									m.state = S_PLAY_ROLL
									end
								end
								if m.z < m.ceilingz-300*FRACUNIT
									m.momx = $*100/99
									m.momy = $*100/99
									P_Thrust(m, R_PointToAngle2(m.x, m.y, s.target.x, s.target.y), 10*FRACUNIT) //Suck in
								end
							P_Thrust(m, R_PointToAngle2(m.x, m.y, s.target.x, s.target.y)-ANGLE_90+ANG2, 85000) //Tornadoooo
							m.hmstorvictim = 7
							end
						return false
							
			elseif (m.type == MT_SMSDUMMYTRACKER) and m.target and m.target.valid
				m.target.momz = $+4*FRACUNIT
				if (m.target.z < m.target.ceilingz-300*FRACUNIT)
					P_Thrust(m, R_PointToAngle2(m.target.x, m.target.y, s.target.x, s.target.y), 36*FRACUNIT) //Suck in
				else
					P_Thrust(m, R_PointToAngle2(m.target.x, m.target.y, s.target.x, s.target.y), -8*FRACUNIT) //Shoot out
				end
				P_Thrust(m, R_PointToAngle2(m.target.x, m.target.y, s.target.x, s.target.y)-ANGLE_90+ANG2, 12*FRACUNIT) //Tornadoooo
				m.target.angle = $+ANGLE_45
			else
				m.momz = $+4*FRACUNIT
				if (m.z < m.ceilingz-300*FRACUNIT)
					P_Thrust(m, R_PointToAngle2(m.x, m.y, s.target.x, s.target.y), 36*FRACUNIT) //Suck in
				else
					P_Thrust(m, R_PointToAngle2(m.x, m.y, s.target.x, s.target.y), -8*FRACUNIT) //Shoot out
				end
				P_Thrust(m, R_PointToAngle2(m.x, m.y, s.target.x, s.target.y)-ANGLE_90+ANG2, 12*FRACUNIT) //Tornadoooo
				m.angle = $+ANGLE_45
			end
			return false
		 else
			if ((m.type == MT_RING) or (m.type == MT_COIN) or (m.type == MT_BLUESPHERE))
			and m.health and (P_CheckSight(s.target, m))
			and not (s.target.player.smspickup and (s.target.player.smspickup == m)) 
				if (s.z > m.z+m.height)
				or (m.z > s.z+s.height)
				return false
				end
				if s.justcheckin
				s.target.smsldret = 1
				else
					if s.target.ldclosest == nil or ( s.target.ldclosest and ( (FixedHypot(m.x-s.x, m.y-s.y)) <= s.target.ldclosest) )
					s.target.ldclosest = (FixedHypot(m.x-s.x, m.y-s.y))
					s.target.target = m
					s.target.smsrdash = m
					return false
					end
				end
			end
		 end
		end
	end
	return false
end

addHook("MobjCollide", smsecheck, MT_SMSECHECK)
addHook("MobjMoveCollide", smsecheck, MT_SMSECHECK)

//Kick the TNT barrels!

addHook("MobjThinker", function(sp)
		if sp.tntdelayexp
			sp.tntdelayexp = $-1
			if sp.tntdelayexp == 1
			sp.flags = MF_MISSILE|MF_NOBLOCKMAP
			sp.momz = $-1
			sp.momy = $-1
			sp.momx = $-1
			end
		end
end, MT_TNTBARREL)

addHook("MobjDeath", function(sp, i, s)
	if sp and sp.valid and s and s.player and (s.player.footsweepanim or s.player.hypermysticsonic)
		P_SetObjectMomZ(sp, 12*FRACUNIT, false)
			if (s.player.speed < 16*FRACUNIT)
			P_Thrust(sp, R_PointToAngle2(s.x, s.y, sp.x, sp.y), 15*FRACUNIT)	
			else
			P_Thrust(sp, R_PointToAngle2(s.x, s.y, sp.x, sp.y), s.player.speed*10/8)
			end
			if not (sp.state == S_TNTBARREL_FLYING)	
			S_StartSound(sp, sfx_bowl)
			sp.state = S_TNTBARREL_FLYING
			end
		sp.health = 1
		sp.tntdelayexp = 4
		sp.flags = MF_NOBLOCKMAP
		return true
	end
end, MT_TNTBARREL)

//It feels evil to only include this for SMS, but hey, character mod, not game mod...

addHook("MobjDeath", function(s, i, so)
		if s and (s.type == MT_MINECART) and s.valid and s.target and s.target.player and s.target.skin == "sms" and s.target.health
			s.target.player.powers[pw_carry] = 0
			P_DamageMobj(s.target)
			s.target.momx = s.momx
			s.target.momy = s.momy
			P_SetObjectMomZ(s.target, 6*FRACUNIT, true)
				if s.target.player.sms_transformstate and (s.target.player.sms_transformstate == 1)
				s.target.player.sms_transformstate = 2
				end
			s.target = nil
		end
end, MT_MINECART)

//Death handles for SMS and the Mystic Supers

addHook("MobjDeath", function(s, i, so)
	if s.player
		if s.ibethrownbysmshelp and s.player.smsgriefw == nil and not s.player.smsdontgrabme
		s.player.smsgriefw = 180
		end
		if s.player.hypermysticsonic
		return true
		elseif s.player.smspickup and s.player.smspickup.valid and (i == s.player.smspickup or so == s.player.smspickup)
		return true
		elseif s.skin == "sms" and s and s.valid
			P_FlashPal(s.player, PAL_MIXUP, 3)
			S_StartSound(s, sfx_s3k66)
			for d = 0,15
				P_SpawnParaloop(s.x, s.y, s.z+s.momz+s.height*2, 10*FRACUNIT, 16, MT_NIGHTSPARKLE, d*ANGLE_22h, S_SMSTSPARK1, false)
			end
			return
		elseif s.player.mysticsuper
		A_ENDMYSTICSUPER(s)
		return
		end
	end
end, MT_PLAYER)


//Bounce off monitors when hometricking, and dodge through shields

addHook("MobjMoveCollide", function(s, m)
	if s.player and s.player.hometrickanim and (s.skin == "sms")
		if m and (m.flags & MF_MONITOR) and m.health and not (m.flags & MF_ENEMY)
			if not (s.z < m.z)
			and not (s.z > m.z+m.height)
			s.player.hometrickanim = false
			s.player.pflags = $|PF_JUMPED
			s.state = S_PLAY_ROLL
			return false
			end
		return false
		end
	end
end,  MT_PLAYER)

//SMS dodges through you

local function ShieldNopeS(s, so)
	if so and so.player and (so.player.sms_dodging and so.player.sms_dodging > 3)
	return true
	end
end

local function ShieldNope(s, so)
	if so and so.player and (so.player.sms_dodging and so.player.sms_dodging > 3)
		return false
	end
end

addHook("TouchSpecial", ShieldNopeS,  MT_EGGSHIELD)
addHook("MobjCollide", ShieldNope,  MT_EGGSHIELD)

addHook("MobjCollide", function(s, m)
	if (s.player.sms_dodging and (s.player.sms_dodging > 3))
	and not s.player.powers[pw_invulnerability]
		if (m.valid and m.flags & MF_MISSILE)
		and not (m.type == MT_DETON) and s.skin == "sms" //Destroy detons with dodges.
			return false
		end
	end
	if not s.player or not s.player.hypermysticsonic
	return nil
	end
	if (m and m.valid and (m.flags & MF_MISSILE))
	and not ((m.z > s.z+s.height) or (m.z < s.z))
	and not (m.target and m.target == s)
	and not m.disappeartimer
	and not (m.info.speed == 0)
	and not (m.type == MT_HMSNOVABLAST) and not (m.type == MT_HMS_NAPALM_FLAMES) //No way....you can't reflect something like that.
		m.rvgtracker = P_SpawnMobj(m.x, m.y, m.z, MT_RVGMISSILE)
		m.rvgtracker.target = m
		m.rvgtracker.tracer = s
		m.boomerangtarget = m.target
		m.disappeartimer = 275
		m.target = s
		S_StartSound(m, sfx_zoom)
		m.thokspawner = P_SpawnMobj(m.x, m.y, m.z, MT_BURSTLIGHT)
		m.thokspawner.color = SKINCOLOR_YELLOW
		m.momx = (m.momx*-1)
		m.momy = (m.momy*-1)
		m.momz = (m.momz*-1)
		return false
	end
end, MT_PLAYER)

//Of course, all of HMS' projectiles murder stuff too, so let's get that working.

addHook("MobjMoveCollide", function(s, v)
		if v.player and (gametype == GT_COOP)
		and ( (v.player.knucklewaving or v.player.iamcarryingsms)
		or ((v.player.powers[pw_carry] == CR_PLAYER) and v.tracer and s.target and (s.target == v.tracer)) )			
		return false
		end
		if (s.z > v.z+v.height)
		or (v.z > s.z+s.height)
		return nil end
		if (v.flags & (MF_ENEMY|MF_BOSS)) //Specifically things with these flags die too.
		or (v.type == MT_TURRET)
		or (v.type == MT_CYBRAKDEMON_ELECTRIC_BARRIER)
		or (v.type == MT_EGGSHIELD)
			if v.health
			and not (v.info.mass == 2006)
				if s.target
				P_KillMobj(v, s, s.target)
				else
				P_KillMobj(v, s, s)
				end
			end
		end
end, MT_HMSFIREBLAST)

local function NovaCollide(s, v)
	if (s.type == MT_HMSNOVABLASTHB) and s.hmstarget and s.hmstarget.battlemodsms and v and v.player  //You're a real pain in the neck, Battlemod
	and not ( (s.hmstarget.player and s.hmstarget.player.ctfteam) and (s.hmstarget.player.ctfteam == v.player.ctfteam) )
	and not (s.z > v.z+v.height)
	and not (v.z > s.z+s.height) 
	P_DamageMobj(v, s.hmstarget, s.hmstarget)
	return false
	end
	if v.player and (gametype == GT_COOP) 
	and ( (v.player.knucklewaving) or ((v.player.powers[pw_carry] == CR_PLAYER) and v.tracer and s.target and (s.target == v.tracer)) )	
	return false
	end
	if not (s.z > v.z+v.height)
	and not (v.z > s.z+s.height)
		if (v.flags & (MF_ENEMY|MF_BOSS))
		or (v.type == MT_TURRET) or (v.type == MT_CYBRAKDEMON_ELECTRIC_BARRIER) or (v.type == MT_EGGSHIELD)
			if v.health
			and not (v.info.mass == 2006)
				if (s.type == MT_HMSNOVABLASTHB)
					P_KillMobj(v, s.novatarget, s.hmstarget)				
				else
					if s.target
					P_KillMobj(v, s, s.target)
					else
					P_KillMobj(v, s, s)
					end
				end
			end
			if (s.type == MT_HMSNOVABLASTHB) and s.novatarget and s.novatarget.valid and (s.novatarget.state == S_NOVABLAST)
			P_ExplodeMissile(s.novatarget)
			return
			end
		//Enjoy invincibility.....all the while you're going STRAIGHT TO HELL!! --Shadow
		elseif G_GametypeHasSpectators() and v and v.player
			if (v.player.powers[pw_invulnerability] > 2)
			and not v.player.hypermysticsonic // Unstoppable Force vs Immovable Object is the same as dividing by 0
				if (s.type == MT_HMSNOVABLAST) and not ( (s.target and s.target.player and s.target.player.ctfteam) and (s.target.player.ctfteam == v.player.ctfteam) )
				or (s.type == MT_HMSNOVABLASTHB) and not ( (s.hmstarget and s.hmstarget.player and s.hmstarget.player.ctfteam) and (s.hmstarget.player.ctfteam == v.player.ctfteam) )
				v.player.powers[pw_invulnerability] = 2 //Invincibility's merely relative.
				return
				end
			end
		end
	end
end

addHook("MobjCollide", NovaCollide, MT_HMSNOVABLASTHB)
addHook("MobjMoveCollide", NovaCollide, MT_HMSNOVABLASTHB)
addHook("MobjMoveCollide", NovaCollide, MT_HMSNOVABLAST)

//Like the Novablast, HMS' Galaxy Storm has an invisible hitbox following it to avoid walls stopping it.

local function GaxCollide(s, v)
if (v and (v.type == MT_HMSGAXHB) or v.hmsgaxed)
or (s and (s.hmstarget and v and (v == s.hmstarget)))
return false //Don't bother.
end
	if (v.player and (gametype == GT_COOP))
	return false
	elseif not (((s.z-500*FRACUNIT > v.z+v.height) and s.gaxhbphase2) or (s.z > v.z+v.height) and not s.gaxhbphase2)
	and not (v.z > s.z+s.height)
		if (v.flags & MF_ENEMY) or (v.flags & MF_BOSS)
		or (v.type == MT_TURRET) or (v.type == MT_CYBRAKDEMON_ELECTRIC_BARRIER) or (v.type == MT_EGGSHIELD)
		or (v.player and ( G_GametypeHasSpectators() or v.battlemodsms) and not v.player.hypermysticsonic and not v.player.powers[pw_flashing])
			if not (v.info.mass == 2006)
			and (v.health or (v.flags & MF_BOSS))
				if s.gaxhbphase2
					s.tsp = P_SpawnMobj(v.x, v.y, v.z, MT_HMSGAXT)
					s.tsp.oggax = s.novatarget
					s.tsp.hmstarget = s.hmstarget
					s.tsp.gaxedboi = v
					v.hmsgaxed = true //You got gaxed
					return false
				else //Hacky way of dealing damage that won't cause sigsevs.
					if s.hmstarget
					P_NukeEnemies(s, s.hmstarget, 400*FRACUNIT)
					else
					P_NukeEnemies(s, s, 400*FRACUNIT)
					end
					if v and v.valid and v.player
					P_InstaThrust(v, v.angle, -80*FRACUNIT)
					return false
					end
				end
			end
		end
	end
	return false
end

addHook("MobjCollide", GaxCollide, MT_HMSGAXHB)
addHook("MobjMoveCollide", GaxCollide, MT_HMSGAXHB)

local function BalloonCollide(s, so)
	if s and s.health and (s.state != s.info.deathstate)
		if so and so.player
			if so.skin == "sms" and not so.player.hypermysticsonic
			and (so.z <= s.z + s.height)
			and (s.z <= so.z + so.height)
			and so.health
			so.rollangle = 0
			so.state = S_PLAY_ROLL
			so.player.homingtrickcharge = 4
			so.forcesmstrick = true
			end
		end
	end
end
addHook("MobjCollide", BalloonCollide, MT_BALLOON)
addHook("MobjMoveCollide", BalloonCollide, MT_BALLOON)

addHook("MobjCollide", function(p, f)
	if not G_GametypeHasSpectators()
	return end
	if f.valid and not (f.type == MT_FLINGRING)
	return end
	if f.valid and f.cmphflung
	return false end
		if p and ((p.state == S_SMSCOMETHAYMAKER2) or (p.state == S_HMSCOMETHAYMAKER2))
			f.angle = p.angle
			f.cmphflung = 7
			return false
		end
end,  MT_PLAYER)

addHook("MobjMoveCollide", function(p, f)
	if not G_GametypeHasSpectators()
	return end
	if f.valid and not (f.type == MT_FLINGRING)
	return end
	if f.valid and (f.cmphflung)
	return false end
		if p and ((p.state == S_SMSCOMETHAYMAKER2) or (p.state == S_HMSCOMETHAYMAKER2))
			f.angle = p.angle
			f.cmphflung = 7
			return false
		end
end, MT_PLAYER)

local function SmokeCollide(s, v)
if v and s.target and s.target == v
return false
end
	if ((v.type == MT_SPIKE) or (v.type == MT_WALLSPIKE))
	and not ((s.z > v.z+v.height+20*FRACUNIT) or (s.z+s.height+20*FRACUNIT < v.z))
	P_KillMobj(v, s, s.target)
	return
	end
	if not ((s.z > v.z+v.height) or (s.z+s.height < v.z))
		if v.valid and v.health and ((v.flags & MF_ENEMY) or (v.flags & MF_BOSS))
		and not (v.type == MT_TNTBARREL)
		P_DamageMobj(v, s, s.target)
		return
		end
		if G_GametypeHasSpectators()
		and v.valid and v.player and v.health 
		and not (G_GametypeHasTeams() and (v.player.ctfteam and (s.target.player.ctfteam == v.player.ctfteam)))
			if not v.player.hypermysticsonic and not v.player.powers[pw_super]
			and not (s.smssmmk and ((s.state == S_SMMK5) or (s.state == S_SMMK4) or (s.state == S_SMMK3)))
				if s.target.battlemodsms
				P_DamageMobj(v, s.target, s.target) //Direct damage since battlemod will try to say otherwise.
				else
				P_DamageMobj(v, s, s.target)
				end
				v.player.weapondelay = 25
				v.player.sms_flamedelay = 25
				return
			elseif not v.player.hypermysticsonic and not v.player.powers[pw_super] and not s.smssmmk //No special knockback for stomps.
				P_InstaThrust(v, v.angle, -20*FRACUNIT)
				P_SetObjectMomZ(v, 8*FRACUNIT)
				v.player.pflags = $|PF_JUMPED //Let's not kill Super players by kicking them off cliffs...
				return
			end
		end
		if (v.valid and v.health and v.flags & (MF_MONITOR))
		and not s.smssmmk
			P_KillMobj(v, s, s.target)
			return
		end
	else
		return false
	end
end

addHook("MobjCollide", SmokeCollide, MT_SMMK)
addHook("MobjMoveCollide", SmokeCollide, MT_SMMK)

//Make Rollout Rocks go faster if SMS holds CUSTOM1

addHook("MobjThinker", function(s)
	if s and s.valid
		if s.tracer and s.tracer.valid and s.tracer.skin != "sms"
		return
		end
		if s.iampickedupbysmshelp
		s.iampickedupbysmshelp = $-1
		end
		if s.tracer and s.tracer.valid and s.tracer.skin == "sms" and s.tracer.player 
		s.tracer.DeyCURollin = 8
		 if s.tracer.player.powers[pw_carry] == CR_ROLLOUT
local p = s.tracer.player
local t = s.tracer //Shorten things for convenience and filesize
			if s.nomyman
			s.nomyman = $-1
			end
			if (p.cmd.buttons & BT_CUSTOM1) and not (p.cmd.buttons & BT_JUMP) and not s.nomyman and not s.iampickedupbysmshelp
				if not ( P_TryMove(s, t.x+FixedMul(85355, cos(t.angle)), t.y+FixedMul(85355, sin(t.angle)), true) )
				p.powers[pw_carry] = 0
				t.momz = s.momz
				S_StartSound(s, sfx_s3k49)
				s.nomyman = 6
				s.flags = $|MF_PUSHABLE
				t.target = s
				s.tracer = nil
				return
				end
				if not ( P_TryMove(t, t.x+FixedMul(85355, cos(t.angle)), t.y+FixedMul(85355, sin(t.angle)), true) )
				p.powers[pw_carry] = 0
				t.momz = s.momz
				s.flags = $|MF_PUSHABLE
				S_StartSound(s, sfx_s3k49)
				s.nomyman = 6
				t.target = s
				s.tracer = nil
				return
				end
				
				P_Thrust(s, t.angle, 105355)
				if not p.hypermysticsonic
				t.state = S_PLAY_ROLL //Go into rolling frames for boosting.
				p.pflags = $|PF_JUMPED
				P_SpawnGhostMobj(s)
				t.rorg2t = P_SpawnGhostMobj(t)
				t.rorg2t.frame = t.frame
				t.rorg2t.tics = 3
				else
				t.rorg2t = P_SpawnGhostMobj(t)
				t.rorg2t.sprite = SPR_HMSO
					if leveltime % 2 == 0
					t.rorg2t.frame = C
					else
					t.rorg2t.frame = L
					end
				end
				if (s.eflags & MFE_UNDERWATER) //Don't disappear under sloped lava so easily!
				P_SetObjectMomZ(s, FRACUNIT*4, true)
				P_SetObjectMomZ(t, FRACUNIT*4, true)
				end
				if not s.smssoundplayed2
				S_StartSound(s, sfx_zoom)
					if p.hypermysticsonic
						S_StartSound(s, sfx_smach)
						A_SMSquake(t, 54*FRACUNIT, 4, 1200)
						t.hudboost = 1
						P_RadiusAttack(t, t, FixedMul(480*FRACUNIT, s.scale))
						p.smsradialboosteffect = P_SpawnMobj(t.x, t.y, t.z, MT_RADIALBOOST)
						p.smsradialboosteffect.target = s
					end
				s.smssoundplayed2 = true
				end
			else
				if (p.pflags & PF_JUMPED)			
				p.pflags = $ & ~PF_JUMPED & ~PF_STARTJUMP & ~PF_SPINNING
				end
				if t.state == S_PLAY_ROLL
				t.state = S_PLAY_WALK
				p.pflags = $ & ~PF_JUMPED & ~PF_STARTJUMP & ~PF_SPINNING
				end
				if s.smssoundplayed2
				s.smssoundplayed2 = false
				end
			end
			if (p.cmd.buttons & BT_USE) and not (p.cmd.buttons & BT_CUSTOM1)
			P_Thrust(s, t.angle, 105355)
					if not p.hypermysticsonic
					t.rorg2t = P_SpawnGhostMobj(t)
					t.rorg2t.frame = t.frame
					t.rorg2t.tics = 3
					else
					t.rorg2t = P_SpawnGhostMobj(t)
					t.rorg2t.sprite = SPR_HMSO
					if leveltime % 2 == 0
					t.rorg2t.frame = C
					else
					t.rorg2t.frame = L
					end
					t.rorg2t.tics = 3
					end
				if (t.tics > 1)
				t.tics = 1
				end
				if (s.eflags & MFE_UNDERWATER)
				P_SetObjectMomZ(s, FRACUNIT*2, true)
				P_SetObjectMomZ(t, FRACUNIT*2, true)
				end
				if not s.smssoundplayed
				S_StartSound(s, sfx_zoom)
				s.smssoundplayed = true
				end
			elseif s.smssoundplayed
			s.smssoundplayed = false
			end
			if p.smspickup and p.smspickup.valid and (p.smspickup == s)
			P_DoPlayerPain(p) //We can't carry each other at the same time
			end
		end
	  elseif s.tracer
	  s.tracer.target = s
	  s.flags = $|MF_PUSHABLE
	  s.tracer = nil
	  end
	end
end, MT_ROLLOUTROCK)
//Prevent a sigsev.
addHook("MobjRemoved", function(s)
	if s and s.tracer and s.tracer.valid and s.tracer.player and (s.tracer.player.powers[pw_carry] == CR_ROLLOUT)
		s.tracer.player.powers[pw_carry] = 0
		s.tracer = nil
		s.flags = $|MF_PUSHABLE
	return
	end
end, MT_ROLLOUTROCK)


//Speed up minecarts with SMS too.

addHook("MobjThinker", function(s)
	if s and s.valid and s.health and s.target
		if not s.gottoexist
		s.gottoexist = 1
		else
		s.gottoexist = $+1
		end
		if s.target.valid and s.target.skin == "sms" and s.target.player 
			if s.target.player.powers[pw_carry] == CR_MINECART
				if ((s.target.player.cmd.buttons & BT_USE) and not (s.target.player.sms_spinhold and s.target.player.sms_spinhold > 1))
				and (s.gottoexist > 40)
				s.target.player.powers[pw_carry] = 0
				s.target.player.pflags = $|PF_JUMPED
				s.target.momx = s.momx
				s.target.momy = s.momy
				P_DoJump(s.target.player, true)
				P_SetObjectMomZ(s.target, 8*FRACUNIT, true)
				s.target = nil
				return
				end
				if (s.target.player.cmd.buttons & BT_CUSTOM1) and (((s.gottoexist < 40) and P_IsObjectOnGround(s)) or s.target.player.hypermysticsonic)
					if (P_IsObjectOnGround(s) and not (s.target.player.cmd.sidemove)) or s.target.player.hypermysticsonic
					A_SMSquake(s.target, 37*FRACUNIT, 2, 500, true)
						if s.target.player.hypermysticsonic
						s.target.smsbaang = R_PointToAngle2(s.x, s.y, (s.x+s.momx), (s.y+s.momy))
						s.target.player.speed = 160*FRACUNIT
						s.target.smsspeedticket = true
						P_SpawnGhostMobj(s)
						P_SpawnGhostMobj(s.target)
						P_InstaThrust(s, s.angle, 160*FRACUNIT)
						else
						P_InstaThrust(s, s.angle, 32*FRACUNIT)
						end
					s.gottoexist = $+20
					end
					if s and s.valid and not s.smssoundplayed
						if s.target.player.hypermysticsonic
						s.target.hudboost = 1
						A_SMSSTOMPSMOKE(s.target, 30, MT_HMSLIGHTNING1, nil, nil, nil, SKINCOLOR_SKY)
						S_StartSound(s, sfx_smach)
						S_StartSound(s, sfx_bkpoof)
						P_NukeEnemies(s.target, s.target, 400*FRACUNIT)
						P_FlashPal(s.target.player, PAL_MIXUP, 3)
						end
					S_StartSound(s, sfx_zoom)
					s.smsaurablastspawn = P_SpawnMobj(s.x+(s.momx*2), s.y+(s.momy*2), s.z, MT_BURSTWAVE)
					s.smsaurablastspawn.color = SKINCOLOR_BONE
					s.smssoundplayed = true
					end
				elseif s.smssoundplayed and not (s.target.player.cmd.buttons & BT_CUSTOM1)
				s.smssoundplayed = false
				elseif s.target.player.hypermysticsonic
					if s.target.player.speed == 160*FRACUNIT 
					P_InstaThrust(s, s.angle, 32*FRACUNIT)
					end
				s.target.player.speed = 8*FRACUNIT
				end
				
				if (s.target.player.cmd.buttons & BT_CUSTOM1) and (s.gottoexist > 40) and not s.smssoundplayed and not s.target.player.hypermysticsonic
					if P_IsObjectOnGround(s) and not (s.target.player.cmd.sidemove)
					P_InstaThrust(s, s.angle, 85*FRACUNIT)
					s.target.smsbaang = R_PointToAngle2(s.x, s.y, (s.x+s.momx), (s.y+s.momy))
					s.target.boostpass = 1
					s.target.smsspeedticket = true
					s.target.player.speed = 160*FRACUNIT
					s.mineboost = true
						if not s.smssoundplayed3
						S_StartSound(s, sfx_smach)
						A_SMSquake(s.target, 37*FRACUNIT, 2, 500, true)
						s.smsaurablastspawn = P_SpawnMobj(s.x+(s.momx*2), s.y+(s.momy*2), s.z, MT_BURSTWAVE)
						s.smsaurablastspawn.color = SKINCOLOR_SUPERGOLD3
						s.smssoundplayed3 = true
						end
					end
				elseif s.smssoundplayed3
				s.smssoundplayed3 = false
				end
				if P_IsObjectOnGround(s) and s.mineboost and not (s.target.player.cmd.buttons & BT_CUSTOM1)
					P_InstaThrust(s, s.angle, 25*FRACUNIT)
					s.target.player.speed = 8*FRACUNIT
					s.mineboost = false
				//	if (s.target.state == S_SMSWATERGRIND1) or (s.target.state == S_SMSWATERGRIND2)
					s.target.state = S_PLAY_STND
				//	end
				elseif s.mineboost and s.target
					s.target.smsbaang = R_PointToAngle2(s.x, s.y, (s.x+s.momx), (s.y+s.momy))
					s.target.player.speed = 160*FRACUNIT
					s.target.boostpass = 1
					s.target.smsspeedticket = true
				end 
				if not P_IsObjectOnGround(s) //s.target.player.hypermysticsonic	and
				s.angle = s.target.angle
				end
				if (s.target.player.cmd.buttons & BT_JUMP and not (s.target.player.sms_jumphold > 1))
				and not (s.target.player.pflags & PF_JUMPDOWN) //Welp, this turned out hilarious
				or (s.target.player.cmd.buttons & BT_JUMP) and s.target.player.hypermysticsonic
				 if s.target.player.hypermysticsonic
					P_SetObjectMomZ(s, 9*FRACUNIT, false)
				 else
					if not P_IsObjectOnGround(s) or s.target.player.hypermysticsonic
						if (s.momz > FRACUNIT)
						s.momz = $/2
						else
						P_SetObjectMomZ(s, -3*FRACUNIT, false)
						end
					P_InstaThrust(s, s.target.angle, 52*FRACUNIT)
					S_StartSound(s.target, sfx_thok)
					P_SpawnThokMobj(s.target.player)
					s.angle = s.target.angle
					s.target.player.sms_jumphold = 3
					if not s.target.player.hypermysticsonic
						if s.sprite1
						s.target.state = S_SMSWATERGRIND1
						s.sprite1 = false
						else
						s.target.state = S_SMSWATERGRIND2
						s.sprite1 = true
						end
					end
					else
					s.target.player.sms_jumphold = 3
					end
				 end
				end
				if s.smssoundplayed	!= nil			
					if not s.target.player.hypermysticsonic
						if s.sprite1
						s.target.state = S_SMSWATERGRIND1
						s.sprite1 = false
						else
						s.target.state = S_SMSWATERGRIND2
						s.sprite1 = true
						end
					end
				end
			end
		end
	end
end, MT_MINECART)

//Gotta make this apply to ALL deaths and then run it.

addHook("MobjDeath", function(s, i, so)
		if s and s.type == MT_ROLLOUTROCK
			if s.tracer and s.tracer.player and s.tracer.player.powers[pw_carry] == CR_ROLLOUTROCK
			s.flags = $|MF_PUSHABLE
			s.tracer.player.powers[pw_carry] = 0 //Prevent SigSev because this game is coded amazingly.
			s.tracer = nil
			end		
		end
		if so and so.player
			if so.player.hypermysticsonic
			P_ResetScore(so.player)
				if s and s.valid and (s.flags2 & MF2_FRET)
				s.flags2 = $ & ~MF2_FRET
				end
			end
			if so.player.mslightspeedattack and not so.player.lsdeadjump and so.target and s and (so.target == s)
			and (s.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR))
			so.player.lsdeadjump = 1
			so.target = nil
			so.lsaclosest = nil
			so.lsatarget = nil
				if so.lsaringdebt and not (so.skin == "sms")
				P_GivePlayerRings(so.player, -5)
				so.lsaringdebt = 0
				end
			end
			if so.player.hypermysticsonic and i and (i == so) and s and s.valid and (s.flags & (MF_ENEMY|MF_BOSS))
			and ((FixedHypot(FixedHypot(so.x-s.x, so.y-s.y), so.z-s.z)) < 214*FRACUNIT)
			S_StartSound(s, sfx_cdfm50)
			s.deathsmoke = P_SpawnMobj(s.x, s.y, s.z+s.height/3, MT_TNTDUST)
			s.hmsgodaurad = true
				if s.deathsmoke
				s.deathsmoke.destscale = $*5
				s.deathsmoke.fuse = 43
				s.deathsmoke.tics = 1
				S_StartSound(s.deathsmoke, sfx_kc40)
				P_Thrust(s.deathsmoke, R_PointToAngle2(s.x, s.y, so.x, so.y), -14*FRACUNIT)
				end
			//	S_StartSound(so, sfx_kc40)
			//	S_StartSound(so, sfx_cdfm50)
			A_SMSquake(so, 25*FRACUNIT, 3, 999, true)
			end
		end
		
//It's the Robot Gore code	
		if so and so.player and (so.skin == "sms" or so.player.mslightspeedattack)
		and s and ( ( (s.flags & (MF_ENEMY|MF_BOSS)) and (mobjinfo[s.type].deathstate > 2522 and mobjinfo[s.type].deathstate < 2600) and (mobjinfo[s.type].deathsound == 119) )
		or (s.type == MT_DETON) or (s.type == MT_HIVEELEMENTAL) or (s.type == MT_BUMBLEBORE) or (s.type == MT_GSNAPPER) or (s.type == MT_FACESTABBER) or (s.type == MT_SNAILER) or (s.flags & MF_BOSS) )
			if so.player.hypermysticsonic or so.player.homing or so.player.footsweepanim or so.airboostroll or s.mhomingbounced
			or ((so.player.pflags & PF_SPINNING) and (so.player.speed > 45*FRACUNIT)) or so.player.sms_stompanim or so.player.sms_afterstompthok or so.state == S_SMS_ATOMLAND1
			or (i and (i.type == MT_CMPHTRACKER or i.type == MT_SMSTHROWTRACKER) or (i.flags & MF_MISSILE) or i.type == MT_SMSPOWERBOMB) or so.player.powers[pw_sneakers] or (so.player.speed > 70*FRACUNIT)
			or (so.momz < -30*FRACUNIT) or (so.momz > 30*FRACUNIT) or so.player.mslightspeedattack
				s.rgsps = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_THOK)
					local harshrobotgore = P_RandomRange(1,3) //Custom Robot Deaths
					if harshrobotgore == 1
					S_StartSound(s.rgsps, sfx_harrg1)
					elseif harshrobotgore == 2
					S_StartSound(s.rgsps, sfx_harrg2)
					else
					S_StartSound(s.rgsps, sfx_harrg3)
					end
				s.mhomingbounced = 0
				s.rgsps.sprite = SPR_NULL
				s.rgsps.tics = 60
			   if not (so.player.smsgraphix and so.player.smsgraphix == 2)
				s.rgsp = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_SMSRGORESPAWN)
				s.rgsp.state = S_HMSLIGHTNING  //Feed a crapton of information into the gorespawner, which will then do all the gore.
				s.rgsp.frame = A
				s.rgsp.sprite = 0
				s.rgsp.eneheight = s.height
				s.rgsp.eneradius = s.radius
				if s.color
				s.rgsp.enecolor = s.color
				elseif (s.type == MT_BLUECRAWLA) or (s.type == MT_SPRINGSHELL)  or (s.type == MT_YELLOWSHELL) or (s.type == MT_PENGUINATOR)
				s.rgsp.enecolor = SKINCOLOR_CORNFLOWER
				elseif (s.type == MT_GFZFISH) or (s.type == MT_CRAWLACOMMANDER) or (s.type == MT_METALSONIC_BATTLE)
				s.rgsp.enecolor = SKINCOLOR_COBALT
				elseif (s.type == MT_GSNAPPER) or (s.type == MT_JETTBOMBER) or (s.type == MT_ROBOHOOD)
				s.rgsp.enecolor = SKINCOLOR_GREEN
				elseif (s.type == MT_REDCRAWLA) or (s.type == MT_REDBUZZ) or (s.type == MT_DETON) or (s.type == MT_VULTURE) or (s.type == MT_CRUSHSTACEAN)
				s.rgsp.enecolor = SKINCOLOR_RED
				elseif (s.type == MT_EGGGUARD) or (s.type == MT_BANPYURA) or (s.type == MT_PTERABYTE)
				s.rgsp.enecolor = SKINCOLOR_LAVENDER
				elseif (s.type == MT_FACESTABBER) or (s.type == MT_JETJAW)
				s.rgsp.enecolor = SKINCOLOR_CRIMSON
				elseif (s.type == MT_DRAGONBOMBER) or (s.type == MT_PYREFLY) or (s.type == MT_CANARIVORE) or (s.type == MT_SNAILER) or (s.type == MT_GOLDBUZZ)
				or (s.type == MT_HIVEELEMENTAL) or (s.type == MT_BUMBLEBORE)
				s.rgsp.enecolor = SKINCOLOR_GOLD
				elseif (s.type == MT_JETTGUNNER) or (s.type == MT_CYBRAKDEMON)
				s.rgsp.enecolor = SKINCOLOR_BROWN
				elseif (s.type == MT_UNIDUS) or (s.type == MT_POPUPTURRET) or (s.type == MT_MINUS)
				s.rgsp.enecolor = SKINCOLOR_CARBON
				end
				s.rgsp.enescale = s.scale
				if so and so.player.homing
				s.rgsp.enethrust = 10*FRACUNIT
				elseif so and (so.player.speed > 20*FRACUNIT)
				s.rgsp.enethrust = so.player.speed*6/7 
				else
				s.rgsp.enethrust = 16*FRACUNIT
				end
				s.rgsp.eneanglethrust = R_PointToAngle2(s.x, s.y, so.x, so.y)
				s.rgsp.enex = s.x
				s.rgsp.eney = s.y
				s.rgsp.enez = s.z
				s.rgsp.target = s
				s.rgsp.smskiller = so
				if so.player.srgorelvl != nil
				so.player.srgorelvl = $+1
				s.rgsp.srgorelvl = so.player.srgorelvl
				else
				s.rgsp.srgorelvl = 0
				end
				if so.player.hypermysticsonic
				s.rgsp.hmskiller = so
				end
			   end
			   	A_SMSquake(so, 14*FRACUNIT, 2, 300, true)
				
				if (s.flags & MF_ENEMY) and not (s.flags & MF_BOSS) //"Inflate" and then blow up! Enjoy, Deviantart
				and ((mobjinfo[s.type].deathstate > 2522 and mobjinfo[s.type].deathstate < 2600) and mobjinfo[s.type].deathsound == 119)
				s.rgspa = P_SpawnMobj(s.x, s.y, s.z, MT_THOK)
				s.rgspa.sprite = s.sprite
				s.rgspa.frame = s.frame
				s.rgspa.angle = s.angle
				s.rgspa.scale = s.scale
				s.rgspa.color = s.color
				if s.rgsp and s.rgsp.valid
				P_Thrust(s.rgspa, s.rgsp.eneanglethrust, s.rgsp.enethrust*-2)
				end
				s.rgspa.tics = 4
				s.rgspa.scalespeed = $*9
				s.rgspa.destscale = $*33
				end
				
				return
			end
		end
end)

//Lightspeed Attack Damage reset. Also done in MobjDeath just to make sure.

addHook("MobjDamage", function(s, i, so)
	if not (so and so.player)
	return
	end
	
		if s and (s.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR))
			if so.player.hometrickanim and so.skin == "sms" and i and i.skin == "sms" and i.player
				if so.player.hometrickanim
				so.player.hometrickanim = false
				so.state = S_PLAY_ROLL //Enough tricking
				end
			end
			if (s.flags & MF_BOSS) and so.player.homing and so.skin == "sms" and not so.player.hypermysticsonic and i and i.skin == "sms" and i.player
			so.forcesmstrick = true
				if (s.type == MT_EGGMOBILE4)
				P_Thrust(so, R_PointToAngle2(so.x, so.y, s.x, s.y), -195*FRACUNIT) //Don't insta-crush players who homing attack you
				end
				return
			elseif so.player.hypermysticsonic and (so.player.hypermysticsonic > 30) and not so.player.starthmscombo
			P_KillMobj(s, i, so) //Any damage from Hyper Mystic Sonic is instant death
			return false
			end
		end
		if so.player.mslightspeedattack
			if not so.player.lsdeadjump and so.target and s and (so.target == s)
			and (s.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR))
			so.player.lsdeadjump = 1
			so.target = nil
			so.lsaclosest = nil
			so.lsatarget = nil
				if so.lsaringdebt and not (so.skin == "sms")
				P_GivePlayerRings(so.player, -5)
				so.lsaringdebt = 0
				end
			end
		end
end)

addHook("MobjMoveCollide", function(s, v)
	if s.player and (s.player.footsweepanim or s.player.sms_stompanim) and s and s.health
	and not (v and v.valid and ((s.z+180000 > v.z+v.height) or (s.z+s.height < v.z-180000)))
		if (v.valid and v.type == MT_EGGSHIELD)
			P_SetObjectMomZ(v, 20*FRACUNIT)
			P_SetObjectMomZ(s, 8*FRACUNIT)
			P_InstaThrust(s, s.angle, -7*FRACUNIT)
			s.state = S_PLAY_FALL
			s.player.footsweepanim = false
			s.player.sms_stompanim = 0
			s.height = P_GetPlayerHeight(s.player)
			S_StartSound(s, sfx_cdfm36)
			s.player.powers[pw_flashing] = 14
			P_KillMobj(v, s, s)
			return false
		end
		if G_GametypeHasSpectators()
		and v.valid and v.health and v.player
		and not (v.player.ctfteam and (s.player.ctfteam == v.player.ctfteam))
			if not v.player.hypermysticsonic
				if s.player.footsweep03
				P_Thrust(v, v.angle, -7*FRACUNIT)
				P_SetObjectMomZ(v, 7*FRACUNIT, relative)
				end
				if (s.player.speed >= v.player.speed)
				P_DamageMobj(v, s, s)
				v.player.weapondelay = 25
				v.player.sms_flamedelay = 25
				end
				return
			elseif not v.player.hypermysticsonic
				P_InstaThrust(v, v.angle, -20*FRACUNIT)
				P_SetObjectMomZ(v, 8*FRACUNIT)
				v.player.pflags = $|PF_JUMPED
				return
			end
		end
	else
		return
	end
end, MT_PLAYER)

//Burn Cacti with flames!

local function CactiBurn(f, s)
	if f and f.valid and ((f.flags & MF_MISSILE) or (f.player and f.player.hypermysticsonic))
	and s and s.valid and (s.type >= MT_CACTI1 and s.type <= MT_CACTISMALLSEG) and (s.flags & MF_PAIN)
	and (f.readyforonemoreplant or not ((f.z > s.z+s.height) and not (f.z+f.height < s.z)) )
	s.sprite = SPR_AURA
	s.frame = C
	s.flags = $ & ~MF_PAIN & ~MF_SOLID & ~MF_NOGRAVITY
	s.scale = $*P_RandomRange(0, 4)
		if not P_IsObjectOnGround(s)
		s.z = s.floorz
		end
		if f.player and f.player.hypermysticsonic	
			s.benope = P_SpawnMobj(s.x, s.y, s.z, MT_BOSSEXPLODE)
			if not f.readyforonemoreplant
			S_StartSoundAtVolume(s, sfx_brakrx, 155)
			end
			A_SMSquake(f, 65*FRACUNIT, 3, 1400, true)
			if s.benope and s.benope.valid
			s.benope.scale = FRACUNIT*3
			end
		else
			s.benope = P_SpawnMobj(s.x, s.y, s.z, MT_FLAMEJETFLAME)
			if s.benope and s.benope.valid
			s.benope.flags = MF_NOGRAVITY|MF_SCENERY
			s.benope.destscale = $*3
			s.benope.scalespeed = $/2
			s.benope.fuse = P_RandomRange(20, 35)
			end	
			S_StartSound(s, sfx_s3k7f)
			S_StartSound(s, sfx_s248)
		end
		f.readyforonemoreplant = 2
	end
end

addHook("MobjCollide", CactiBurn, MT_PLAYER)
addHook("MobjMoveCollide", CactiBurn, MT_SMSFIREBLAST)
addHook("MobjMoveCollide", CactiBurn, MT_HMSFIREBLAST)
addHook("MobjMoveCollide", CactiBurn, MT_HMSNOVABLAST)
addHook("MobjCollide", CactiBurn, MT_HMSNOVABLASTHB)
addHook("MobjMoveCollide", CactiBurn, MT_HMSNOVABLASTHB)
addHook("MobjMoveCollide", CactiBurn, MT_PLAYER)

//Ignore most of SMS' attacks in the cage.

addHook("ShouldDamage", function(s, i, so)
	if (so and so.skin == "sms" and not (so.player and so.player.hypermysticsonic)) 
	and i and i.skin ~= "sms" //If SMS hit you indirectly while you're in the cage, brush it off. He's trying to cheat.
	and not (s and s.valid and (s.state >= S_EGGMOBILE4_RAISE1))
	return false
	end
end, MT_EGGMOBILE4)

//Your flames are just fueling these guys!

addHook("ShouldDamage", function(s, i, so)
	if i and i.type == MT_SMSFIREBLAST and s and s.health
		S_StartSound(s, sfx_gravch)
		s.novawave = P_SpawnMobj(s.x, s.y, s.z, MT_HMSNOVAWAVE)
		s.novawave.color = SKINCOLOR_FLAME
		s.novawave.scale = s.scale/2
		s.novawave.destscale = s.novawave.scalespeed+1
		if s.valid and (s.state == (S_PYREFLY_FLY or S_PYREFLY_BURN))
		s.state = S_PYREFLY_BURN
		s.fuse = 1
		end
	return false
	end
end, MT_PYREFLY)

//And these'll absorb your fire!

addHook("ShouldDamage", function(s, i, so)
	if i and i.type == MT_SMSFIREBLAST and s and s.health
	s.novawave = P_SpawnMobj(s.x, s.y, s.z, MT_HMSNOVAWAVE)
	s.novawave.color = SKINCOLOR_FLAME
	s.novawave.scale = s.scale/2
	s.novawave.destscale = s.novawave.scalespeed+1
	S_StartSound(s, sfx_gravch)
	return false
	end
end, MT_UNIDUS)

addHook("MobjMoveBlocked", function(s)
	if s and s.player
local p = s.player					
		if s.hypermysticdash and not (p.cmd.angleturn or p.cmd.sidemove)
			if not (p.pflags & PF_ANALOGMODE)
			s.hypermysticdash = 0
			end
		end
	end
end, MT_PLAYER)

addHook("MobjMoveBlocked", function(s)
	if s and (s.fusrodahfuse and s.fusrodahfuse > 2)
		s.fusrodahwallexplode = true //Blow up the enemy!
	end
end, MT_CMPHTRACKER)