--===========================ITEM PICKUPS==============================
--Powerup pickups, ammo drops, tracking items in HUD, that's all in here.
--======================================================================
local SAM = MetroidVanguard
local SAMUSDIFFICULTY = SAMUSDIFFICULTY

local function P_MobjFlip(s) --Preventing MobjFlip crash by overriding the function entirely.
	if s and s.valid and ((s.eflags & MFE_VERTICALFLIP) or (s.flags2 & MF2_OBJECTFLIP))
		return -1 --
	end return 1 --
end

rawset(_G, "NewSamPickup", function(s, NAME, SCALE, TIME, COLOR, TRANS) -- Set Parameters
	TIME = TIME or 150
	SCALE = SCALE or FRACUNIT
	if not COLOR
		COLOR = (NAME=="NRGDB0") and SKINCOLOR_SUPERGOLD4 or SKINCOLOR_NONE
	end
	TRANS = (TRANS) or FF_TRANS10

    -- Move these two to the front of the row....
	if s.sampickuptime3 -- and s.sampickuptime2
		if not s.sampickuptime
			s.sampickupname = NAME
			s.sampickupscale = SCALE
			s.sampickuptime = TIME
			s.sampickupoffset = 6<<16
			s.sampickuptrns = TRANS
			s.sampickupcolor = COLOR
        else
			s.sampickupname3 = s.sampickupname2
			s.sampickupscale3 = s.sampickupscale2
			s.sampickuptime3 = s.sampickuptime2
			s.sampickupoffset3 = s.sampickupoffset2
			s.sampickuptrns3 = s.sampickuptrns2
			s.sampickupcolor3 = s.sampickupcolor2
			
			s.sampickupname2 = s.sampickupname
			s.sampickupscale2 = s.sampickupscale
			s.sampickuptime2 = s.sampickuptime
			s.sampickupoffset2 = s.sampickupoffset
			s.sampickuptrns2 = s.sampickuptrns
			s.sampickupcolor2 = s.sampickupcolor
			
			s.sampickupname = NAME
			s.sampickupscale = SCALE
			s.sampickuptime = TIME
			s.sampickupoffset = 6<<16
			s.sampickuptrns = TRANS
			s.sampickupcolor = COLOR
        end
		if s.sampickupname3 == "NRGDB0" and not s.sampickupcolor3
			s.sampickupcolor3 = SKINCOLOR_SUPERGOLD4 --ffs
		end

    elseif s.sampickuptime2
		s.sampickupname3 = NAME
		s.sampickupscale3 = SCALE
		s.sampickuptime3 = TIME
		s.sampickupoffset3 = 6<<16
		s.sampickuptrns3 = TRANS
		s.sampickupcolor3 = COLOR

    elseif s.sampickuptime
		s.sampickupname2 = NAME
		s.sampickupscale2 = SCALE
		s.sampickuptime2 = TIME
		s.sampickupoffset2 = 6<<16
		s.sampickuptrns2 = TRANS
		s.sampickupcolor2 = COLOR

    else
		s.sampickupname = NAME
		s.sampickupscale = SCALE
		s.sampickuptime = TIME
		s.sampickupoffset = 6<<16
		s.sampickuptrns = TRANS
		s.sampickupcolor = COLOR
    end
end)

local function RingToSam(m)
	local CHANGE = (SAM.HUNTERS(s)) and true or false
	if METROIDSKINS == true or (SAM.HUNTERS(s))
		if m and m.valid
			if (m.type == MT_STARPOST)
				m.samspawnitem = P_SpawnMobj(m.x, m.y, m.z, MT_SMONTRACKER)
				m.samspawnitem.target = m
				m.samspawnitem.starposttracker = true
				m.metroidvisual = true
				if m.health
					m.sprite = SPR_MPR1
					m.frame = O
					m.color = SKINCOLOR_RED
				end
			elseif m.health
				m.state = S_METRING1
				m.metroidvisual = true
				m.colorized = true
				m.color = SKINCOLOR_WHITE
			end
		end
	end
end
addHook("MobjSpawn", RingToSam, MT_RING)
addHook("MobjSpawn", RingToSam, MT_FLINGRING)
addHook("MobjSpawn", RingToSam, MT_COIN)
addHook("MobjSpawn", RingToSam, MT_FLINGCOIN)

--Hunters only skins.
local function RingToSam7(m)
	if (SAM.HUNTERS(s)) and m
		m.state = S_HUNTERSMISSILE1
		if m.type == MT_INFINITYRING
			m.scale = $+30000
			m.color,m.colorized = SKINCOLOR_RED,true
		else
			m.scale = $+10000
		end
	end
end
addHook("MobjSpawn", RingToSam7, MT_BOUNCERING)
addHook("MobjSpawn", RingToSam7, MT_RAILRING)
addHook("MobjSpawn", RingToSam7, MT_AUTOMATICRING)
addHook("MobjSpawn", RingToSam7, MT_EXPLOSIONRING)
addHook("MobjSpawn", RingToSam7, MT_SCATTERRING)
addHook("MobjSpawn", RingToSam7, MT_GRENADERING)
addHook("MobjSpawn", RingToSam7, MT_EXPLOSIONRING)
addHook("MobjSpawn", RingToSam7, MT_INFINITYRING)

local function RingToSam8(m)
	if (SAM.HUNTERS(s)) and m
		m.state = S_HUNTERSMISSILE3
		m.scale = max($*2-4000, 500)
		m.info.deathstate = S_SPRK1
		local ghs = P_SpawnMobj(m.x, m.y, m.z, MT_SAMSPAWNITEMSONIC)
		ghs.ogmonitor = m
		ghs.tics = -1
		ghs.missilepanel = true
	end
end
addHook("MobjSpawn", RingToSam8, MT_BOUNCEPICKUP)
addHook("MobjSpawn", RingToSam8, MT_RAILPICKUP)
addHook("MobjSpawn", RingToSam8, MT_AUTOPICKUP)
addHook("MobjSpawn", RingToSam8, MT_SCATTERPICKUP)
addHook("MobjSpawn", RingToSam8, MT_GRENADEPICKUP)
addHook("MobjSpawn", RingToSam8, MT_EXPLODEPICKUP)

//Pity TV MobjSpawn doesn't work for some reason.
addHook("MobjThinker", function(m) if not m.valid or m.triedspawn return end
	if m.SAM_matchmonitors == nil --Save this once, regardless of triedspawn getting removed.
		SAM.ApplyMonitorSettings(m) --applies m.SAM_metroidvisuals, m.SAM_matchmonitors, and m.SAM_nosuperpowert 
		m.triedspawn = true
	end
	if G_GametypeHasSpectators() --Hmm, this MIGHT be dangerous in netgames...keep track of it.
		if not m.SAM_matchmonitors and (leveltime > 8)
			SAM.MonitorRandomize(m) --Changes the monitor type potentially!
		end
	end
	if m and m.valid and m.SAM_metroidvisuals
		SAM.MonitorToSphere(m)
	end
end, MT_PITY_BOX)

local function BoxToSam(m)
	if m.SAM_matchmonitors == nil --Save this once, regardless of triedspawn getting removed.
		SAM.ApplyMonitorSettings(m) --applies m.SAM_metroidvisuals and m.SAM_matchmonitors
		m.triedspawn = true
	end
	if G_GametypeHasSpectators()
		if m.SAM_matchmonitors and (leveltime > 11) and (m.flags & MF_MONITOR)
			SAM.MonitorRandomize(m)
		end
	end
	if m and m.valid and m.SAM_metroidvisuals
		SAM.MonitorToSphere(m)
	end
end
addHook("MobjSpawn", BoxToSam, MT_RING_BOX)
addHook("MobjSpawn", BoxToSam, MT_RING_REDBOX)
addHook("MobjSpawn", BoxToSam, MT_RING_BLUEBOX)
addHook("MobjSpawn", BoxToSam, MT_SNEAKERS_BOX)
addHook("MobjSpawn", BoxToSam, MT_INVULN_BOX)
addHook("MobjSpawn", BoxToSam, MT_ATTRACT_BOX )
addHook("MobjSpawn", BoxToSam, MT_FORCE_BOX)
addHook("MobjSpawn", BoxToSam, MT_ARMAGEDDON_BOX)
addHook("MobjSpawn", BoxToSam, MT_WHIRLWIND_BOX)
addHook("MobjSpawn", BoxToSam, MT_ELEMENTAL_BOX)
//addHook("MobjSpawn", BoxToSam, MT_PITY_BOX)
addHook("MobjSpawn", BoxToSam, MT_EGGMAN_BOX)
addHook("MobjSpawn", BoxToSam, MT_EGGMAN_GOLDBOX)
addHook("MobjSpawn", BoxToSam, MT_RECYCLER_BOX)
addHook("MobjSpawn", BoxToSam, MT_MYSTERY_BOX)
addHook("MobjSpawn", BoxToSam, MT_SCORE1K_BOX)
addHook("MobjSpawn", BoxToSam, MT_SCORE10K_BOX)
addHook("MobjSpawn", BoxToSam, MT_MIXUP_BOX)
addHook("MobjSpawn", BoxToSam, MT_1UP_BOX)

addHook("MobjThinker", function(s)
	if s.metroidvisual or METROIDSKINS == true
		if s.health and (s.color < 25)
			if (s.color % 8 == 0) and not (s.flags2 & MF2_DONTDRAW) --Ooooo, we soooo special.
				P_SpawnMobj(
				s.x+(P_RandomRange(-80,80)<<16), 
				s.y+(SAM.RNG(-80,80,s)<<16),
				s.z+(SAM.RNG(3,50,s)<<16), MT_SUPERSPARK)
			end
			s.color = $+1
		elseif s.health and (s.color >= 25)
			s.color = 0
		end
	end
end, MT_MIXUP_BOX)


addHook("MobjSpawn", function(s) s.sampickup=true end, MT_SPKU)
addHook("MobjSpawn", function(s) s.sampickup=true end, MT_BMPKU)
addHook("MobjSpawn", function(s) s.sampickup=true end, MT_MTNK)

addHook("MobjThinker", function(s) if not s.valid return end --
	if (leveltime%12==0)
		A_SAMPARTICLE(s, MT_MPR1, 50, 1, 1, 1, SAM.RNG(SKINCOLOR_SUPERGOLD3, SKINCOLOR_SUPERGOLD5,s), SAM.RNG(23355, 55353,s))
		if not s.samsize
			s.samsize = true
			s.scale = $*10/6
		end
	end
	S_StartSound(s, sfx_pbpku)	
end, MT_PBOM)

addHook("MobjThinker", function(s)
	if not s.colorchange	
		if s.hyperbeamammo 
			s.color = (leveltime%2) and SKINCOLOR_SKY or SKINCOLOR_CLOUDY
		else
			s.color = SKINCOLOR_YELLOW
			s.colorchange = true
		end
	end
end, MT_NRGD)

local function ChargeHomer(s) if not s.valid return end --
	if s.chargehomertime
		s.chargehomertime = $-1
		if s.chargehomertime <= 0
			s.momx,s.momy,s.momz = 0,0,0
			s.chargehomertime = nil
			if (s.z < s.floorz+18<<16)
				s.z = $+(16<<16)
			end
			return --
	/*	else
			if s.chargehomertarget and s.chargehomertarget.valid
			s.target = s.chargehomertarget
				if P_FaceStabCheckMeleeRange(s)
					P_SpawnGhostMobj(s)
					P_MoveOrigin(s, s.target.x+s.target.momx, s.target.y+s.target.momy, s.target.z+(s.target.height/3)+s.target.momz)
				end
			end */
		end 
	end
end

addHook("MobjThinker", ChargeHomer, MT_MPKU)
addHook("MobjThinker", ChargeHomer, MT_BMPKU)
addHook("MobjThinker", ChargeHomer, MT_SPKU)
addHook("MobjThinker", ChargeHomer, MT_PBOM)
addHook("MobjThinker", ChargeHomer, MT_NRGA)
addHook("MobjThinker", ChargeHomer, MT_NRGB)
addHook("MobjThinker", ChargeHomer, MT_NRGD)

--The Prism Orb for the Hunters gamemode and the easy campaign difficulty.
addHook("MobjThinker", function(s) if not s.valid return end
	local t = s.target local p = t and t.player
	if not (s.fuse and t and p and t.health)
		s.state = S_NULL return --
	end

	s.fancyangle = s.fancyangle and $+ANGLE_45 or ANGLE_45
	s.angle = s.fancyangle+ANGLE_90
	if not (s.color > SKINCOLOR_SUPERPURPLE4)
		s.color = $+1
	else
		s.color = SKINCOLOR_ROSY
	end
	if s.donttouch
		s.donttouch = $-1
	end
	if (s.fuse < 100) --Flicker
		if (s.fuse%2==0)
			s.flags2 = $|MF2_DONTDRAW
		else
			s.flags2 = $ & ~MF2_DONTDRAW
		end
	end
	if not SAM_displayplayer(p)
		s.flags2 = $|MF2_DONTDRAW --Only display for 1 player.
	end
	
	--Spawn a spinning ghost
	local ghs = P_SpawnGhostMobj(s)
	if s.ghosttime
		ghs.tics = 6
		s.ghosttime = $-1
	else
		ghs.tics = 2
	end
	ghs.renderflags = RF_PAPERSPRITE|RF_SEMIBRIGHT|RF_NOCOLORMAPS
	ghs.angle = s.fancyangle
	ghs.blendmode = AST_ADD
	ghs.colorized = true
	if (s.flags2 & MF2_DONTDRAW)
		ghs.flags2 = $|MF2_DONTDRAW
	end	
	if (leveltime % 3 == 0)
		ghs.color = SKINCOLOR_SUPERGOLD3
		if s.superprism
			ghs.tics = 3
			ghs.scale = s.scale*2
		else
			ghs.scale = s.scale+(s.scale/3)
		end
	else
		ghs.color = SKINCOLOR_BLUE
		ghs.scale = s.scale/2
	end
	
	--Lastly, attraction behaviour. It auto-attracts, but the charge beam has a pretty significant effect.
	local SPEED = (p.sams_chargetime) and 24*t.scale or 8*t.scale
	
	--Attraction?
	if s.valid
		s.frame = $|FF_PAPERSPRITE
		local mult = FixedHypot(FixedHypot(t.x-s.x, t.y-s.y), t.z-s.z)
		if (mult < (70*SPEED))
			if mult < 1
				mult = 1
			end
			if ghs and ghs.valid
			ghs.tics = $+5
			end
			if s.donttouch
				P_SetObjectMomZ(s, 12<<16)
				s.momx = ($*8)/9
				s.momy = ($*8)/9					
			else
				s.momx = FixedMul(FixedDiv(t.x-s.x, mult), SPEED) 
				s.momy = FixedMul(FixedDiv(t.y-s.y, mult), SPEED)
				s.momz = FixedMul(FixedDiv(t.z-s.z, mult), SPEED)
			end
			
		else --Non-attraction.
			s.momx = ($*8)/9
			s.momy = ($*8)/9
			s.momz = ($*8)/9
		end
	end
end, MT_NRGH)
addHook("MobjMoveCollide", function(s, v)
	if v and v.player and YouAreSamus(v) and s.target and s.target == v
	local p = v.player
		if (v.z > s.z+s.height)
		or (s.z > v.z+v.height+8<<16)
		or s.donttouch
			return false --
		end
		if s.superprism	
			local rng = P_RandomRange(0,10)
			if rng > 9 and p.sampwmax
				p.sampw = $+1*p.sam_ammodigitizer
				S_StartSound(nil, sfx_mtnk, p)
			elseif rng > 6 and p.samsupermissilesmax
				p.samsupermissiles = $+1*p.sam_ammodigitizer
				S_StartSound(nil, sfx_mpku, p)
			else
				p.sammissiles = $+3*p.sam_ammodigitizer
			end

		else --Normal Prism?
			if p.buffbottomtier and G_GametypeHasSpectators() and not p.sam_hyperbeam
				GiveSamusEnergy(p, 10, 3)
			else
				GiveSamusEnergy(p, 5, 3)
			end
			p.sammissiles = $+1*p.sam_ammodigitizer
		end
		S_StartSound(v, sfx_nrga)
		s.state = S_NULL
		return false
	else
		return false
	end
end, MT_NRGH)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height+8<<16)
				return --
			end
			local MISSILES = (p.sammissiles) or 0
			local ADD = (SAMUSDIFFICULTY==2) and 1 or 2
			p.sammissiles = MISSILES+(ADD*p.sam_ammodigitizer)
			if p.buffbottomtier and G_GametypeHasSpectators()
				p.sammissiles = $+3*p.sam_ammodigitizer
			end
			NewSamPickup(v, "MPKUA0", 37555)
			S_StartSound(v, sfx_mpku)
			s.state = S_NULL return false --
		end
	end
end, MT_MPKU)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height+8<<16)
				return --
			end
			local MISSILES = (p.sammissiles) or 0
			local ADD = (SAMUSDIFFICULTY==2) and 3 or 5
			p.sammissiles = MISSILES+(ADD*p.sam_ammodigitizer)
			if p.buffbottomtier and G_GametypeHasSpectators()
				p.sammissiles = $+3*p.sam_ammodigitizer
			end
			NewSamPickup(v, "MPKUC0", 47555)	
			S_StartSound(v, sfx_mpku)
			s.state = S_NULL return false --
		end
	end
end, MT_BMPKU)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height+8<<16)
				return --
			end
			local SUPERS = (p.samsupermissiles) or 0
			local SUPERSMAX = (p.samsupermissilesmax) or 0
			if (SUPERS < SUPERSMAX) --If you can actually get some, then....
				p.samsupermissiles = SUPERS+ 1*p.sam_ammodigitizer
			else --Otherwise, turn them into missiles.
				p.sammissiles = p.sammissiles and $+ 2*p.sam_ammodigitizer or 2*p.sam_ammodigitizer
			end
			if p.buffbottomtier and G_GametypeHasSpectators() and SUPERSMAX
				p.samsupermissiles = $+(1*p.sam_ammodigitizer)
			end
			
			NewSamPickup(v, "SPKUA0", 47555)	
			S_StartSound(v, sfx_mpku)
			s.state = S_NULL return false --
		end
	end
end, MT_SPKU)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height+8<<16)
				return --
			end
			local PW = (p.sampw) or 0
			local PWMAX = (p.sampwmax) or 0
			if (PW < PWMAX) --If you can actually get some, then...
				p.sampw = $+1*p.sam_ammodigitizer
			else --Get missiles instead.
				p.sammissiles = $+(3*p.sam_ammodigitizer)
			end
			if p.buffbottomtier and G_GametypeHasSpectators() and PWMAX
				p.sampw = $+1*p.sam_ammodigitizer
			end
			S_StopSound(s)
			NewSamPickup(v, "PBOMA0", 70555)
			S_StartSound(v, sfx_mtnk)
			s.state = S_NULL return false --
		end
	end
end, MT_PBOM)

--Text for your pickups.
rawset(_G, "ItemGetPopup", function(p, timer, color, text, textscale) --Text must be a string!
	if not p return end --
	p.samitemgettimer = (timer) or 80
	p.samitemcolor = (color) or SKINCOLOR_CARBON
	p.samitemgetname = (text) or "Unknown"
	p.samitemscale = (textscale) or 85000
end)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height+8<<16)
				return --
			end
			if p.sammissilesmax != nil
				if p.sammissilesmax
					P_SamFP(p, PAL_MIXUP, 7)
					S_StartSound(v, sfx_mtnk)
				else
					P_SamFP(p, PAL_MIXUP, 9)
					CONS_Printf(p, "You've obtained \x84Missiles!\x80 Press FIRE to shoot them, but watch your ammo!")
					S_StartSound(v, sfx_spwup)
				end
				SamusTutorial(v, "missiles")
				p.sammissilesmax = $+5
				if SAMUSDIFFICULTY != 2
					p.sammissiles = $+5
				end
				NewSamPickup(v, "MTNKD0", 55355, nil, nil)
				ItemGetPopup(p, 80, SKINCOLOR_CRIMSON, "Missiles", 70000)
			end
			s.state = S_NULL return false --
		end
	end
end, MT_MTNK)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if p.nosuperpowert and G_GametypeHasSpectators()
				p.sammissiles = $+3
				S_StartSound(v, sfx_mpku)
				if not p.samhudmessagetime
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Super Missiles tanks are currently set to ammo."
					p.samhudmessage2 = nil
				end
				s.state = S_NULL return false --
			elseif p.samsupermissilesmax
				P_SamFP(p, PAL_MIXUP, 7)
				S_StartSound(v, sfx_mtnk)
			else
				P_SamFP(p, PAL_MIXUP, 9)
				CONS_Printf(p, "You've obtained \x84Super Missiles!\x80 Hold FIRE until it clicks, then release!")
				S_StartSound(v, sfx_spwup)
			end
			SamusTutorial(v, "supermissiles")	
			p.samsupermissilesmax = $+2
			if SAMUSDIFFICULTY!=2
				p.samsupermissiles = $+2
			end
			NewSamPickup(v, "STNKD0", 55355)	
			ItemGetPopup(p, 80, SKINCOLOR_CRIMSON, "Super Missiles", 105355)
			s.state = S_NULL
			return false --
		end
	end
end, MT_STNK)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if p.nosuperpowert and G_GametypeHasSpectators()
				P_GivePlayerRings(p, 30)
				S_StartSound(v, sfx_nrga)
				if not p.samhudmessagetime
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Power Bombs tanks are currently set to health."
					p.samhudmessage2 = nil
				end
				s.state = S_NULL
				return false --
			elseif p.sampwmax
				P_SamFP(p, PAL_MIXUP, 7)
				S_StartSound(v, sfx_mtnk)
			else
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained a \x84Power Bomb!\x80 Hold C2/NormalFire as the Morph Ball, then release!")
			end
			SamusTutorial(v, "pw")	
			p.sampwmax = $+1
			if SAMUSDIFFICULTY!=2
				p.sampw = $+1
			end
			NewSamPickup(v, "PTNKD0", 55355)	
			ItemGetPopup(p, 80, SKINCOLOR_RED, "Power Bombs", 88355)			
			s.state = S_NULL
			return false --
		end
	end
end, MT_PTNK)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.samspbs
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x83Speed Booster!\x80 Hold Custom 1 to dash!")
				ItemGetPopup(p, 80, SKINCOLOR_GREEN, "Speed Booster", 100355)		
				p.samspbs = true
				SamusTutorial(v, "variasuit")
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+3
			end
			NewSamPickup(v, "SPBSA0", 52355)
			s.state = S_NULL return false --
		end
	end
end, MT_SPBS)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_bombs
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained\x85 Bombs!\x80 In morph ball mode, press C2/normalfire and destroy breakable barricades!")
				ItemGetPopup(p, 80, SKINCOLOR_BROWN, "Morph Bombs", 80355)	
				p.sam_bombs = true
				SamusTutorial(v, "bombs")
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not (p.coopboxrespawn == 2)
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+2
				P_GivePlayerRings(p, 10)
			end
			NewSamPickup(v, "GVSTI0", 92355)	
			s.state = S_NULL return false --
		end
	end
end, MT_MHBM)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if p.sam_gravitysuit == 1
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				if netgame or splitscreen
					CONS_Printf(p, "You got the \x81Gravity feature!\x80 Move faster underwater, become immune to lava, and gain extra defense!")
				else
					CONS_Printf(p, "You got the \x81Gravity Suit!\x80 Move faster underwater, become immune to lava, and gain extra defense!")
				end
				p.sam_gravitysuit = 2
				p.sam_gravitysuitjustgot = 75
				ItemGetPopup(p, 80, SKINCOLOR_GRAVITYSUIT, "Gravity Suit", 110000)

			elseif not p.sam_gravitysuit

				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				if netgame or splitscreen
					CONS_Printf(p, "You got the \x87Varia feature!\x80 Gain defense and become immune to toxic damage!")
				else
					CONS_Printf(p, "You got the \x87Varia Suit!\x80 Gain defense and become immune to toxic damage!")
				end
				p.sam_gravitysuit = 1
				p.sam_gravitysuitjustgot = 75
				ItemGetPopup(p, 80, SKINCOLOR_VARIASUIT, "Varia Suit", 94000)

			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false --
			else
				S_StartSound(v, sfx_mpku)
				p.sampw = $+1
			end
			NewSamPickup(v, (not p.sam_gravitysuit) and "GVSTF0" or "GVSTB0", 90355)
			s.state = S_NULL return false --
		end
	end
end, MT_GVST)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_gravitysuit
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				if netgame or splitscreen
					CONS_Printf(p, "You got the \x87Varia feature!\x80 Gain defense and become immune to toxic damage!")
				else
					CONS_Printf(p, "You got the \x87Varia Suit!\x80 Gain defense and become immune to toxic damage!")
				end
				p.sam_gravitysuit = 1
				p.sam_gravitysuitjustgot = 75
				ItemGetPopup(p, 80, SKINCOLOR_VARIASUIT, "Varia Suit", 94000)
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+1
				p.samsupermissiles = $+1
			end
			NewSamPickup(v, "GVSTF0", 90355)
			s.state = S_NULL return false --
		end
	end
end, MT_VRST)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_screwattack
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x83Screw Attack!\x80 Double tap JUMP/C1 midjump to become a deadly projectile!")
				p.sam_screwattack = true
				SamusTutorial(v, "screwattack")
				ItemGetPopup(p, 80, SKINCOLOR_GOLD, "Screw Attack", 90000)
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+2
				p.samsupermissiles = $+1
			end
			NewSamPickup(v, "GVSTD0", 83355)	
			s.state = S_NULL return false --
		end
	end
end, MT_SATK)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sambsbl
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x83 Boost Ball!\x80 Hold C1/FIRE while morphed, then release to boost!")
				p.sambsbl = true
				ItemGetPopup(p, 80, SKINCOLOR_GREEN, "Boost Ball", 88000)
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+4
			end
			NewSamPickup(v, "BSBLA0", 56355)	
			s.state = S_NULL return false --
		end
	end
end, MT_BSBL)

addHook("MobjThinker", function(s) if not (s and s.valid) return end
	if not s.sizered	
		s.scale = $*10/8
		s.sizered = true
	end
end, MT_BSBL)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_highjump
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x83Hi-Jump!\x80 You jump higher, AND can jump with the Spring Ball!")
				p.sam_highjump = true
				ItemGetPopup(p, 80, SKINCOLOR_GREEN, "Hi - Jump", 70000)
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false --
			else
				S_StartSound(v, sfx_mpku)
				p.sampw = $+1
			end
			NewSamPickup(v, "SPBLB0", 76355)	
			s.state = S_NULL return false --
		end
	end
end, MT_SPBL)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_spiderball
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x83Spider Ball!\x80 Tap jump against a wall to climb for as long as you have charge.")
				p.sam_spiderball = true
				SamusTutorial(v, "spiderball")
				ItemGetPopup(p, 80, SKINCOLOR_GREEN, "Spider Ball", 92000)
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+4
			end
			NewSamPickup(v, "MPR9X0", 106355)
			s.state = S_NULL return false --
		end
	end
end, MT_SPDRBL)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_spacejump
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x83Space Jump!\x80 Press jump in midair for an aerial jumpboost!")
				p.sam_spacejump = true
				ItemGetPopup(p, 80, SKINCOLOR_GREEN, "Space Jump", 81000)
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+1
				p.samsupermissiles = $+1
			end
			NewSamPickup(v, "SJMPA0", 35355)	
			s.state = S_NULL return false --
		end
	end
end, MT_SJMP)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			local ETANKS = (p.sam_energytanksmax) or 0 
			if not (ETANKS > 12)
				if (ETANKS < 1)
					S_StartSound(v, sfx_spwup)
					CONS_Printf(p, "You've obtained an\x84 Energy Tank!\x80 Your maximum energy capacity has been permanently increased by 50 units!")
				else
					S_StartSound(v, sfx_mtnk)
				end
				P_SamFP(p, PAL_RECYCLE, 7)
				p.sam_energytanksmax = $+1
				if G_GametypeHasSpectators()
				or SAMUSDIFFICULTY!=2 --Fusion Mode won't grant free health along side.
					GiveSamusEnergy(p, 50, 3)
				end
				ItemGetPopup(p, 80, SKINCOLOR_BLUE, "Energy Tank", 85000)
			else
				S_StartSound(v, sfx_nrga)
				GiveSamusEnergy(p, 50, 3)
			end
			NewSamPickup(v, "ETNKA0", 35355)	
			s.state = S_NULL return false --
		end
	end
end, MT_ENGTNK)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_chargebeam
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x85 Charge Beam!\x80 Hold C2/NormalFire to charge your arm cannon!")
				p.sam_chargebeam = true
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Charge Beam"
				p.samitemscale = 88000
				SamusTutorial(v, "chargebeam")

			elseif not p.sam_powerbeamcombo and not (p.sam_beamcombosrestrict and G_GametypeHasSpectators())

				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x85 Power Beam Combo!\x80 With +10 missiles, hold Fire after your Power Beam is charged fully!")
				p.sam_powerbeamcombo = true
				SamusTutorial(v, "beamcombo")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Super Missile"
				p.samitemscale = 110355
			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false --
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+1
				p.samsupermissiles = $+1
				if not p.samhudmessagetime and (p.sam_beamcombosrestrict and G_GametypeHasSpectators())
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Beam Combo pickups are turned off."
					p.samhudmessage2 = nil
				end
			end
			NewSamPickup(v, "CHBMA0", 83355)
			s.state = S_NULL return false --
		end
	end
end, MT_CHBM)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_spazerbeam
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x85Spazer Beam!\x80 The beam spreads when fired.")
				p.sam_spazerbeam = true SamusTutorial(v, "gravitysuit")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Spazer Beam"
				p.samitemscale = 88000
				p.sam_wantstoswitch = 2 A_SAMBEAMSWITCH(p)

			elseif not p.sam_spazerbeamcombo and not (p.sam_beamcombosrestrict and G_GametypeHasSpectators())

				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x85 Spazer Beam Combo!\x80 With +15 missiles, hold Fire after your Spazer Beam is charged fully!")
				p.sam_spazerbeamcombo = true
				SamusTutorial(v, "beamcombo")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Force Crasher"
				p.samitemscale = 105000


			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn==2
				return false --
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+1
				p.samsupermissiles = $+1
				if not p.samhudmessagetime and (p.sam_beamcombosrestrict and G_GametypeHasSpectators())
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Beam Combo pickups are turned off."
					p.samhudmessage2 = nil
				end
			end
			NewSamPickup(v, "SPBMA0", 40355)	
			s.state = S_NULL return false --
		end
	end
end, MT_SPBM)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_wavebeam
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x85Wave Beam!\x80 This tricky beam bounces and paralyzes foes.")
				p.sam_wavebeam = true SamusTutorial(v, "gravitysuit")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Wave Beam"
				p.samitemscale = 83000
				p.sam_wantstoswitch = 3  A_SAMBEAMSWITCH(p)

			elseif not p.sam_wavebeamcombo and not (p.sam_beamcombosrestrict and G_GametypeHasSpectators())

				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x85 Wave Beam Combo!\x80 With +15 missiles, hold Fire after your Wave Beam is charged fully!")
				p.sam_wavebeamcombo = true
				SamusTutorial(v, "beamcombo")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Waveblast Buffer"
				p.samitemscale = 113000

			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn == 2
				return false --
			else
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+3
				if not p.samhudmessagetime and (p.sam_beamcombosrestrict and G_GametypeHasSpectators())
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Beam Combo pickups are turned off."
					p.samhudmessage2 = nil
				end
			end
			NewSamPickup(v, "WVBMA0", 40355)	
			s.state = S_NULL return false --
		end
	end
end, MT_WVBM)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_icebeam
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x85Ice Beam!\x80 The beam explodes upon impact and can freeze foes.")
				p.sam_icebeam = true SamusTutorial(v, "gravitysuit")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Ice Beam"
				p.samitemscale = 81000

			elseif not p.sam_icebeamcombo and not (p.sam_beamcombosrestrict and G_GametypeHasSpectators())

				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x85 Ice Beam Combo!\x80 With +15 missiles, hold Fire after your Ice Beam is charged fully!")
				p.sam_icebeamcombo = true
				SamusTutorial(v, "beamcombo")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Blizzard Burst"
				p.samitemscale = 113000
				p.sam_wantstoswitch = 4  A_SAMBEAMSWITCH(p)

			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn == 2
				return false --
			else
				S_StartSound(v, sfx_mpku)
				p.sampw = $+1
				if not p.samhudmessagetime and (p.sam_beamcombosrestrict and G_GametypeHasSpectators())
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Beam Combo pickups are turned off."
					p.samhudmessage2 = nil
				end
			end
			NewSamPickup(v, "ICBMA0", 40355)	
			s.state = S_NULL return false --
		end
	end
end, MT_ICBM)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_plasmabeam
				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the \x85Plasma Beam!\x80 This powerful mid-range beam pierces the enemy.")
				p.sam_plasmabeam = true SamusTutorial(v, "gravitysuit")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Plasma Beam"
				p.samitemscale = 86000
				p.sam_wantstoswitch = 5  A_SAMBEAMSWITCH(p)

			elseif not p.sam_plasmabeamcombo and not (p.sam_beamcombosrestrict and G_GametypeHasSpectators())

				P_SamFP(p, PAL_MIXUP, 9)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You've obtained the\x85 Plasma Beam Combo!\x80 It consumes 5 missiles p/s! Hold Fire after your Plasma Beam is charged fully!")
				p.sam_plasmabeamcombo = true
				SamusTutorial(v, "beamcombo")
				p.samitemgettimer = 80
				p.samitemcolor = SKINCOLOR_BLACK
				p.samitemgetname = "Gattling Vortex"
				p.samitemscale = 110000

			elseif (gametype == GT_COOP) and (netgame or splitscreen) and not p.coopboxrespawn == 2
				return false
			else
				S_StartSound(v, sfx_mpku)
				p.samsupermissiles = $+2
				if not p.samhudmessagetime and (p.sam_beamcombosrestrict and G_GametypeHasSpectators())
					p.samhudmessagetime = 50
					p.samhudmessage1 = "\x85"+"Beam Combo pickups are turned off."
					p.samhudmessage2 = nil
				end
			end
			NewSamPickup(v, "PLBMA0", 40355)	
			s.state = S_NULL return false --
		end
	end
end, MT_PLBM)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			local ADD = ((SAMUSDIFFICULTY==2) and not G_GametypeHasSpectators()) and 5 or 10
			GiveSamusEnergy(p, ADD, 2)
			if p.buffbottomtier and ADD != 5
				GiveSamusEnergy(p, 20, 2)
			end
			NewSamPickup(v, "NRGAB0", 65555, nil, nil, FF_TRANS40)
			S_StartSound(v, sfx_nrga)
			s.state = S_NULL return false --
		end
	end
end, MT_NRGA)

--Become a better health pickup if the player's low on health. (Below 40% or so)
addHook("MobjThinker", function(s) if not s.valid return end
	if s.spawnNRGB == nil
		if (gametype == GT_COOP) and gamemap != 28
			for z in players.iterate
				if z.mo and YouAreSamus(z.mo)
				and (FixedHypot(s.x-z.mo.x, s.y-z.mo.y) < 3000<<16)
					local ENERGY = (z.sam_energy) or 0
					local ETANKS = (z.sam_energytanksmax) and 0
					if ( ENERGY < (99+ ETANKS*50)/2 )
						P_SpawnMobjFromMobj(s,0,0,0, MT_NRGB)
						s.flags = $|MF_NOCLIP|MF_NOCLIPTHING
						s.flags2 = $|MF2_DONTDRAW
						s.fuse = 1 break --
					end
				end
			end
		end
		s.spawnNRGB = true
	end
end, MT_NRGA)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if G_GametypeHasSpectators()
				if p.sam_hyperbeam
					GiveSamusEnergy(p, 15, 2)
				else
					GiveSamusEnergy(p, (p.buffbottomtier) and 60 or 25, 2)
				end
			else
				GiveSamusEnergy(p, (SAMUSDIFFICULTY==2) and 10 or 25, 2)
			end
			NewSamPickup(v, "NRGBC0", 65556, nil, nil, FF_TRANS30)	
			S_StartSound(v, sfx_nrga)
			s.state = S_NULL return false --
		end
	end
end, MT_NRGB)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if s.hyperbeamammo --You're a HyperBeam Ammo pickup!
				NewSamPickup(v,"NRGDB0", 75555, nil, SKINCOLOR_SKY, FF_TRANS10)
				if not p.sam_energy or (p.sam_energy < 50)
					p.sam_energy = 50 --Set player energy to a minimum level
				end
				p.sam_hyperbeamammo = $+((SAMUSDIFFICULTY==2) and 25 or 50)
				p.sam_restricthyper = nil --This no longer matters in this fight.
			else --Regular 50 unit energy pickup!
				NewSamPickup(v,"NRGDB0", FRACUNIT, nil, SKINCOLOR_SUPERGOLD4, FF_TRANS30)
				if G_GametypeHasSpectators()
					if p.sam_hyperbeam
						GiveSamusEnergy(p, 30, 2)
					else
						GiveSamusEnergy(p, (p.buffbottomtier) and 125 or 50, 2)
					end
				else
					GiveSamusEnergy(p, (SAMUSDIFFICULTY==2) and 25 or 50, 2)
				end
			end
			S_StartSound(v, sfx_nrga)
			s.state = S_NULL return false --
		end
	end
end, MT_NRGD)


--My own thok object.
addHook("MobjThinker", function(s) if not s.valid return end
	if s.deathbolt local t = s.target
		if t and t.valid
			P_MoveOrigin(s, t.x, t.y, t.z+t.height/2)
		end
		s.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
		s.sprite = SPR_MPR9
		local ghs = P_SpawnMobj(s.x+(P_RandomRange(-40, 40)<<16), s.y+(P_RandomRange(-40, 40)<<16), s.z+s.height/2, MT_EXPLODE)
		ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
		if leveltime % 2 == 0
			ghs = P_SpawnMobj(s.x+(P_RandomRange(-30, 30)<<16), s.y+(P_RandomRange(-30, 30)<<16), s.z+(P_RandomRange(45, 1)<<16), MT_SUPERSPARK)
		else
			ghs = P_SpawnMobj(s.x+(P_RandomRange(-125, 125)<<16), s.y+(P_RandomRange(-125, 125)<<16), s.z+(P_RandomRange(15, -20)<<16), MT_SPARK)
		end ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
		
		if not s.deathboltstart
			s.destscale = 10<<16
			s.scalespeed = $*2
			P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_EXPLODE)
			P_SpawnMobj(s.x, s.y, s.z-5<<16, MT_EXPLODE)
			s.deathboltstart = true
			s.frame = (Z+1)|FF_TRANS20
			s.tics = 2
		elseif s.tics <= 1
			local FRAME = (s.frame & FF_FRAMEMASK)
			if FRAME == (Z+1)
				s.frame = (Z+2)|FF_TRANS10
				s.tics = 5
			elseif FRAME == (Z+2)
				s.frame = (Z+3)|FF_TRANS20
				s.tics = 4
			elseif FRAME == (Z+3)
				s.frame = (Z+4)|FF_TRANS30
				s.tics = 3
			elseif FRAME == (Z+4)
				s.frame = (Z+5)|FF_TRANS40
				s.tics = 2
			end
		end
	elseif s.zap local t = s.target
		if t and t.valid
			s.momx,s.momy,s.momz = t.momx,t.momy,t.momz 
		end
		if s.tics <= 1
			if s.zap <= 2
				s.sprite = SPR_SPRK
			else
				s.sprite = SPR_MPR9
				s.color = SKINCOLOR_FLAME
			end	
			local FRAME = (s.frame&FF_FRAMEMASK)
			if s.sprite == SPR_MPR9
				if FRAME == A
					FRAME = H|FF_TRANS40 s.tics = 2
				elseif FRAME == H
					FRAME = I|FF_TRANS50 s.tics = 2
				elseif FRAME == I
					FRAME = J|FF_TRANS60 s.tics = 2
				end
			else
				if FRAME == A
					FRAME = B|FF_TRANS40 s.tics = 2
				elseif FRAME == B
					FRAME = C|FF_TRANS50 s.tics = 2
				elseif FRAME == C
					FRAME = D|FF_TRANS60 s.tics = 2
				end
			end
			s.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			s.frame = ($ & ~(FF_FRAMEMASK|FF_TRANSMASK)) | FRAME | FF_FULLBRIGHT
		end
	end
	if s.fuse and (s.fuse<10) --Fade like other thok objects.
		if ((s.frame & FF_TRANSMASK) < FF_TRANS90)
			s.frame = $+FF_TRANS10
		end
	end
end, MT_SAMUSTHOK)

local function ScaleFix(s) --SRB2 doesn't do this by default, I guess.
	if not s.tracedone and s.tracer
		s.scale = s.tracer.scale
		s.tracedone = true
	end 
end
addHook("MobjThinker", ScaleFix, MT_CRUSHCLAW)
addHook("MobjThinker", ScaleFix, MT_BANPSPRING)

SAM.EnemyOverLay = function(m, COLOR, FUSE, FRAME, RFLAGS, BLEND)
	if not (m.SAM_Eoverlay and m.SAM_Eoverlay.valid)
		m.SAM_Eoverlay = P_SpawnGhostMobj(m)
	end
	local ghs = m.SAM_Eoverlay
	ghs.momx,ghs.momy,ghs.momz = m.momx,m.momy,m.momz 
	ghs.scale = m.scale
	ghs.spritexscale = m.spritexscale
	ghs.spriteyscale = m.spriteyscale
	ghs.target = m
	ghs.mirrored = m.mirrored
	ghs.rollangle = m.rollangle
	ghs.angle = m.angle
	ghs.sprite = m.sprite
	ghs.frame = (FRAME) or (m.frame & ~FF_TRANSMASK)|FF_TRANS30
	if RFLAGS
		ghs.renderflags = RFLAGS
	end
	if BLEND
		ghs.blendmode = BLEND
	end
	if FUSE
		ghs.tics,ghs.fuse = FUSE,FUSE
	else
		ghs.tics,ghs.fuse = 3,-1
	end
	ghs.color = (COLOR) or $
	ghs.colorized = true
	P_MoveOrigin(ghs,m.x,m.y,m.z) return ghs --
end

--Baby Behaviour
local function TheBabySpawn(s, m) if not (s and s.valid and m and m.valid) return end
	if m.health and not (m.flags & MF2_DONTDRAW) and m.sprite
		if not m.babycolor
			m.radius,m.height = $*2,$*2 --To make it easier to shoot.
			m.babycolor = P_RandomRange(SKINCOLOR_BONE, SKINCOLOR_YELLOW) return --
		end
		SAM.EnemyOverLay(m, m.babycolor)
	end
	if (m.type == MT_REDBUZZ)
		if (m.state == S_RBUZZLOOK1) or (m.state == S_RBUZZLOOK2)
			if not m.zoters
				m.zoters = 50
				m.renderflags = $|RF_FULLBRIGHT --They appear in dark areas usually.
			else
				m.zoters = $-1
				m.momz = (m.zoters>24) and -FRACUNIT or FRACUNIT
				m.z = (m.zoters > 24) and $-FRACUNIT or $+FRACUNIT
			end
		elseif m.zoters
			m.zoters,m.momz = 0,0
		end
	end
end
--This enemy type acts like a Metroid. Bomb or spin fast to break free.
local function TheLeecher(s, m) if not (s and s.valid and m and m.valid) return end
	if s.pouncecd
		s.pouncecd = $-1
	end
	if s.pounce
		m.metroidleech = true
		s.pounce = $+1
		if not m.target or (m.target and not m.target.health) or m.target and not P_CheckSight(m, m.target)
		or m.target and (FixedHypot(FixedHypot(m.x-m.target.x, m.y-m.target.y), m.z-m.target.z) > 1100<<16)
		or (s.pounce > 60) and m.target.player and ((m.target.player.pflags & PF_SPINNING) or m.target.player.sammorphed) and (m.target.player.speed > 28<<16)
			s.pouncecd = 60
			s.pounce = 0
			m.metroidleech = nil
			S_StartSound(m, sfx_s3k82)
			P_MoveOrigin(m, m.x, m.y, m.z+80<<16)
		end
	end
	if m.target and not s.pouncecd and P_CheckSight(m, m.target)
		if (FixedHypot(FixedHypot(m.x-m.target.x, m.y-m.target.y), m.z-m.target.z) < 580<<16)
			if not s.pounce
				s.pounce = 1
				s.plexpand = P_SpawnMobj(m.x, m.y, m.z, MT_PBEXPAND)
				S_StartSound(m, sfx_s3k82)
				S_StartSound(m, sfx_s3k41)
				if s.plexpand
					s.plexpand.color = SKINCOLOR_EMERALD
					s.plexpand.momx = m.momx/2 s.plexpand.momy = m.momy/2 s.plexpand.momz = m.momz/2
					s.plexpand.scale = $*P_RandomRange(1,2)
					s.plexpand.scalespeed = $*P_RandomRange(2, 4)
					s.plexpand.destscale = $*25
				end
			end
		end
		if s.pounce
			if (s.pounce < 12)
				m.momx = m.momx/2 m.momy = m.momy/2 m.momz = m.momz/2
			elseif (s.pounce > 12)
				m.metroidleech = true
				m.momx = FixedMul(FixedDiv(m.target.x-m.x, 600<<16), FixedDiv(132<<16, 3<<16/2))
				m.momy = FixedMul(FixedDiv(m.target.y-m.y, 600<<16), FixedDiv(132<<16, 3<<16/2))
				m.momz = FixedMul(FixedDiv(m.target.z-m.z, 600<<16), FixedDiv(132<<16, 3<<16/2))
				if (FixedHypot(FixedHypot(m.x-m.target.x, m.y-m.target.y), m.z-m.target.z) < 100<<16)
				P_MoveOrigin(m, m.target.x, m.target.y, m.target.z+m.target.height/2)
					if not (m.target.player and (m.target.player.exiting or (m.target.flags & (MF_NOCLIP|MF_NOCLIPTHING)) or m.target.player.sam_screwattacking
					or m.target.player.powers[pw_nocontrol] or m.target.player.powers[pw_flashing] or m.target.player.powers[pw_super] or m.target.player.powers[pw_invulnerability]))
						if leveltime % 19 == 0 and m.target.player
						P_SamFP(m.target.player, PAL_NUKE, 4)
						m.target.sam_systemreboot = 20
						m.target.player.viewrollangle = P_RandomRange(-14,14)*ANG1
						end
						if m.target.player and (YouAreSamus(m.target)) and (m.target.player.sam_energy and m.target.player.sam_energy > 1) and leveltime % 2 == 0
						m.target.player.sam_energy = $-1
							if m and not S_SoundPlaying(m, sfx_buzz2)
							S_StartSound(m, sfx_buzz2)
							end
						elseif (YouAreSamus(m.target) != true) and (m.target.player and m.target.player.rings) and (leveltime % 3 == 0) and m.target.player
						m.target.player.rings = $-1
							if m and not S_SoundPlaying(m, sfx_buzz2)
							S_StartSound(m, sfx_itemup)
							end
							if not m.target.player.rings
							P_PlayRinglossSound(m.target)
							m.target.player.powers[pw_flashing] = 70
							end
						elseif m.target and ((m.target.player and (m.target.player.rings <= 0) and not YouAreSamus(m.target)) or (YouAreSamus(m.target) and m.target.player.sam_energy <= 1))
						P_DamageMobj(m.target, nil, nil)
						end
					else
						m.metroidleech = nil
					end
				elseif (s.pounce > 60)
					s.pouncecd = 120
					s.pounce = 0
					m.metroidleech = nil
				end
			end
		end
	end
end
--This enemy will shock you, with some enemies like the egguard even holding teleporting powers.
local function TheBolter(s, m) if not (s and s.valid and m and m.valid) return end
	local t = m.target
	if s.LastCheckedSight
		s.LastCheckedSight = $-1
	end
	if (m.type == MT_EGGGUARD)
		if t and t.valid
			if (m.state >= S_EGGGUARD_WALK1) and (m.state <= S_EGGGUARD_WALK4)		
			and (s.LastCheckedSight or P_CheckSight(m, t))
				local SHIELD = m.tracer
				if not s.LastCheckedSight
					s.LastCheckedSight = 16
				end
				P_TryMove (m, m.x+FixedMul(180355, cos(m.angle)), m.y+FixedMul (180355, sin (m.angle)), false)
				if SHIELD and SHIELD.valid
					P_TryMove (SHIELD, 
					m.x+FixedMul(180355+m.momx, cos(m.angle)),
					m.y+FixedMul(180355+m.momy, sin(m.angle)), true)
				end
				local XYDIST = FixedHypot(m.x-t.x, m.y-t.y)
				local TDIST = FixedHypot(XYDIST, m.z-t.z)
				if not s.cctimer
					if s.cctimer == nil
						s.cctimer = 0
					end		
					if (TDIST < 1400<<16) and not (TDIST < 300<<16)
					and (P_RandomRange(15, 0) == 14)
						s.plexpand = P_SpawnMobj(m.x, m.y, m.z, MT_PBEXPAND)
						S_StartSound(m, sfx_s3k5a)
						S_StartSound(m, sfx_s3k8e)
						if s.plexpand
							s.plexpand.momx,s.plexpand.momy,s.plexpand.momz = m.momx/2,m.momy/2,m.momz/2
							s.plexpand.scale = $*2
							s.plexpand.scalespeed = $*3
							s.plexpand.destscale = $*25
						end
						s.cctimer = 180
					end
				elseif s.cctimer
					if s.cctimer == 150 and t and t.player	
						s.cctimer = 149
						if (XYDIST > 2000<<16)
						or (m.z < t.z-450<<16)
						or (m.z > t.z+600<<16)
							return --
						end
									
						local ghs = P_SpawnGhostMobj(m)	
						ghs.destscale = $*99 ghs.scalespeed = $*2
						ghs.blendmode = AST_ADD
						P_TryMove(m, t.x+FixedMul(280<<16+(t.player.speed*5), cos(t.angle)), t.y+FixedMul (280<<16+(t.player.speed*5), sin (t.angle)), true)
						m.z = (t.z-8<<16)+(t.player.aiming/50)-(t.momz*4)	
					
					
						if SHIELD and SHIELD.valid 
							P_MoveOrigin(SHIELD, m.x+FixedMul(180355+m.momx, cos(m.angle)), m.y+FixedMul (180355+m.momy, sin (m.angle)), m.z)
						end
						S_StartSound(m, sfx_s3k41)
						A_SAMUSEXPLOSIONS(m, 22, MT_IVSP, false, 4000)
						A_SAMUSEXPLOSIONS(m, 16, MT_SUPERSPARK, false, 2200)
					end
					if s.cctimer > 130
						if (s.cctimer % 2 == 0)
							m.flags2 = $ & ~MF2_DONTDRAW
							if SHIELD and SHIELD.valid
								SHIELD.flags2 = $ & ~MF2_DONTDRAW
							end
						else
							m.flags2 = $|MF2_DONTDRAW
							if SHIELD and SHIELD.valid
								SHIELD.flags2 = $|MF2_DONTDRAW
							end
						end					
					end
					if (s.cctimer > 129)
						m.flags2 = $ & ~MF2_DONTDRAW
						if SHIELD and SHIELD.valid
							SHIELD.flags2 = $ & ~MF2_DONTDRAW
						end
						if m.tics != -1 and m.tics
							m.tics = $+1
						end
						m.momx,m.momy,m.momz = 0,0,2
						if t
							A_FaceTarget(m)
						end
					end
					s.cctimer = $-1
				end
			end
		end
	elseif (m.type == MT_GSNAPPER) 
		if (m.state == S_GSNAPPER2) and t and P_CheckSight(m, t)
			P_TryMove(m, m.x+FixedMul(320355, cos(m.angle)), m.y+FixedMul (320355, sin (m.angle)), false)
		end
	elseif (m.type == MT_SPRINGSHELL) or (m.type == MT_YELLOWSHELL)
		if t and not (m.state == S_SSHELL_STND) and not (m.state == S_YSHELL_STND) and P_CheckSight(m, t)
			P_TryMove(m, m.x+FixedMul(240355, cos(m.angle)), m.y+FixedMul (240355, sin (m.angle)), false)
		end
	end
	if not s.bolttimer
		if (m.type == MT_GFZFISH) --Don't do it too often.
			s.bolttimer = P_RandomRange(170, 260)
		else
			s.bolttimer = (s.bolttimer == nil) and P_RandomRange(61, 102) or P_RandomRange(95, 190)
		end
	end
	if not (m and m.valid) return end --
	
	if t and t.valid
	or (m.type == MT_GFZFISH)
	or (m.type == MT_BUGGLE) and (abs(m.momx)+abs(m.momy) > m.scale/3)
		if (m.type == MT_GFZFISH) 
		or t and (s.LastCheckedSight or P_CheckSight(m, t))
			if not s.LastCheckedSight
				s.LastCheckedSight = 28
			end	
			if (s.bolttimer < 70)
				if (s.bolttimer < 45)
					if not (s.bolttimer < 32)
						if P_IsObjectOnGround(m)
							A_SAMPARTICLE(s, MT_MPR4, 50, 2, 1, 6, SKINCOLOR_BLACK, P_RandomRange(21355, 42353) )
						else
							s.smontracker = P_SpawnMobj(
							m.x+P_RandomRange(-77, 77)<<16, 
							m.y+P_RandomRange(76, -77)<<16, 
							m.z+P_RandomRange(-30, 30)<<16, MT_SUPERSPARK)
						end	
					end
				else --and s.bolttimer >= 45
					if P_IsObjectOnGround(m)
						A_SAMPARTICLE(m, MT_MPR4, 50, 2, 1, 6, SKINCOLOR_GOLD, P_RandomRange(27355, 58353) )
					elseif m
						s.smontracker = P_SpawnMobj(
						m.x+ P_RandomRange(-77, 77)<<16,
						m.y+P_RandomRange(77,-77)<<16,
						m.z+P_RandomRange(-30, 30)<<16, MT_IVSP)
					end
				end
			else
				s.bolttimer = max($-1,0)
			end
		end
	end
	if (s.bolttimer <= 70) --Always play at this point.
		if (s.bolttimer == 70)
			S_StopSoundByID(m, sfx_wvcm2)
			S_StartSound(m, sfx_wvcm2)
		elseif s.bolttimer == 30
			S_StopSoundByID(m, sfx_wvcm)
			S_StartSound(m, sfx_wvcm)
			
			local ghs = P_SpawnMobj(m.x, m.y, m.z+m.height/2, MT_SAMMISSILELIGHT)
			ghs.scale = m.scale/10
			ghs.momx,ghs.momy,ghs.momz = $+m.momx*2/3,$+m.momy*2/3,$+m.momz/2
			ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.blendmode = AST_ADD
			ghs.scalespeed = 5000
			ghs.color = SKINCOLOR_SUPERGOLD4
			ghs.layers = 4
			
			if P_IsObjectOnGround(m) or (m.z <= m.floorz+150<<16)
				local ghs = SamShinySplat(m,SKINCOLOR_SUPERGOLD4, 15)
				ghs.frame = A|FF_TRANS50|FF_FULLBRIGHT
				ghs.momx,ghs.momy = $+m.momx/3,$+m.momy/3
			end
			
		elseif (s.bolttimer < 30) //and (s.bolttimer > 1)
		
			S_StartSound(m, sfx_cmol)
			s.smontracker = P_SpawnMobjFromMobj(m,
			P_RandomRange(-150, 150)<<16,
			P_RandomRange(-150, 150)<<16, 
			P_RandomRange(-40, 60)<<16, MT_SAMUSTHOK)
			
			local ghs = s.smontracker
			ghs.flags = MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_BOUNCE|MF_GRENADEBOUNCE
			ghs.scale = m.scale
			ghs.target = m
			ghs.bolterattack = true
			ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.blendmode = AST_ADD
			ghs.sprite = SPR_SPRK
			ghs.frame = A|FF_TRANS30
			ghs.height = 45<<16
			ghs.radius = 40<<16
			ghs.zap = P_RandomRange( 1, 4)
			ghs.tics = 3
			
			if s.bolttimer%4==0
				local ghs = SAM.EnemyOverLay(m,(s.bolttimer%8==0) and SKINCOLOR_SUPERGOLD5 or SKINCOLOR_JET, 3, nil,(s.bolttimer%8==0) and RF_FULLDARK|RF_NOCOLORMAPS or RF_FULLDARK|RF_NOCOLORMAPS)
				if ghs and ghs.valid
					ghs.dispoffset = 7
				end
			end
		end
		s.bolttimer = max($-1,0)
	end
end
--Improved air control for these guys.
local function TheFloater(s, m) if not (s and s.valid and m and m.valid) return end
	if s.LastCheckedSight
		s.LastCheckedSight = $-1
	end
	local t = m.target
	if (m.type == MT_VULTURE)
		if (m.state == S_VULTURE_ZOOM1)
			m.flags = $|MF_FLOAT|MF_NOGRAVITY
			if t.z+t.height < m.z
				m.momz = -3<<16
			elseif t.z > m.z
				m.momz = 3<<16
			end			
		end	
		if t
			if (leveltime % 8 == 0)
				S_StartSound(m, sfx_gbeep)
			end
		elseif (leveltime % 35 == 0)
			S_StartSound(m, sfx_gbeep)
		end
		if not (m.kamibomb and m.kamibomb.valid)
			if m.health
				m.kamibomb = P_SpawnMobj(m.x, m.y, m.z, MT_THOK)
				m.kamibomb.sprite = SPR_NPLM
				m.kamibomb.frame = A
			end
		elseif (leveltime%2==0)
			local BOMB = m.kamibomb
			BOMB.sprite,BOMB.frame = SPR_NPLM,A
			BOMB.tics = 3
			BOMB.scale = 100000
			P_MoveOrigin(BOMB, m.x+m.momx, m.y+m.momy, m.z+m.height/2+m.momz)
			if m.kamibomb and m.kamibomb.valid and t --Check that it's still there after moving
				local TDIST = FixedHypot(FixedHypot(m.x-t.x, m.y-t.y), m.z-t.z)
				if TDIST <= 192<<16 or not m.health 			
					local ghs = P_SpawnMobj(m.x, m.y, m.z+m.height/2, MT_THROWNEXPLOSION)
					m.kamibomb.state = S_NULL
					if ghs and ghs.valid
						ghs.kamibomb = true
						S_StartSound(ghs, sfx_bexpld)
						A_samquake(m, 12<<16, 4)
						ghs.sprite,ghs.frame = SPR_NPLM,A
						P_ExplodeMissile(ghs)
					end
					return --
				end
			end
		end
		if m.kamibomb and m.kamibomb.valid and m and m.valid and m.health 
			m.kamibomb.sprite = SPR_NPLM
			m.kamibomb.frame = (leveltime%2) and B or A
		end
	else --not a vulture
		--This enemy has exceptional flying powers, usually with some extra abilities.
		if (m.type == MT_UNIDUS)
			if s.mguncd == nil s.mguncd = 30
			elseif s.mguncd and t s.mguncd = $-1 --CD goes down quicker with a target.
			end
			if m.UniBig == nil
				m.UniBig,m.scale = true,$*2
				searchBlockmap("objects", function(ref, mobj)
					if mobj and mobj.type == MT_UNIBALL
						mobj.scale = m.scale
						mobj.spritexscale = $*4/3
						mobj.spriteyscale = $*4/3
						mobj.spriteyoffset = $-3<<16
					end
				end, m, m.x-160<<16, m.x+160<<16, m.y-160<<16, m.y+160<<16)					
			end
			if t and not s.mguncd
				if not s.mgunspin 
					s.mgunspin = 1
					s.plexpand = P_SpawnMobj(m.x, m.y, m.z, MT_PBEXPAND)
					S_StartSound(m, sfx_s3k5a)
					S_StartSound(m, sfx_s3k8e)
					if s.plexpand
						s.plexpand.momx = m.momx/2
						s.plexpand.momy = m.momy/2
						s.plexpand.momz = m.momz/2
						s.plexpand.scale = $*P_RandomRange(1,2)
						s.plexpand.scalespeed = $*P_RandomRange(2, 4)
						s.plexpand.destscale = $*25
					end
				else
					s.mgunspin = $+1
					if s.LastCheckedSight and t.valid --Zoom!
						if P_TryMove(m, m.x+FixedMul(m.scale, cos(m.angle)),m.y+FixedMul(m.scale, sin(m.angle)), true)
							local ghs = P_SpawnGhostMobj(m)
							ghs.fuse,ghs.tics = 11,11
							ghs.destscale = 1
							ghs.renderflags = RF_NOCOLORMAPS|RF_SEMIBRIGHT
							ghs.dispoffset = -20
							ghs.color,ghs.colorized = SKINCOLOR_FLAME, true
						end
					end
					if (s.mgunspin > 25)	
						if (s.LastCheckedSight or P_CheckSight(m, t))
							if not s.LastCheckedSight
								s.LastCheckedSight = 6
							end
							S_StartSound(m, sfx_s3k54)
							
							s.tryit = P_SpawnPointMissile(m, 
							t.x + (t.momx*9), 
							t.y + (t.momy*9), 
							t.z + t.height/2 + (t.momz*6),
							MT_ENERGYBALL,
							m.x, m.y, m.z + m.height/2 )
							if s.tryit and s.tryit.valid
								s.tryit.flags = $|MF_MISSILE & ~(MF_PAIN|MF_NOCLIPHEIGHT|MF_NOCLIP)
								s.tryit.momx,s.tryit.momy,s.tryit.momz = $*5/6,$*5/6,$*5/6
								s.tryit.scale = 35355
								s.tryit.destscale = 70710 
								s.tryit.scalespeed = $/4
							end
						end
						s.mguncd = 105
						s.mgunspin = 0
					end
				end
			end
		elseif m.type == MT_REDCRAWLA
			local ghs = P_SpawnMobj(m.x, m.y, m.z-5<<16, MT_SAMCHARGEGFX)
			ghs.scale = m.scale/(P_RandomRange(5,20))
			ghs.color = SKINCOLOR_PINK
			ghs.momx,ghs.momy = s.momx/2,s.momy/2
			m.flags = $|MF_FLOAT|MF_NOGRAVITY
			if t and (s.state != S_SPOS_STND)
				if not s.sideswing 
					if P_RandomRange(0, 100) == 99
						s.sideswing = P_RandomRange(9, 14)
						s.sideswingdirect = P_RandomRange(0, 1) 
					end
				else --if s.sideswing
					s.sideswing = $-1
					A_FaceTarget(m)
					if s.sideswingdirect 
						P_InstaThrust(m, m.angle+ANGLE_90, 10<<16)
					else
						P_Thrust(m, m.angle-ANGLE_90, 10<<16)
					end
				end
				if not s.sideswing
					local TDIST = FixedHypot(FixedHypot(m.x-t.x, m.y-t.y), m.z-t.z)
					if TDIST > 1500<<16
						A_FaceTarget(m)
						P_InstaThrust(m, m.angle, 12<<16)
					else
						P_InstaThrust(m, m.angle, 7<<16)
					end
				end
				if (leveltime%2)
					P_SpawnGhostMobj(m)
				end
			end
		end
		m.flags = $|MF_FLOAT|MF_NOGRAVITY
		if t
			if t.z+t.height < m.z
				m.momz = -3<<16
			elseif t.z > m.z
				m.momz = 3<<16
			end
		end		
	end
end
--Machine Gunner speaks for itself, no? Typically very dangerous foes
local function TheMachineGunner(s, m) if not (s and s.valid and m and m.valid) return end
	if m.IsAShield or not (m.target and m.target.valid)
		return	--
	end
	if s.mguncd == nil 
		s.mguncd = 30
	end	
	local t = m.target
	
	if s.mguncd
		s.mguncd = $-1
	else --if not s.mguncd
		if not s.mgunspin 
			s.mgunspin = 1
			S_StartSound(m, sfx_s3k5a)
			S_StartSound(m, sfx_s3k8e)		
			s.plexpand = P_SpawnMobj(m.x, m.y, m.z, MT_PBEXPAND)
			if s.plexpand
				s.plexpand.momx,s.plexpand.momy,s.plexpand.momz = m.momx/2,m.momy/2,m.momz/2
				s.plexpand.scale = $*P_RandomRange(1, 2)
				s.plexpand.scalespeed = $*P_RandomRange(4,2)
				s.plexpand.destscale = $*25
			end
		else
			s.mgunspin = $+1
			if s.mgunspin == 23
				s.mgunstrafe = P_RandomRange(0, 1)
			elseif (s.mgunspin > 25)
				if (m.type == MT_JETTGUNNER) or (m.type == MT_CRAWLACOMMANDER) or m.type == MT_CACOLANTERN
					if leveltime % 2 == 0 and P_CheckSight(m, t)
						P_SpawnGhostMobj(m)
						A_FaceTarget(m)
						P_InstaThrust(m, m.angle+ANGLE_90, (s.mgunstrafe) and 15<<16 or -15<<16)
						if m.type == MT_CACOLANTERN
							P_SpawnPointMissile(m, t.x+(t.momx*15), t.y+t.momy*15, t.z+t.momz*9, MT_CACOFIRE, m.x, m.y, m.z+m.height/2)
						else
							S_StartSound(m, sfx_s3k4d)
							P_SpawnPointMissile(m, t.x+(t.momx*15), t.y+t.momy*15, t.z+t.momz*9, MT_JETTBULLET, m.x, m.y, m.z+m.height/2)
						end
					end
					if (s.mgunspin > 40)
						s.mguncd = 105
						s.mgunspin = 0
						if m.type == MT_CACOLANTERN
							P_InstaThrust(m, m.angle, 5<<16)
						end
					end
				elseif (m.type == MT_POPUPTURRET) and not m.IsAShield
					if (s.LastCheckedSight or P_CheckSight(m, t))
						if not s.LastCheckedSight
							s.LastCheckedSight = 12
						end
						m.sprite = SPR_TURR
						m.frame = I
						S_StartSound(m, sfx_trfire)
						P_SpawnMissile(m, t, MT_TURRETLASER)
					end
					if m and m.valid and (s.mgunspin > 59)
						m.reactiontime = 1
						m.state = S_TURRETPOPDOWN2
						s.mguncd = 105
						s.mgunspin = 0
					end
				elseif (m.type == MT_SNAILER)
					if leveltime % 4 == 0 
					and (s.LastCheckedSight or P_CheckSight(m, t))
						if not s.LastCheckedSight
							s.LastCheckedSight = 16
						end
						S_StartSound(m, sfx_rlaunc)
						s.tryit = P_SpawnPointMissile(m, t.x+(t.momx*25), t.y+t.momy*25, t.z+t.momz*18, MT_ROCKET, m.x, m.y, m.z+m.height/2)
						if s.tryit and s.tryit.valid
							s.tryit.destscale = s.scale*3 
							s.tryit.scalespeed = $/3
						end
					end
					if (s.mgunspin > 70)
						s.mguncd = 105
						s.mgunspin = 0
					end
				elseif (m.type == MT_DRAGONBOMBER)
					S_StartSound(m, sfx_trfire)
					P_SpawnMissile(m, t, MT_TURRETLASER)
					if (s.mgunspin > 70)
						s.mguncd = 105
						s.mgunspin = 0
					end									
				end
			end
		end
	end
end
local function TheRammer(s, m) if not (s and s.valid and m and m.valid) return end
	local t = m.target
	if s.LastCheckedSight
		s.LastCheckedSight = $-1
	end
	if (m.type == MT_FACESTABBER) and not (m.state == S_FACESTABBER_CHARGE4)
	or (m.type == MT_GSNAPPER) and not (m.state == S_GSNAPPER_STND) 
		if t and t.valid
			if P_IsObjectOnGround(m)
			and (s.LastCheckedSight or P_CheckSight(m, t))
				if not s.LastCheckedSight
					s.LastCheckedSight = 18
				end
				P_TryMove (m, m.x+FixedMul(160355, cos(m.angle)), m.y+FixedMul (160355, sin (m.angle)), false)
			end
		end
	end
	if m.dodgecd
		m.dodgecd = $-1
		m.dodgeret = false
		if (m.dodgecd > 58)
			if m.dodgecd == 69 --First tic
				S_StartSound(m, sfx_s3ka6)
				S_StartSound(m, sfx_s3kb6)
				S_StartSound(m, sfx_s3k82)
				S_StartSound(m, sfx_s3k9e)
				S_StartSound(m, sfx_s3k9e)
				if (m.type == MT_JETJAW)
					s.fishdodge = (P_RandomRange(0,1)) and true or false
				end
				m.dodgecd = 68
			else
				if m.samroll == nil m.samfroll = ANG30 end
				m.samfroll = $+ANG30
				m.rollangle = m.samfroll
				if (m.type == MT_JETJAW)
					P_SpawnGhostMobj(m)
					P_InstaThrust(m, m.angle+(s.fishdodge and ANGLE_90 or -ANGLE_90), 15<<16)
				end
			end
		elseif m.samfroll
			m.samfroll = nil
			m.rollangle = 0
		end
	else
		m.dodgeret = true
	end
	if s.pouncecd
		s.pouncecd = $-1
	end
	if s.pounce
		s.pounce = $+1
		if (s.pounce > 30)
			s.pouncecd = 60
			s.pounce = 0
		end
	end
	local DODGE = m.dodgecd or 0
	if t and not s.pouncecd and not (DODGE > 40)
	and (s.LastCheckedSight or P_CheckSight(m, t))
		if not s.LastCheckedSight
			s.LastCheckedSight = 24
		end
		if (FixedHypot(FixedHypot(m.x-t.x, m.y-t.y), m.z-t.z) < 640<<16)
			if not s.pounce
				s.pounce = 1
				s.plexpand = P_SpawnMobj(m.x, m.y, m.z, MT_PBEXPAND)
				local ghs = s.plexpand
				S_StartSound(m, sfx_s3k82)
				S_StartSound(m, sfx_s3kb6)
				if ghs
					ghs.color = SKINCOLOR_CLOUDY
					ghs.momx,ghs.momy,ghs.momz = m.momx/2,m.momy/2,m.momz/2
					ghs.scale = $*P_RandomRange(1,2)
					ghs.scalespeed = $*P_RandomRange(2, 4)
					ghs.destscale = $*25
				end
				if (m.type == MT_GSNAPPER)
					P_SetObjectMomZ(m, 10<<16, true)
					m.momx,m.momy = 0,0
				end
			end
		elseif (m.type == MT_REDBUZZ) and not (m.state == S_RBUZZLOOK1) and not (m.state == S_RBUZZLOOK2) and not s.pounce
			P_TryMove (m, m.x+FixedMul(240355, cos(m.angle)), m.y+FixedMul (240355, sin (m.angle)), false)
		end
		if s.pounce
			if s.pounce == 12
				if (m.type == MT_GSNAPPER)
				or P_IsObjectOnGround(m) and not (m.flags & MF_NOGRAVITY) and not (m.type == MT_SKIM)
					A_FaceTarget(m)
					P_InstaThrust(m, m.angle, 31<<16)
					P_SetObjectMomZ(m, 6<<16, true)
					if (m.type == MT_GSNAPPER)
						m.momz = m.momz/9
						S_StartSound(m, sfx_thok)
						P_SpawnMobj(m.x, m.y, m.z+m.height/2, MT_THOK)
						if (FixedHypot(m.x-t.x, m.y-t.y) < 230<<16)
							P_SetObjectMomZ(m, -15<<16, true)
						end
					end
				end
				if not (m.flags & MF_NOGRAVITY) and not P_IsObjectOnGround(m) and not (m.type == MT_GSNAPPER)
					s.pounce = 0
				else
					s.pounce = 13
				end
			elseif (s.pounce < 12)
				m.momx,m.momy = $/2,$/2
				if (m.type == MT_GSNAPPER)
					if s.pounce==2
						m.target = nil
					end
					P_SpawnGhostMobj(m)
				else
					m.momz = $/2
				end
			elseif (s.pounce > 12)
				if (m.flags & MF_NOGRAVITY)
				or (m.type == MT_SKIM)
					if not ((m.type == MT_SKIM) and not (m.eflags & MFE_TOUCHWATER))
						A_FaceTarget(m)
						P_SpawnGhostMobj(m)
						m.momx = FixedMul(FixedDiv(t.x-m.x, 500<<16), FixedDiv(132<<16, 3<<16/2))
						m.momy = FixedMul(FixedDiv(t.y-m.y, 500<<16), FixedDiv(132<<16, 3<<16/2))
						if (leveltime % 4 == 0) 
							if (m.type == MT_JETTBOMBER) or (m.type == MT_SKIM)
								local ghs = P_SpawnMobj(m.x, m.y, m.z+m.height/3, MT_MINE)
								if ghs and ghs.valid
									ghs.target = m
									S_StartSound(m, sfx_s3k51)
									if (t.z+(t.height*4) < m.z)
										m.momz = 5<<16
									end
								end
							end
						end
						if not (m.type == MT_JETTBOMBER)
							m.momz = FixedMul(FixedDiv(t.z-m.z, 500<<16), FixedDiv(132<<16, 3<<16/2))
						end
					end
				elseif not (m.type == MT_SKIM)
					if not (m.type == MT_GSNAPPER)
						P_SpawnGhostMobj(m)
						if m.type == MT_FACESTABBER
							m.sprite = SPR_CBFS
							m.frame = H
						end	
					end
				end
			end
		end
	end
end
local function TheFlamer(s, m) if not (s and s.valid and m and m.valid) return end
	--The flamer has a flamethrower. Some have better range or reaction time.
	if not m.startupflame
		if m.type == MT_POPHAT
			m.scale = $*2
			m.thetank = true
			m.health = $+1
		end
		m.startupflame = true
	end
	if s.flamercooldown and not s.tryitstartup
		s.flamercooldown = max($-1,0)
	end
	if s.LastCheckedSight
		s.LastCheckedSight = $-1
	end
	local t = m.target
	if not (t and t.valid and t.health)
		s.tryitstartup = 0
	else
		if s.flamercooldown and not s.tryitstartup
			s.flamercooldown = max($-1,0) --Cool down faster with a target.
		end
		if not s.tryitstartup
			if not s.flamercooldown
				local CHECKDIST = ((m.type == MT_ROBOHOOD) or (m.type == MT_PYREFLY)) and 1200<<16 or 400<<16
				if (FixedHypot(FixedHypot(m.x-t.x, m.y-t.y), m.z-t.z) < CHECKDIST)
					s.tryitstartup = 1
				
					s.plexpand = P_SpawnMobj(m.x, m.y, m.z, MT_PBEXPAND)
					S_StartSound(m, sfx_s3k82)
					S_StartSound(m, sfx_s3kb6)
					if s.plexpand
						s.plexpand.color = SKINCOLOR_CLOUDY
						s.plexpand.momx,s.plexpand.momy,s.plexpand.momz = m.momx/2,m.momy/2,m.momz/2
						s.plexpand.scale = $*2
						s.plexpand.scalespeed = $*3
						s.plexpand.destscale = $*25
					end
				end
			end
		else
			if (s.tryitstartup < 11)
				if (m.type == MT_BLUECRAWLA)
					if not (leveltime%3==0) --Slower to start.
						s.tryitstartup = $+1
					end
					if not (m.state == S_POSS_STND) --Make these guys move a bit faster.
						P_TryMove (m, m.x+FixedMul(m.scale*3, cos(m.angle)), m.y+FixedMul(m.scale*3, sin(m.angle)), false)
					end			
				else
					s.tryitstartup = $+1
				end
			elseif (s.tryitstartup < 41)
				if (s.tryitstartup > 26)
					if (m.type == MT_MINUS) or (m.type == MT_BLUECRAWLA)
						s.flamercooldown = 38 s.tryitstartup = 0 return --
					end
				end
				if (m.type == MT_MINUS) 
					if P_IsObjectOnGround(m)
					or (m.state >= S_MINUS_DIGGING1) and (m.state <= S_MINUS_DIGGING4)
						m.state = S_MINUS_POPUP
					end
				end
				s.tryitstartup = $+1
				
				if not (m.type == MT_ROBOHOOD) and (leveltime%3==0)
				or (m.type == MT_ROBOHOOD) and (leveltime%5==0)
					local ARROW,ghs
					if (m.type == MT_ROBOHOOD)
						ARROW = P_SpawnXYZMissile(m, t, MT_ARROW, m.x, m.y, m.z+m.momz+(44*m.scale))
						if ARROW and ARROW.valid and not P_IsObjectOnGround(ARROW)
							ghs = P_SpawnMissile(m, t, (m.type == MT_POPHAT) and MT_GREENFLAME or MT_CYBRAKDEMON_FLAMESHOT)
						end
					else
						ghs = P_SpawnMissile(m, t, (m.type == MT_POPHAT) and MT_GREENFLAME or MT_CYBRAKDEMON_FLAMESHOT)
					end
					if ghs and ghs.valid
						s.tryit = ghs
						ghs.target,ghs.mahflamer = m,m
						ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
						ghs.rollangle = P_RandomRange(-40,40)*ANG1
						ghs.blendmode = AST_ADD
						ghs.destscale = $*3
						if m.type == MT_ROBOHOOD --Bouncing fire arrows!
							ghs.fuse = 42
							if ARROW and ARROW.valid
								ghs.flags,ghs.flags2 = ARROW.flags,ARROW.flags2
								ARROW.flags = $|MF_GRENADEBOUNCE
								ARROW.fuse = 63
								ghs.height = ARROW.height
								ghs.spriteyscale,ghs.spritexscale = $*2/3,$*2/3
								ghs.dispoffset = -133
								ghs.momx,ghs.momy,ghs.momz = ARROW.momx,ARROW.momy,ARROW.momz+(99*P_MobjFlip(ARROW))
								ghs.frame = ($ & ~FF_TRANSMASK)|FF_TRANS60
								if (leveltime%10==0)
									ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING|MF_NOBLOCKMAP & ~(MF_SOLID|MF_PAIN|MF_FIRE)
									ghs.color,ghs.colorized = SKINCOLOR_KETCHUP, true
								else
									ghs.fuse = 99
								end
								P_MoveOrigin(ghs, ARROW.x, ARROW.y,ARROW.z+(ARROW.height/2)) --Fire arrows!
							end
						else
							ghs.flags = $|MF_NOCLIPHEIGHT|MF_MISSILE & ~MF_SCENERY
							if m.type == MT_PYREFLY
								ghs.fuse = 33
							else
								ghs.momz = $/2
								ghs.fuse = 15
							end
							if ghs and (ghs.momz <= 0)
								P_SetObjectMomZ(ghs, FRACUNIT, false)
							end							
						end
					end
					if not (t and t.valid)
					or not s.LastCheckedSight and not P_CheckSight(m, t)
						if not s.LastCheckedSight
							s.LastCheckedSight = 22
						end
						s.tryitstartup = 0 return --
					end					
				end
			else
				s.tryitstartup = 0
				s.flamercooldown = 51
				s.LastCheckedSight = 4
			end
		end
	end
end

local FlashMobjC={SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERORANGE5,SKINCOLOR_RED, SKINCOLOR_WHITE, SKINCOLOR_SUPERGOLD3}
//The SMONtracker tracks a target and will modify it's behaviour without having to create new states/thingtypes.
addHook("MobjThinker", function(s) if not s.valid return end
	if s.gotmestorage and (s.tics > 20)
		s.tics = 20
	end
	if s.mymon
		if (s.tics == 1)
			local ghs = P_SpawnMobj(s.x, s.y, s.z, s.mymon)
			ghs.eflags = s.pp
			ghs.flags2 = s.pp2
			if s.gotmestorage
				ghs.samgotme = s.gotmestorage
			end
			if s.gotmestoragehost
				ghs.samgotmehost = true 
			end
			s.state = S_NULL return --
		end	
	end
	local t = s.target local m = t 
	if not (t and t.valid)
		s.state = S_NULL return --No point to exist without a target.
	end
	s.tics,s.fuse = 7,7 --Keep the tracker at 7 tics so it doesn't disappear until it's target does
	if s.starposttracker 
		if not s.monstart3
			if not s.target.montargetedyet3
				s.target.montargetedyet3 = true
				s.monstart3 = true
			elseif s and s.valid
				s.state = S_NULL return --
			end
		end
		t.tics = $+1
		t.sprite = SPR_MPR1
		t.frame = O|FF_TRANS20
		if not s.scaler
			t.destscale = $*10/6 
			s.scaler = true
		end
		if (t.state != S_STARPOST_IDLE) 
			t.color = (leveltime%3==0) and SKINCOLOR_ORANGE or SKINCOLOR_SUPERGOLD3
		else
			t.color = SKINCOLOR_RED
		end
		return --
	end
	if s.thebaby
		if m.health and not s.thebabyspawned
			local ghs 
			local FISHY = ((m.type == MT_CRUSHSTACEAN) or (m.type == MT_BANPYURA) or (m.type == MT_JETJAW)) and true or false
			--This type spawns a baby once, then goes towards other behaviour. Because of this, subtypes like rammer are possible.
			for d = 2,4
				if FISHY
					if d != 3
						ghs = P_SpawnMobj(
						m.x+FixedMul(210<<16, cos(m.angle+ANGLE_90*d)), 
						m.y+FixedMul(210<<16, sin(m.angle+ANGLE_90*d)), m.z, m.type)
						if ghs and ghs.valid
							ghs.scale = m.scale/2
							ghs.flags,ghs.flags2,ghs.eflags = m.flags,m.flags2,m.eflags
							ghs.othermom = m
							ghs.thebabyspawn,ghs.notabee = true,true
							
							if not (m.FoeTracked and m.FoeTracked.valid) --MT_SFOETRACKER
								m.smontracker = P_SpawnMobj(m.x, m.y, m.z, MT_SFOETRACKER)
								m.smontracker.target = ghs
								m.smontracker.thebabyspawn = true
								m.smontracker.notabee = true
								m.smontracker.othermom = m
							end
						end
					end
				else --if d != 1
					if m.type == MT_PTERABYTE
						ghs = P_SpawnMobj(
						m.x+FixedMul(180<<16, cos(m.angle+ANGLE_112h*d)), 
						m.y+FixedMul(180<<16, sin(m.angle+ANGLE_112h*d)),
						m.z-250<<16+(d*(100<<16)), MT_PYREFLY)
						if ghs and ghs.valid
							ghs.scale = m.scale/2
							ghs.radius = $*2
							ghs.height = $*2
						end
					else
						ghs = P_SpawnMobj(
						m.x+FixedMul(140<<16, cos(m.angle+ANGLE_112h*d)),
						m.y+FixedMul(140<<16, sin(m.angle+ANGLE_112h*d)),
						m.z, MT_REDBUZZ)
						if ghs and ghs.valid
							ghs.scale = m.scale/3
							ghs.thebabyspawn = true
							ghs.othermom = m
							
							if not (m.FoeTracked and m.FoeTracked.valid) --MT_SFOETRACKER
								m.smontracker = P_SpawnMobj(m.x, m.y, m.z, MT_SFOETRACKER)
								m.smontracker.target = ghs
								m.smontracker.thebabyspawn = true
								m.smontracker.othermom = m
							end
						end
					end
				end
			end
			s.thebabyspawned = true
		end
	end
	
	if s.flashingt and t and t.valid
		if not (t.type == MT_METROID or t.type == MT_SUPERMETROID or t.type == MT_METALSONIC_BATTLE)
			--Make enemies flash when Samus shoots them!
			if m.gavecolorpermission == nil
				m.gavecolorpermission = (not m.color) --Careful not to break enemies with colors!
			end
			if not s.monstart2
				if not m.montargetedyet2 and not (m.flags2 & (MF2_DONTDRAW|MF2_FRET)) and not m.superbrak
					m.montargetedyet2 = true
					s.monstart2 = true
				elseif s.valid
					s.state = S_NULL return --
				end
			end
			if (s.flashingt%2==0) and (s.flashingt > 1)
				m.flags2 = $|MF2_DONTDRAW
			else
				local ghs = SAM.EnemyOverLay(m, FlashMobjC[P_RandomRange(1,5)], 3, m.frame, RF_FULLBRIGHT|RF_NOCOLORMAPS)
				if ghs and ghs.valid	
					ghs.tics = 3
					ghs.fuse = 99
					ghs.frame = $ & ~FF_TRANSMASK
					ghs.dispoffset = 150
					ghs.flags2 = $ & ~MF2_DONTDRAW
					ghs.spritexoffset = m.spritexoffset+P_RandomRange(-3,3)<<16
					ghs.spriteyoffset = m.spriteyoffset+P_RandomRange(0,3)<<16
					ghs.spritexscale = m.spritexscale+9000
					ghs.spriteyscale = m.spriteyscale+9000
					if (s.flashingt>=5) or (s.flashingt==2)
						if P_IsObjectOnGround(m)
							local ghs = P_SpawnMobjFromMobj(m,0,0,0, MT_EXPLODE)
							ghs.spritexscale = $*3/2
							ghs.spriteyscale = $/2
							ghs.dispoffset = 199
							local ghs = P_SpawnMobjFromMobj(m,0,0,0, MT_SPINDUST)
							ghs.dispoffset = 250
							ghs.spritexscale = $*4/3
						end
					end
				end
				if m.gavecolorpermission != nil
					m.color = FlashMobjC[P_RandomRange(1,5)]
					m.colorized = true
				end
				m.flags2 = $ & ~MF2_DONTDRAW
				if (s.flashingt <= 1) and s.valid
					if m and m.valid
						m.montargetedyet2 = nil
						m.flags2 = $ & ~MF2_DONTDRAW
						if m.gavecolorpermission != nil
							m.color = 0
							m.colorized = false
						end		
					end
					s.state = S_NULL return --
				end				
			end
			s.flashingt = max($-1,0)
		end
	end	
end, MT_SMONTRACKER)

--Seperate HyperMode tracker for HyperMode Enemies to ease on Lua strain. 
local function FoeTracker(s,t)
	t.FoeTracked = s --Link them to us.
	if not (t.flags & MF_BOSS)  --Okay, we're looking at hyper enemies here!
		if t.health and not t.frozenbox --Or...y'know, just s.hyperfoe as a table? Jesus.
			local m = t
			if m.spazershocked or m.waverstunned return end --You're stunned!
			
			if s.thebabyspawn
				TheBabySpawn(s, m) --Baby enemy behaviour. Slightly different from general enemies, and have less health.
			elseif s.leecher
				TheLeecher(s, m)				
			elseif s.bolter 
				TheBolter(s, m)
			elseif s.floater
				TheFloater(s, m)
			elseif s.machinegunner 
				TheMachineGunner(s, m)
			elseif s.rammer 
				TheRammer(s, m)
			elseif s.flamer 
				TheFlamer(s, m) --These are kinda like TF2 classes at this point
			elseif s.thetank
				if m.thetank
					if m.health == 1
						m.color,m.colorized = SKINCOLOR_RED,true
						if (leveltime % 6 == 0)
							local ghs = P_SpawnMobjFromMobj(m, 0, 0, m.height, MT_SMOKE)
							ghs.momz = FRACUNIT*8*P_MobjFlip(m)
							ghs.destscale = m.scale*10
							ghs.fuse = 50
						end
					end
				elseif m.health --Grant them health!
					m.thetank = true
					m.scale = $+105000
					m.health = $+1
				end
			end
		end
	else--if (t.flags & MF_BOSS) --Faster bosses + SuperBrak.		
		if t.superbrakbigjump or t.superbrakjump
			return --
		end
		for i = 1,2
			if (t.tics > 2) and (t.tics < 20)
				if t.health and not t.frozenbox  and not (t.tics == -1)
				and not ((t.state >= S_CYBRAKDEMON_VILE_ATTACK2) and (t.state <= S_CYBRAKDEMON_VILE_ATTACK6))
					if i==1
						if t.superbrak
							if not (t.health < 25)
								t.tics = $-1 continue --
							end
						elseif not (t.superbrak and (t.health < 11) and (t.tics < 7))
							t.tics = $-2 break --
						end
					elseif (t.health > 43) and not (t.health > 52)
						t.tics = $-2
					end
				end
			end
		end
	end
end
addHook("MobjThinker", function(s) if not s.valid return end --
	if not (s.target and s.target.valid) s.state = S_NULL return end --
	s.tics = 9
	FoeTracker(s, s.target)
end, MT_SFOETRACKER)

--The Gunship floats up and down and checks if it fits in the place it's in, landing/shrinking accordingly.

addHook("MobjThinker", function(s)
	if s.valid
		if s.checktimer == nil
			s.checktimer = 15
		elseif s.checktimer
			s.checktimer = $-1
			if s.checktimer == 1 and s.tracer and s.tracer.valid
				if ( ( ((s.tracer.state == S_PLAY_STND) or (s.tracer.state == S_PLAY_SPRING) or (s.tracer.state == S_PLAY_FALL))
				and not P_IsObjectOnGround(s.tracer) and not (s.tracer.player and (s.tracer.player.pflags & PF_JUMPED)))    
				or not (P_CheckSight(s, s.tracer)) and (FixedHypot(FixedHypot(s.x-s.tracer.x, s.y-s.tracer.y), s.z-s.tracer.z) > 200<<16) ) 
				
				or s.tracer.samspinpad
					s.rettp = true
					s.checktimer = 0
				end
			end
		end
		
		if s.rettp and s.tracer and s.tracer.valid and P_IsObjectOnGround(s.tracer) and (s.tracer.ceilingz > s.floorz+100<<16)
		and P_CheckPosition(s, s.tracer.x+50<<16, s.tracer.y+50<<16) and not s.tracer.samspinpad
			P_MoveOrigin(s, s.tracer.x+50<<16, s.tracer.y+50<<16, s.tracer.z+s.tracer.height/2)
			S_StartSound(s, sfx_appear)
			S_StartSound(s, sfx_appear)
			s.rettp = nil
		end
		
		if not s.bigship or (s.eflags & MFE_VERTICALFLIP)
		s.scale = 155000
		s.sss = P_SpawnPointMissile(s, s.x, s.y, s.z+s.height+160<<16, MT_SAMWALLJUMP, s.x, s.y, s.z+s.height+180<<16)
		s.ssss = P_SpawnPointMissile(s, s.x, s.y, s.z+s.height+60<<16, MT_SAMWALLJUMP, s.x, s.y, s.z+s.height+70<<16)
		s.ogmaxz = s.z+190<<16
		s.ogmaxztime = 80
		s.ogz = s.z
		s.bigship = true
		s.flags = $|MF_SOLID
			if (s.z >= s.ceilingz-50<<16)
			P_MoveOrigin(s, s.x, s.y, s.floorz)
			end
			if (s.ceilingz < s.z+s.height+180<<16)
			s.landingmode = true
			s.flags = $|MF_NOCLIPHEIGHT
			s.yougottaland = false
			elseif s.yougottaland and not ((gametype == GT_COOP) and gamemap == 23)
			s.landingmode = true
			s.flags = $|MF_NOCLIPHEIGHT
			end
			if (s.ceilingz < s.z+s.height+100<<16) or s.yougottaland and not ((gametype == GT_COOP) and gamemap == 23) and not ((gametype == GT_COOP) and gamemap == 08)
			s.scalespeed = $/4
			s.destscale = FRACUNIT
			S_StartSoundAtVolume(s, sfx_s3k72, 100)
			end
			s.downfloat = false
			s.upfloat = true
			s.maxfloat = s.z+50<<16
			if s.landingmode
				s.minfloat = s.floorz-10<<16
			else
				s.minfloat = s.z+10<<16
			end
		end

		if not S_SoundPlaying(s, sfx_s3ka1) and not s.landedmode
		S_StartSoundAtVolume(s, sfx_s3ka1, 5)
		end

		if (leveltime % 2 == 0) and not s.landedmode
		s.ship_sjmpgfx = P_SpawnMobj(s.x, s.y-120<<16, s.z-5<<16, MT_SAMCHARGEGFX)
		s.ship_sjmpgfx.scale = s.scale/(P_RandomRange(8,15))
		s.ship_sjmpgfx.color = SKINCOLOR_SKY
		s.ship_sjmpgfx.momx = s.momx/2
		s.ship_sjmpgfx.momy = s.momy/2
		s.ship_sjmpgfx = P_SpawnMobj(s.x, s.y+120<<16, s.z-5<<16, MT_SAMCHARGEGFX)
		s.ship_sjmpgfx.scale = s.scale/(P_RandomRange(8,15))
		s.ship_sjmpgfx.color = SKINCOLOR_SKY
		s.ship_sjmpgfx.momx = s.momx/2
		s.ship_sjmpgfx.momy = s.momy/2

		s.ship_sjmpgfx = P_SpawnMobj(s.x-120<<16, s.y, s.z-5<<16, MT_SAMCHARGEGFX)
		s.ship_sjmpgfx.scale = s.scale/(P_RandomRange(8,15))
		s.ship_sjmpgfx.color = SKINCOLOR_SKY
		s.ship_sjmpgfx.momx = s.momx/2
		s.ship_sjmpgfx.momy = s.momy/2
		s.ship_sjmpgfx = P_SpawnMobj(s.x+120<<16, s.y, s.z-5<<16, MT_SAMCHARGEGFX)
		s.ship_sjmpgfx.scale = s.scale/(P_RandomRange(8,15))
		s.ship_sjmpgfx.color = SKINCOLOR_SKY
		s.ship_sjmpgfx.momx = s.momx/2
		s.ship_sjmpgfx.momy = s.momy/2
			if s.landingmode 
			s.landedmode = true
			end
		end
		if s.upfloat
			if s.ogmaxztime
			s.ogmaxztime = $-1
				if (s.ogmaxztime == 1) and s.ogmaxz
					if (s.z < s.ogmaxz)
					s.scalespeed = $/4
					s.destscale = FRACUNIT
					S_StartSoundAtVolume(s, sfx_s3k72, 100)
					s.landingmode = true
					s.flags = $|MF_NOCLIPHEIGHT
					end
				end
			end
			s.ogmaxz = s.z+190<<16
			if s.landingmode
			s.downfloat = true
			s.upfloat = false
			end
			if s.z > (s.maxfloat-15<<16)
			s.momz = 32000
			else
			s.momz = 64000
			end
			if (s.z > s.maxfloat)
			s.ogmaxztime = 0
			s.downfloat = true
			s.upfloat = false
				if not s.firstdown and not s.landingmode
				s.firstdown = true
					if (s.floorz+100<<16 < s.z)
					s.firstrapidcheck = true
					s.minfloat = s.floorz+20<<16
					s.maxfloat = s.floorz+60<<16
					end
				end
			end
		end
		if s.firstrapidcheck
			if (s.floorz+40<<16 < s.z) and not s.upfloat and not P_IsObjectOnGround(s)
			s.minfloat = s.floorz+20<<16
			s.maxfloat = s.floorz+60<<16
			else
			s.firstrapidcheck = false
			end
		end
		if s.downfloat
			if s.z < (s.maxfloat-25<<16) and not s.landingmode and not P_IsObjectOnGround(s)
			s.momz = -32000
			elseif not (s.landingmode and (s.z <= s.minfloat)) and not P_IsObjectOnGround(s)
			s.momz = -64000
			elseif s.landingmode and s.momz
			s.momz = 0
			end
			if ((s.z < s.minfloat) or P_IsObjectOnGround(s)) and not s.landingmode
			s.downfloat = false
			s.upfloat = true
			end
		end
		if s.dying --GFZ1 smoking fx
			if not s.dyingsoundp
			s.dyingsoundp = true
			local doit = false
				for z in players.iterate
					if z.mo and not z.sam_saveselect
						if netgame
						or (z.jointime and z.jointime > 4)
							if (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < 620<<16)
							A_samquake(z.mo, 14<<16, 7, 1)
							P_SamFP(z, PAL_NUKE, 6)
							P_PlayRinglossSound(z.mo, z)
							doit = true
							end
						end
					end
				end	
				if doit == true
					S_StartSound(s, sfx_dmpain)
					S_StartSound(s, sfx_pstop) S_StartSound(s, sfx_befall)
				end
			end
			if (leveltime % 5 == 0)
			s.ghs = P_SpawnMobj(s.x+P_RandomRange(-200,200)<<16, s.y+P_RandomRange(-200,200)<<16, s.z+P_RandomRange(-50,150)<<16, MT_SAMCHARGEGFX)
			s.ghs.scale = FRACUNIT/P_RandomRange(2,8)
			s.ghs.color = SKINCOLOR_BLACK
			s.ghs.target = s
			end
			if (leveltime % 7 == 0)
			s.ghs = P_SpawnMobj(s.x+P_RandomRange(-150,150)<<16, s.y+P_RandomRange(-150,150)<<16, s.z+P_RandomRange(-50,150)<<16, MT_SMOKE)
			s.ghs.scale = FRACUNIT*P_RandomRange(1,2)
			end
			if (leveltime % 18 == 0) and not P_RandomRange(0,2)
			S_StartSound(s, sfx_s3kb4)
			P_SpawnMobj(s.x+P_RandomRange(-300,300)<<16, s.y+P_RandomRange(-300,300)<<16, s.z+P_RandomRange(-50,200)<<16, MT_SONIC3KBOSSEXPLODE )
			end
			if (leveltime % 98 == 0)
				S_StartSound(s, sfx_cmol)
				for d = 1,20
					local ghs = P_SpawnMobj(s.x+P_RandomRange(-120,120)<<16, s.y+P_RandomRange(-120,120)<<16, s.z+P_RandomRange(5,90)<<16, MT_MINECARTSPARK)
					ghs.scale = FRACUNIT/12
					ghs.fuse = 30
					P_InstaThrust(ghs, P_RandomRange(1,359)*ANG1, P_RandomRange(12,24)<<16)
				end			
			end			
		end
	end
end, MT_SAMUSSHIP)

addHook("MobjSpawn", function(s)
	for z in players.iterate --GUYS! I'm ALREADY here!!
		if z.mo and z.mo.sam_sprstship
			z.mo.sam_sprstship = false
		end
	end
end, MT_SAMUSSHIP)

local function ShipCollide(s, v) if not s.valid or not (v and v.valid and v.player) return false end --
	local p = v.player
	if (gametype == GT_COOP)
		if not p.firstshipin
			p.samhudmessagetime = 24
			p.samhudmessage1 = "Jump on your gunship and press\x83 spin\x82 to enter."
			p.samhudmessage2 = nil	
		elseif p.sams_itemcompletionprev == nil
			p.sams_itemcompletionprev = 0
		elseif p.sams_itemcompletion != nil and p.icr13 != nil and p.icr14 != nil and p.icr15 != nil and p.icr17 != nil
		and p.sams_itemcompletionprev < (p.sams_itemcompletion-p.icr13-p.icr14-p.icr15-p.icr17)
			p.samhudmessagetime = 24
			p.samhudmessage1 = "\x87 New data's\x82 available inside your gunship."
			p.samhudmessage2 = nil
		end
	end
	if (v.z < s.z+s.height-2<<16) and (v.z > s.z-s.height)
		if (p.pflags & PF_STARTJUMP) and (p.cmd.buttons & BT_JUMP)
		and (v.momz > 5<<16) and (v.momz < 7<<16)
			v.momz = 7<<16 --Raise the player up towards the top of the ship incase they don't have spacejump!
		end
		return false --
	elseif (v.z > s.z+s.height/3) and (v.z < s.z+s.height+11<<16)
		if v.health and not p.sam_exitship and not (v.momz*P_MobjFlip(s) > 4<<16)
			local USECD = (p.sams_usecd) or 0
			if not (p.pflags & (PF_JUMPED|PF_SPINNING|PF_NOJUMPDAMAGE))
				p.sam_framejump = 5
			end			
			v.eflags = $ & ~(MFE_JUSTSTEPPEDDOWN|MFE_APPLYPMOMZ|MFE_SPRUNG)
			p.sam_shipready = 2
			if (p.cmd.buttons & BT_USE) and not (USECD > 1)
				if p.sam_shipready and not (p.sam_hyperbeampanic)
				and not p.sam_intoship
					local USECD = (p.sams_usecd) or 0
					local LIGHTS = v.gravitylights
					if LIGHTS and LIGHTS.valid
						local ghs = P_SpawnGhostMobj(LIGHTS)
						ghs.fuse,ghs.tics = 13,14
						ghs.spriteyoffset = -5<<16
						ghs.destscale = 99<<16
						ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
						ghs.blendmode = AST_ADD
						ghs.dispoffset = 139
					end
					p.sam_intoship = 35
					p.sam_st = s
					SAM.Completion(p, v)
					p.firstshipin = true
				end
			end
		end
	end
end

addHook("MobjCollide", ShipCollide, MT_SAMUSSHIP)
addHook("MobjMoveCollide", ShipCollide, MT_SAMUSSHIP)

//Next two items are optional passive bonuses that won't count towards completion!
//This one's the ammo digitizer. More ammo restored means more incentive to cause mayhem with beam combos

addHook("MobjThinker", function(s) if not s.valid return end
	if (leveltime % 10 == 0)
		A_SAMPARTICLE(s, MT_MPR1, 50, 1, 1, 1,  SAM.RNG(SKINCOLOR_SUPERGOLD3, SKINCOLOR_SUPERGOLD5,s), SAM.RNG(23355, 55353,s))
	end
	S_StartSound(s, sfx_pbpku)		
	if not (s.samholo and s.samholo.valid)
		s.color = SKINCOLOR_GOLD
		s.samholo = P_SpawnMobj(s.x, s.y, s.z,  MT_BONUSHOLOGRAM)
	else
		s.samholo.tics = 2
		P_MoveOrigin(s.samholo, s.x, s.y, s.z)
		if not s.trnsphase
			s.trnsphase = 30
		else
			local trn = FF_TRANS10*max( 1,min(6,6-(s.trnsphase-9)/2) ) //Mathematics! 
			s.samholo.frame = S|(trn)|FF_FULLBRIGHT		
			s.trnsphase = $-1
		end	
	end
end, MT_AMMODIGITIZER)

--Bonus item 2. Doesn't count for completion.
addHook("MobjThinker", function(s)  if not s.valid return end
	if (leveltime % 10 == 0)
		A_SAMPARTICLE(s, MT_MPR1, 50, 1, 1, 1,  SKINCOLOR_ROSY, P_RandomRange(23355, 55353))
	end
	S_StartSound(s, sfx_pbpku)		
	if not (s.samholo and s.samholo.valid)
		s.color = SKINCOLOR_ROSY
		s.samholo = P_SpawnMobj(s.x, s.y, s.z,  MT_BONUSHOLOGRAM)
	else
		s.samholo.tics = 2
		P_MoveOrigin(s.samholo, s.x, s.y, s.z)
		if not s.trnsphase
			s.trnsphase = 30
		else
			local trn = FF_TRANS10*max( 1,min(6,6-(s.trnsphase-9)/2) ) //Mathematics! 
			s.samholo.frame = T|(trn)|FF_FULLBRIGHT		
			s.trnsphase = $-1
		end	
	end
end, MT_AUTOTANK)

--Bonus item 3. Doesn't count for completion.
addHook("MobjThinker", function(s) if not s.valid return end
	if (leveltime % 10 == 0)
		A_SAMPARTICLE(s, MT_MPR1, 50, 1, 1, 1,  SKINCOLOR_SKY, SAM.RNG(23355, 55353,s))
	end
	S_StartSound(s, sfx_pbpku)		
	if not (s.samholo and s.samholo.valid)
		s.color = SKINCOLOR_SKY
		s.samholo = P_SpawnMobj(s.x, s.y, s.z,  MT_BONUSHOLOGRAM)
	else
		s.samholo.tics = 2
		s.samholo.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
		P_MoveOrigin(s.samholo, s.x, s.y, s.z)
		if not s.trnsphase
			s.trnsphase = 30
		else
			local trn = FF_TRANS10*max( 1,min(6,6-(s.trnsphase-9)/2) ) //Mathematics! 
			s.samholo.frame = Z|(trn)	
			s.trnsphase = $-1
		end	
	end
end, MT_SCANVISOR)


addHook("MobjThinker", function(s) if not s.valid return end
	if not s.gripscaled
		s.scale = $*2
		s.gripscaled = true
	end
	if not (s.griporb and s.griporb.valid)
		s.griporb = P_SpawnMobjFromMobj(s,0,0,0, MT_BONUSHOLOGRAM)
		s.griporb.sprite = SPR_GVST
		s.griporb.blendmode = AST_ADD
		s.griporb.renderflags = $|RF_FULLBRIGHT
		s.griporb.frame = N
		s.griporb.plus = 1
		
		s.sprite = SPR_GVST
		s.frame = M
		s.plus = 1
		s.renderflags = $|RF_SEMIBRIGHT
	end
	
	local t = s.griporb
	t.tics = 3 t.fuse = 3
	t.anim_duration = 3		
	P_MoveOrigin(t, s.x, s.y, s.z)
	
	--Animate the item and its overlaying orb at the same time.
	
	s.frame = (s.frame & FF_FRAMEMASK)
	if s.frame >= M
		s.plus = -1
	elseif s.frame <= K
		s.plus = 1
	end
	
	t.frame = (t.frame & FF_FRAMEMASK)
	if t.frame >= Q
		t.plus = -1
	elseif t.frame <= N
		t.plus = 1
	end

	s.frame = $+s.plus
	s.frame = max($, K)
	s.frame = min($, M)

	t.frame = $+s.plus
	t.frame = max($, N)
	t.frame = min($, Q)
	t.frame = $|FF_TRANS60
	
end, MT_PWGRP)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s.valid and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			
			if not p.sam_power_grip			
				P_SamFP(p, PAL_MIXUP, 6)
				S_StartSound(v, sfx_spwup)				
				CONS_Printf(p, "You got the\x82 Power Grip!\x80 You can now jump and morph onto ledges!")
				p.sam_power_grip = true
				ItemGetPopup(p, 80, SKINCOLOR_POWERSUIT, "Power Grip", 94000)			
			elseif (gametype == GT_COOP) and (netgame or splitscreen)
			and not (p.coopboxrespawn == 2)			
				return false --			
			else			
				S_StartSound(v, sfx_mpku)
				p.sammissiles = $+3			
			end
			NewSamPickup(v, "GVSTK0", 88750)
			if s.griporb and s.griporb.valid
				s.griporb.state = S_NULL
			end
			
			s.state = S_NULL return false --
		end
	end
end, MT_PWGRP)

addHook("MobjCollide", function(s, v) return false end, MT_PWGRPLD)
addHook("MobjMoveCollide", function(s, v) return false end, MT_PWGRPLD)

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s.valid and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not (p.sam_ammodigitizer == 3)			
				P_SamFP(p, PAL_MIXUP, 14)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You upgraded with the\x87 Ammo Digitizer!\x80 Ammo pickups restore 3x the ammo.")
				v.player.sam_ammodigitizer = 3
				ItemGetPopup(v.player, 80, SKINCOLOR_YELLOW, "Ammo Digitizer", 100000)
				NewSamPickup(v, "MPR1S0", 35355)
				if not ((gametype == GT_COOP) and (multiplayer or netgame))			
					s.state = S_NULL return false --
				end
			end
		end return false --
	end
end, MT_AMMODIGITIZER)

//Not to be confused with reserve tanks, which revive you from death.

addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s.valid and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_autotank			
			P_SamFP(p, PAL_MIXUP, 14)
			S_StartSound(v, sfx_spwup)
			CONS_Printf(p, "You upgraded with the\x87 Auto Tank!\x80 Slowly auto-restore up to 99 energy!")
			p.sam_autotank = 99
			NewSamPickup(v, "MPR1T0", 35355)
			ItemGetPopup(p, 80, SKINCOLOR_ROSY, "Auto Tank", 87000)
				if not ((gametype == GT_COOP) and (multiplayer or netgame))	
					s.state = S_NULL --stay behind to let other players obtain the item too.
				end
			end
		end return false --
	end
end, MT_AUTOTANK)

//Sorta more like an Aeon Pulse
addHook("MobjMoveCollide", function(s, v)
	if v and YouAreSamus(v) local p = v.player
		if s.valid and p
			if (v.z > s.z+s.height)
			or (s.z > v.z+v.height)
				return --
			end
			if not p.sam_scanvisor
				P_SamFP(p, PAL_MIXUP, 14)
				S_StartSound(v, sfx_spwup)
				CONS_Printf(p, "You upgraded with the\x84 Scan Visor!\x80 Stand still to scan your surroundings.")
				p.sam_scanvisor = true
				SamusTutorial(v, "scanvisor")
				NewSamPickup(v, "MPR1Z0", 35355)
				ItemGetPopup(p, 80, SKINCOLOR_SLATE, "Scan Visor", 87000)
				if not ((gametype == GT_COOP) and (multiplayer or netgame))	
					s.state = S_NULL --stay behind to let other players obtain the item too.
				end
			end
		end
		return false --
	end
end, MT_SCANVISOR)
--Alternate token skin for damage challenge
addHook("MobjThinker", function(s)
	if s.valid
		if not s.checkedchallenge
		s.checkedchallenge = true 
			for z in players.iterate
				if not z.tokensrb2style or z.tokensrb2style == 1
					s.samustoken = true
					s.flags2 = $|MF2_DONTDRAW
				end
			end
		elseif s.samustoken and leveltime % 2 == 0
			s.clight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_SAMMISSILELIGHT)
			s.clight.scale = s.scale/15
			s.clight.scalespeed = $/4
			s.clight.layers = 2
			s.clight.tokenlight = true
		end
	end
end, MT_TOKEN)