--==============BEAMS, BOMBS, PROJECTILES==================
--If it destroys enemies or monitors, it's probably here!
--=========================================================
local SAM = MetroidVanguard

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
local function shatterfof(s,sectorsam) if not s.valid return end
	for fof in sectorsam.ffloors()
		if (fof.flags & FF_EXISTS) 
		and (fof.flags & (FF_BUSTUP|FF_SPINBUST))
		and not ((fof.flags & FF_STRONGBUST) and not s.pworsm)
			if not (s.z-150<<16 >= fof.topheight)
			and not (s.z+150<<16+s.height < fof.bottomheight)
				EV_CrumbleChain(sectorsam, fof)
			end
		end
	end
end
local function MonitorBreaker(s, t, scale)
	if s.valid and t and t.valid
		local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_SAMMONBREAKER)
		if hs and ghs.valid
			ghs.target = t
			if scale
				ghs.scale = scale
			end
			ghs.momx,ghs.momy,ghs.momz = 1,1,-1
		end
	end
end

local function SlideBeam(s, TRESHOLD) if not s.valid return end
	if TRESHOLD == nil
	or (abs(s.momz) < TRESHOLD)
	
		if s.target and s.target.SAM_didlockon return end 
		
		if (s.momz < 0)
			if (s.z+s.momz-(8*s.scale) <= s.floorz)
				s.momz = 0
				if (s.floorz+1 < s.z)
					s.z = s.floorz+1
				end return true --
			end
		elseif (s.momz > 0)
			if (s.z+s.momz+s.height+(8*s.scale) >= s.ceilingz)
				s.momz = 0
				if (s.ceilingz-1 < s.z+s.height)
					s.z = s.ceilingz-1-s.height
				end	return true --
			end
		end
	end
end

local function ShortBeam(s) if not (s and s.valid) return end
	s.color = (leveltime%3==0) and SKINCOLOR_FLAME or (leveltime%2==0) and SKINCOLOR_RED or SKINCOLOR_RUBY
	s.colorized = true
	if s.ShortBeam == 13
		s.momx,s.momy,s.momz = $*2/3,$*2/3,$*2/3
	end	
	s.ShortBeam = max($-1,0)
	if (s.ShortBeam < 9) 
		if not s.ShortBeam
			s.state = S_NULL return true--
		elseif ((s.frame & FF_TRANSMASK) < FF_TRANS90)
			s.frame = $+FF_TRANS10
		end
	end
end
--For the Power Bomb.
local function WindStorm(s) 
	if not s.valid or (leveltime%2==0) return end --
	
	local UW = (s.eflags & MFE_UNDERWATER) and true or false
	local RFLAGS = (UW) and RF_SEMIBRIGHT or RF_PAPERSPRITE|RF_NOCOLORMAPS|RF_FULLBRIGHT
	local ZPOS = s.z+(10<<16)
	
	for d = 1,929,57
		local rng = P_RandomRange(-30,30)	
		local ghs = P_SpawnMobj(
		s.x+FixedMul((10+d)<<16,cos(d*(ANG1+9909))),
		s.y+FixedMul((10+d)<<16,sin(d*(ANG1+9909))),
		ZPOS+(rng<<16*2), MT_SAMWINDLINE)
		
		P_SetObjectMomZ(ghs, (rng+30)*30000)
		P_InstaThrust(ghs, R_PointToAngle2(s.x, s.y, ghs.x, ghs.y)+rng, 74<<16)
		ghs.destscale = $*99
		ghs.spriteyscale = $/2
		ghs.tics = $*2
		ghs.angle = R_PointToAngle2(ghs.x, ghs.y, ghs.x+ghs.momx, ghs.y+ghs.momy)
		if UW
			ghs.state = (d%3==0) and S_MEDIUMBUBBLE or S_SMALLBUBBLE
			ghs.fuse = 7
			ghs.renderflags = RF_SEMIBRIGHT
		else
			ghs.angle = R_PointToAngle2(ghs.x, ghs.y, ghs.x+ghs.momx, ghs.y+ghs.momy)
			ghs.renderflags = RFLAGS
			if (d%2==0)
				ghs.flags2 = $|MF2_SHADOW
				ghs.scale = $*2
				ghs.blendmode = AST_ADD
				ghs.spritexscale = $*2
			else
				ghs.spritexscale = $*3
			end
		end
	end
end

local FlashMobjC={SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERORANGE5,SKINCOLOR_RED, SKINCOLOR_WHITE, SKINCOLOR_SUPERGOLD3}
addHook("MobjThinker", function(s) if not s.valid return end --
	if (s.state >= S_PBXP1) 
		if not s.saldsalf
			local ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_SAMUSTHOK)
			ghs.flags2 = MF2_DONTDRAW 
			ghs.fuse,ghs.tics = 55,55
			if s.ShortBeam
				s.color,s.colorized = SKINCOLOR_PINK, true
				S_StartSoundAtVolume(ghs, sfx_pbxp,138)
			else
				S_StartSound(ghs, sfx_pbxp)
			end		
		--	SamusShotImpact(s)
			
			ghs = SamusBulletHole(s, s.scale/10, (s.ShortBeam) and SKINCOLOR_PINK or SKINCOLOR_SUPERGOLD4)	
			if ghs and ghs.valid
				ghs.flags2 = $|MF2_SHADOW
				ghs.fuse = 6
				ghs.scalespeed = FRACUNIT/24
				ghs.destscale = FRACUNIT*99
			end
			s.samusshot,s.saldsalf = true, true
		end
	elseif s.health
	
		if s.saldsalf == false
		
			if s.ShortBeam
				s.spritexscale = (leveltime%2) and $+8000 or max(1, $-8000)
				s.spriteyscale = (leveltime%2) and $+8000 or max(1, $-8000)
				if (s.ShortBeam > 5)
					local ghs = P_SpawnGhostMobj(s)
					ghs.blendmode = AST_ADD	
					ghs.fuse,ghs.tics = 8,8
					ghs.scale = min(s.scale, (s.scale*2)/((s.ShortBeam/3)+1) )
					ghs.color,ghs.colorized = s.color,s.colorized
					ghs.frame = ($ & ~FF_TRANSMASK) | min(FF_TRANS90, (s.frame & FF_TRANSMASK)+FF_TRANS30)
				end				
				if (ShortBeam(s)) == true return end --
			else
				local ghs = P_SpawnGhostMobj(s)
				ghs.flags = $|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT
				ghs.blendmode = AST_ADD
				ghs.spriteyoffset = $-FRACUNIT
				ghs.scalespeed = FRACUNIT/((leveltime%2) and 7 or 6)
				ghs.destscale = 1	
			end	
		end
		if s.saldsalf == nil
			s.saldsalf = false
		end
	end
	s.samusshot = true --
end, MT_PBSHOT)

addHook("MobjThinker", function(s) if not s.valid return end --
	if s.saldsalf or not s.target
		return --
	end
	s.samusshot = true
	if (s.state == S_PBCHARGESHOT1) or (s.state == S_PBCHARGESHOT2)
		if s.ShortBeam
			if (ShortBeam(s)) == true return end --
		end
		local ghs = P_SpawnMobj(
		s.x+FixedMul(-15<<16, cos(s.angle)),
		s.y+FixedMul(-15<<16, sin(s.angle)),
		s.z, MT_PBCHARGESHOTT)
		if ghs and ghs.valid
			ghs.color,ghs.colorized = s.color,s.colorized
		end
	elseif (s.state == S_PBCHARGESHOTE)
		local t = s.target
		if not s.saldsalf
			if s.ShortBeam
				s.color = SKINCOLOR_PINK
				s.colorized = true
			end
			if s.wallclipped and t
				P_Thrust(t, t.angle, -6<<16)
				P_MoveOrigin(s, t.x, t.y, t.z+(t.height/2))
			end		
			A_SAMUSEXPLOSIONS(s, 7, MT_SAMEXPLODE2, false, 1000, (s.ShortBeam) and SKINCOLOR_PINK or SKINCOLOR_ORANGE)
			A_SAMUSEXPLOSIONS(s, 7, MT_SAMMISSILESMOKE, 25<<16, 430000)
			A_SAMUSEXPLOSIONS(s, 18, MT_SAMMISSILESMOKE, false, 80000)	
			local DIST = (620<<16)
			A_samquake(s, 11<<16, 7, DIST)
			if t and t.valid
				if G_GametypeHasSpectators()
					A_Samuskillstuff(s, 275<<16, 155<<16, t, true)
				else
					A_Samuskillstuff(s, 345<<16, 315<<16, t, true)
				end
			end
			SamFaceReflect(s, 250<<16)
			s.saldsalf = true
			S_StartSound(s, sfx_pbchae)
		end
	end
end, MT_PBCHARGESHOT)

addHook("MobjThinker", function(s)
	if (s.state == S_PBCHARGESHOTT2)
		if not s.saldsalf
			s.scale = s.scale*6
			s.saldsalf = 1
		end
	elseif (s.state == S_PBCHARGESHOTT3)
		if s.saldsalf != 2
			s.scale = s.scale/2
			s.saldsalf = 2
		end
	end
end, MT_PBCHARGESHOTT)

addHook("MobjThinker", function(s) if not (s.valid and s.target and s.target.valid) return end 
	local t = s.target
	local p = t and t.player
	if s.ret2sign and p --Used for Super Missile/Power Bombs "ready" graphics.
		local zet = (p.speed > 8<<16) and 5 or 8
		
		P_MoveOrigin(s, t.x+FixedMul(t.radius*5/2, cos(t.angle-ANG2*2)), t.y+FixedMul(t.radius*5/2, sin(t.angle-ANG2*2)), t.z+(t.height*4/zet))
		s.z = $+(FixedMul(FixedMul(50<<16, t.scale), sin(p.aiming)))
		if s.dontstateme
			return --
		end
		if (s.tics > 10)
			s.frame = Z|FF_TRANS20
		else
			s.frame = Z|((s.tics>4) and FF_TRANS50 or FF_TRANS70)
		end
	elseif s.ret2bomb --Bomb graphic.
		P_MoveOrigin(s, t.x, t.y, t.z)
		if s.dontstateme
			return --
		end		
		s.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
		if (s.tics > 10)
			s.frame = Z|FF_TRANS20
		elseif (s.tics >= 5)
			s.frame = Z|FF_TRANS50
			s.color = SKINCOLOR_VARIASUIT
		else--if (s.tics < 5)
			s.frame = Z|FF_TRANS70
			s.color = SKINCOLOR_RED
		end
	elseif s.ret2spring --Spring Ball Graphic
		s.renderflags = $|RF_NOCOLORMAPS|RF_FULLBRIGHT
		if (s.tics > 10)
			s.frame = L|FF_TRANS40
		elseif (s.tics >= 8)
			s.frame = M|FF_TRANS50
		elseif (s.tics >= 6)
			s.frame = N|FF_TRANS60
		elseif (s.tics >= 4)
			s.frame = O|FF_TRANS70
		elseif (s.tics >= 2)
			s.frame = P|FF_TRANS80
		else
			s.frame = Q|FF_TRANS90
		end
	else --Actual charge beam graphic.
		s.momz = t.momz + (2<<16*P_MobjFlip(s))
		
		if s.PPoffset == nil
			s.PPoffset = true
			s.dispoffset = -88
			if s.ChargeGFX == true
				local RNG = P_RandomRange(3,4)
				s.renderflags = $|RF_NOCOLORMAPS|RF_FULLBRIGHT
				s.dispoffset = -88-RNG
				if displayplayer and displayplayer.mo and displayplayer.mo == t and camera and camera.chase != true
					s.spriteyoffset = 0 --First person version.
					s.spritexoffset = 105<<16
				else
					s.spritexscale,s.spriteyscale = $*RNG,$*RNG
					local SPEED = abs(s.momx)+abs(s.momy)
					s.spriteyoffset = 32<<16 +(SPEED/3) --Third person version.
				end 
			end
		end
	end
end, MT_SAMCHARGEGFX)

addHook("MobjThinker", function(s) if not s.valid return end --
	s.color = (s.color) or SKINCOLOR_GREEN
	s.samusshot = true
	if (s.state == S_SPSHOT1) or (s.state == S_SPSHOT2)
		if not (s.wave4 or s.wave5) 
		or s.ghoster and (s.wave4 or s.wave5)
		or twodlevel 
		or s.target and s.target.valid and (s.target.flags2 & MF2_TWOD)
			local ghs = P_SpawnGhostMobj(s)
			ghs.scalespeed = $*2
			ghs.destscale = 1
			ghs.blendmode = AST_ADD
		elseif s.wave4 or s.wave5
			s.ghoster = true
		end	
		if s.wave2
			A_SAMPARTICLE(s, MT_MPR4, 2, 10, -4, 7, s.color, P_RandomRange(25355, 48355), true)
		end
		SlideBeam(s, 25<<16)
	else --if (s.state == S_SPXP1)
		MonitorBreaker(s, s.target, s.scale*2)
		s.saldsalf = true
	end
end, MT_SPSHOT)

--Spawn and set the other Spazer Charge Shot properties with ANG as an offset.
local SpreadChargeShots = function(s, ANG)
	ANG = (ANG) or ANG2
	local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_SPCHARGESHOT)
	if ghs and ghs.valid
		ghs.target = s.target
		ghs.meleeshot = 1
		ghs.blendmode = s.blendmode
		ghs.eflags,ghs.flags2 = s.eflags,s.flags2
		ghs.scale = s.scale
		ghs.angle = s.angle-ANG
		ghs.momz = s.momz
		P_Thrust(ghs, s.angle-ANG, FixedMul(ghs.info.speed, s.target and s.target.scale or s.scale))	
	end
end
addHook("MobjThinker", function(s) if not s.valid return end --
	s.samusshot = true
	if s.weakertic == nil
		s.weakertic = 0
		s.spazerdist = 0
		if not s.brakandco
			s.color = (s.color) or SKINCOLOR_GREEN
			if s.meleeshot == nil 
				s.meleeshot = 2
				local t = s.target
				if t and t.crystalflashtime
					s.CFversion = true
				end
			end
		end
	else
		s.weakertic = $+1
		if (s.weakertic >= 4)
			if not (s.spazerdist and (s.spazerdist >= 25))
				s.weakertic = 0
				s.spazerdist = $+1
			end
		end
		if s.meleeshot --For a few tics, you're a melee-shot capable of "shotgun-blasting" opponents!
			s.meleeshot = $-1
		end
	end
	if (s.state == S_SPSHOT1) or (s.state == S_SPSHOT2)	
		if not (s.CFversion and s.saldsaf)
			local ghs = P_SpawnGhostMobj(s)	
			ghs.destscale = 5
			ghs.blendmode = AST_ADD
		end
		SlideBeam(s, 27<<16)	
		if s.magicaltic
			if s.wave2 --The side shots emit these particles!
				if not (s.CFversion and s.saldsaf)
					A_SAMPARTICLE(s, MT_MPR4, 5, 14, -4, 8, s.color, P_RandomRange(45355, 65354))
				end
				if not s.saldsalf and not (s.brakandco and not s.superbrak)
					for i = 1,7,2 --Spawn the other shots and make them travel with you!
						SpreadChargeShots(s, ANG2*i)
						if i!= 7 --The initial projectile already has an offset of -ANG2, so skip 1 on this side.
							SpreadChargeShots(s, -ANG2*i)
						end
					end 
					s.saldsalf = true
				end	
			end
		else
			s.magicaltic = true
			s.destscale = $*3
			s.plshottimer = 45
			s.blendmode = AST_ADD				
		end
		if s.plshottimer
			s.plshottimer = $-1
			if s.plshottimer == 25
				s.destscale = 5
			end
		end
		if s.valid and (s.scale < 88) --Okay, we can stop existing now.
			s.state = S_NULL return --
		end
	end
end, MT_SPCHARGESHOT)

addHook("MobjThinker", function(s)
	if not s.Start
		s.samusshot = true
		s.Start = true
		if not s.brakandco
			s.color = (s.color) or SKINCOLOR_GREEN
		end
	end
	SlideBeam(s)
	if not s.valid return end --
	
	if (s.state == S_SPXP1) or (s.state == S_SPXP2)
		if not s.boombear and not s.noshatter
			A_Samuskillstuff(s, 375<<16, 322<<16, s.target, true)
			A_SAMUSEXPLOSIONS(s, 8, MT_SAMSHATTERFOF, false, 9000, true)
			A_SAMPARTICLE(s, MT_MPR4, 9, 14, -4, 8, s.color, P_RandomRange(45355, 65345)*9)	
			s.boombear = true
			s.blendmode = AST_ADD
		end
	elseif s.health
		local tsh = P_SpawnGhostMobj(s)
		tsh.blendmode = AST_ADD
		tsh.destscale = (leveltime%2==0) and $*2 or 1
		
		if not s.noshatter
			A_Samuskillstuff(s, 344<<16, 210<<16, s.target, true, "combowave")
			if (leveltime % 6 == 0)
				local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
				ghs.sprite = SPR_MXP4
				ghs.frame = V|FF_FULLBRIGHT|FF_TRANS60
				ghs.blendmode = AST_ADD
				ghs.scale = FRACUNIT
				ghs.tics,ghs.fuse = 99,36
				ghs.destscale = $*99		
				A_SAMUSEXPLOSIONS(s, 2, MT_SAMSHATTERFOF, false, 9000)
				A_SAMPARTICLE(s, MT_MPR4, 15, 18, -7, 12, s.color, P_RandomRange(24355, 65353)*4)
			else
				A_SAMPARTICLE(s, MT_MPR4, 11, 14, -5, 9, SKINCOLOR_WHITE, P_RandomRange(44355, 65353)*4)
			end
		end
		if (s.tics > 1)
			s.tics = $-1
		end
		if (s.state == S_MPR9G) and (s.tics < 3)
			s.state = S_MPR9A
		end
		if s.magicaltic
			if not s.noshatter
				A_SAMUSEXPLOSIONS(s, 5, MT_SAMSHATTERFOF, false, 144000)	
		
				if not s.saldsalf
					local ANG,THRUSTANG = -16,-ANG2*2
					for i = 4,8,4
						if i == 8 ANG,THRUSTANG = ANG2*8, ANG2 end
						local ghs = P_SpawnMobj(
						s.x+FixedMul(s.radius*i, cos(s.angle+ANG)), 
						s.y+FixedMul(s.radius*i, sin(s.angle+ANG)), 
						s.z+(s.height/4*P_MobjFlip(s)), MT_SPCHARGECOMBO)
						ghs.target = s.target
						ghs.noshatter = true
						ghs.blendmode = AST_ADD
						ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE
						ghs.eflags,ghs.flags2 = s.eflags,s.flags2 
						ghs.scale,ghs.angle = s.scale/2,s.angle 
						ghs.momz = s.momz
						P_Thrust(ghs, s.angle+THRUSTANG, FixedMul(ghs.info.speed, s.target and s.target.scale or FRACUNIT))
					end
					s.saldsalf = true
				end
			end
		else
			s.magicaltic = true
			s.destscale = $*6
			s.plshottimer = 40
		end
		if s.plshottimer
			s.plshottimer = $-1
			if s.noshatter
				if s.plshottimer == 25
					s.destscale = 5
				end
			elseif (s.flags & MF_BOUNCE)
				s.flags = $ & ~(MF_BOUNCE|MF_GRENADEBOUNCE)
			end
		end
		if s.valid and (s.scale < 20000)
			s.state = S_NULL
		end
	end
end, MT_SPCHARGECOMBO)

addHook("MobjThinker", function(s) if not s.valid return end --
	if s.customcolor
		s.color = s.customcolor
	elseif s.hypered
		if s.wavebeamtimer != nil
			if (s.wavebeamtimer > 16)
				s.color = SKINCOLOR_SKY
			elseif (s.wavebeamtimer > 14)
				s.color = SKINCOLOR_BLUE
			elseif (s.wavebeamtimer > 12)
				s.color = SKINCOLOR_MAGENTA
			elseif (s.wavebeamtimer > 10)
				s.color = SKINCOLOR_PINK
			elseif (s.wavebeamtimer > 8)
				s.color = SKINCOLOR_CLOUDY
			elseif (s.wavebeamtimer > 6)
				s.color = SKINCOLOR_GOLD
			elseif (s.wavebeamtimer > 4)
				s.color = 29
			elseif (s.wavebeamtimer > 2)
				s.color = 32
			else
				s.color = SKINCOLOR_EMERALD
			end
		end
		s.wavebeamtimer = (not s.wavebeamtimer) and 18 or $-1
	else
		s.color = (s.color) or SKINCOLOR_GREEN
	end
	
	s.samusshot = true
	if not (s.rocket and s.rocket.valid) 
		if (s.state == S_SAMSPAWNITEM2)
			P_KillMobj(s)
		end
		return --
	end
	local t = s.rocket
	local p = t and t.player
	
	if s.samdrollangle == nil
		s.samdrollspeed = ((P_RandomRange(1,60))*ANG1)
		s.samdrollangle = P_RandomRange(-1,1)
		s.blendmode = AST_ADD
		if not s.samdrollangle
			s.samdrollangle = 1
		end
	end
	if s.screamsound == nil
		s.screamsound = true
		if p and t.skin
			local SKIN = t.skin
			--Scream for me, bois.
			if SKIN == "werehog" --Stack the CRAP out of this
				S_StartSound(t, P_RandomRange(0,1) and sfx_rsaaa1 or sfx_rsaaa2)
				s.screamsound = nil
			elseif SKIN == "duke"
				if not S_SoundPlaying(t, sfx_dnpn03)
					S_StartSound(t, sfx_dnpn03) S_StartSound(t, sfx_dnpn03)
				end
			elseif SKIN == "sms" 
				if not S_SoundPlaying(t, sfx_smscr2) and not p.hypermysticsonic
					S_StartSound(t, sfx_smscr2) S_StartSound(t, sfx_smscr2)
				end
			elseif SKIN== "silver" 
				if not S_SoundPlaying(t, sfx_silrip)
					S_StartSound(t, sfx_silrip) S_StartSound(t, sfx_silrip)
				end
			elseif SKIN == "eggman" or SKIN == "brakeggman"
				if not S_SoundPlaying(t, sfx_eggahh)
					S_StartSound(t, sfx_eggahh)
				end
			elseif SKIN == "shadow"
				if (leveltime%20==0)
				or (leveltime%10==0) and P_RandomRange(0,1)
					S_StartSound(t, sfx_damnit) S_StartSound(t, sfx_damnit)
				end
				s.screamsound = nil
			end		
		end
		if s.hypered
			S_StopSoundByID(t, sfx_shnuke)
			S_StartSound(t, sfx_shnuke)
		end
	end
	
	
	--waaaaa
	if not (t.superbrak and not s.hypered)
		s.samvrollangle = s.samvrollangle and $+(s.samdrollspeed*s.samdrollangle) or s.samdrollspeed*s.samdrollangle
	--	if MODVERSION
			t.rollangle = s.samvrollangle
	--	end
	end
	if p and not p.sam_sensitive
		p.viewrollangle = s.samvrollangle
	end
	if t.superbrak 
	
		if not t.superbrakquickfret
			if s.hypered
				t.superbrakquickfret2 = true
			end
			t.superbrakquickfret = true
		end
	/*	if (t.flags2 & MF2_FRET)
			t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
			if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil
		--	return --
		end */
		
	elseif p
	
		if p.hbimmune or p.hypermysticsonic
		or G_GametypeHasTeams() and s.target and s.target.player and (p.ctfteam == s.target.player.ctfteam)
			t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
			if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil		
			
		elseif s.target and s.target.player and t and s.target != t
		
			if G_GametypeHasSpectators() and not t.health and P_CheckDeathPitCollide(t)
				if not t.gavespdeathscore
					P_AddPlayerScore(s.target.player, 64)
					t.gavespdeathscore = true
				end
				t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
				if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil
				return --
			end
		end
		
	elseif t.barocket and (t.barocket > 250) 
	or s.target and t == s.target
	or (t.info.mass == 2006)
	
		t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
		if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil
		return --
		
	elseif t and t.valid 
	
		if (t.type == MT_METROID) or (t.type == MT_SUPERMETROID)
			if s.hypered and (t.type == MT_METROID)
				P_KillMobj(t)
			else
				t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
				if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil
				return --
			end
		elseif (t.type == MT_EGGMOBILE3) or (t.type == MT_EGGMOBILE4) or (t.type == MT_BLACKEGGMAN)
		or (t.type == MT_METALSONIC_BATTLE) or (t.info.doomednum == 1555)
			if t.health and (t.health > 2)
			
				if s.hypered and not (t.type == MT_PZBOSS)
					P_DamageMobj(t, s.target and s or nil, s.target or nil, 6)
				else
					P_DamageMobj(t, s.target and s or nil, s.target or nil, 2)
				end
				P_SpawnMobj(t.x, t.y, t.z, MT_SONIC3KBOSSEXPLODE)
				S_StartSound(t, sfx_brakrx)
				t.spazershocked = nil
				if not p and s.ogflags
					t.flags = s.ogflags
				end
				t.spcombod = nil
				if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil
				return
			end	
		elseif t.type == MT_POPUPTURRET or t.type == MT_METROIDPART or t.type == MT_PZBOSS 
		or t.type == MT_PTERABYTE or t.type == MT_DRAGONBOMBER 
			if t.health
				t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
				P_DamageMobj(t, s, s, 2)
				if p p.viewrollangle = 0 end t.rollangle = 0 s.rocket = nil
				return --
			end
		end
	end

	if t.barocket == nil
		if t.spazershocked 
			if (t.type >= MT_EGGMOBILE) and (t.type <= MT_EGGMOBILE4) --Heeey, this is EGGMAN!
				if (t.spcombod or s.hypered)
				and not (t.flags2 & MF2_FRET)
					S_StartSound(t, sfx_eggahh) //Squeal for me, stache boy
				end
			end
		end
		t.barocket = 0
	else 
		t.barocket = $+1
	end

	if t.flags != nil
		if p
			if p.powers[pw_flashing] and (p.powers[pw_flashing] < 3)
				p.powers[pw_flashing] = 3
			end
			if t.health and not (t.state == S_PLAY_PAIN) and not P_IsObjectOnGround(t)
				t.state = p.powers[pw_super] and S_PLAY_STUN or S_PLAY_PAIN
			end
		else
			if not s.ogflags
				s.ogflags = t.flags
				t.flags = $ & ~(MF_FLOAT|MF_NOGRAVITY|MF_SLIDEME|MF_SHOOTABLE)
			end
			t.target = t
		end
	end
	
	--UpMove and DownMove.
	if s.upm == nil
		if s.hypered
			P_MoveOrigin(s, t.x, t.y, t.z)
			s.momx,s.momy,s.momz = t.momx,t.momy,t.momz
		end

		if not (t.barocket and (t.barocket > 8))
			s.upm = 11
			if s.target 
				if s.target.player and s.target.player.aiming and not t.spcombod and not s.hypered
					local AIMPLUS = s.target.player.aiming/(400<<16)
					s.upm = max(1, $+AIMPLUS) --Aiming affects flightpath.
				end
				s.momx,s.momy,s.momz = s.target.momx,s.target.momy,s.target.momz/2
			end	
		end
	else
		s.upm = $-1
		if (s.upm <= 1) and s.downm == nil
			s.downm = 0
		end
	end
	if s.downm != nil
		s.downm = $-1
	end
	if t.rocketangledirection == nil t.rocketangledirection = P_RandomRange(-1, 1) end
	if t.rocketanglespeed == nil t.rocketanglespeed = (P_RandomRange(6, 40))*ANG1 end

	if t.rocketangle == nil
		t.rocketangle = t.angle
		if p
			P_SamFP(p, PAL_RECYCLE, 4)
			P_PlayRinglossSound(t)
		end
	else
		t.rocketangle = $+(t.rocketanglespeed*t.rocketangledirection)
	end
	
	if not (p and not t.spcombod)
		t.angle = t.rocketangle
	end
	if s.hypered
		if t.superbrak 
			t.flags = $|MF_BOUNCE
			if s.superbrakbigjump or s.superbrakjump
				s.superbrakbigjump = 0
				s.superbrakjump = 0
			end
		else
			local ghs = P_SpawnGhostMobj(t)
			ghs.scale = $*2
			ghs.blendmode = AST_ADD
			ghs.colorized = true
			ghs.fuse = 12
			ghs.tics = 13
			ghs.rollangle = t.rollangle-ANGLE_45
			ghs.color = (leveltime%2==0) and SKINCOLOR_SUPERSKY4 or SKINCOLOR_SUPERSILVER1
			ghs.scalespeed = $*2
			ghs.destscale = ghs.scalespeed+1
		end
		s.hypered = max($-1,0)
		if not s.hypered
			s.hypered = nil
			if t and t.valid
				t.momz,t.momy,t.momx = 0,0,0
				P_DamageMobj(t, s, s, 3) --Let's put in a failsafe.
				if t and t.valid
					t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
					if p
						p.viewrollangle = 0
					end
					t.rollangle = 0
				end
			end	
			s.rocket = nil
			return --
		end
	end	
	if (leveltime % 2 == 0)
		if t.specialexpangle
			P_InstaThrust(t, t.specialexpangle+ANGLE_180, 88<<16)
		else
			P_InstaThrust(t, s.angle, 88<<16)
		end
		
		if s.upm
			P_SetObjectMomZ(t, s.upm<<16)
		elseif s.downm
			P_SetObjectMomZ(t, s.downm<<16)
		end
		
		if s.preimage == nil
			s.preimage = 6
		end
		if s.preimage
			local ghs = P_SpawnGhostMobj(t)
			ghs.rollangle = t.rollangle
			ghs.colorized = true
			ghs.scale = ($*5)/s.preimage
			if t.hypered
				ghs.color = (s.preimage%2== 0) and SKINCOLOR_PINK or SKINCOLOR_SUPERGOLD5
			else
				ghs.color = (s.preimage%2== 0) and SKINCOLOR_SUPERSILVER1 or SKINCOLOR_SUPERGOLD2
			end					
			s.preimage = $-1
		end
		
	elseif (t.barocket and t.barocket > 3)
		if (abs(t.momx)+abs(t.momy) < 7<<16)
		or (t.eflags & (MFE_JUSTHITFLOOR|MFE_GOOWATER|MFE_SPRUNG))
		or (t.barocket > 35) and (P_IsObjectOnGround(t) or (t.z <= t.floorz))
			if p and p.powers[pw_super]
				P_GivePlayerRings(p, -30)
			end
			if s.hypered and s.target
				if not p
					t.flags = $|(s.ogflags or 0)
				else
					p.hbimmune = 45
					p.viewrollangle = 0
				end
				
			   t.spazershocked = nil
			   t.barocket = nil
			   s.hyperedboom = P_SpawnMobj(t.x, t.y, t.z, MT_HBSHOT)
			   s.hyperedboom.target = s.target
			   s.hyperedboom.lasthyper = t
			   S_StartSound(s.hyperedboom, sfx_smexp)
			   S_StartSound(s.hyperedboom, sfx_hbsh)
			   S_StartSound(s.hyperedboom, sfx_brakrx)
			   P_ExplodeMissile(s.hyperedboom)
			   
				if not (p and p.powers[pw_flashing])
					if t.superbrak
						if (t.health > 6)
							P_DamageMobj(t, s, s.target, 6)
						elseif t.hyperbeampanic and (t.health <= 6)
							P_KillMobj(t, s, s.target)
						else
							P_DamageMobj(t, s, s.target)
						end
					else
						P_DamageMobj(t, s, s.target, 6)
					end
			   	end
			   t.rollangle = 0 
			   s.rocket = nil
			   return --

			elseif t and t.valid and t.health
			
				local ghs = P_SpawnMobj(t.x, t.y, t.z, MT_CYBRAKDEMON_VILE_EXPLOSION)
				S_StopSoundByID(t, sfx_brakrx)
				S_StartSound(t, sfx_brakrx)
				S_StartSound(t, sfx_brakrx) 
				S_StartSound(t, sfx_s1b9)
				local angle = s.angle+ANGLE_180				
				if t.specialexpangle
					angle = t.specialexpangle+ANGLE_180
				end
				for d = -3,3 --Rocks!
					local debris = P_SpawnMobjFromMobj(t, 0, 0, 0, MT_MPR8)
					if debris and debris.valid
						local rng = P_RandomRange(7,44)
						debris.spriteyscale = $/(rng/7)
						debris.spritexscale = $/(rng/7)
						debris.flags = MF_BOUNCE|MF_GRENADEBOUNCE|MF_SOLID|MF_NOCLIPTHING //& ~MF_NOCLIPHEIGHT & ~MF_NOGRAVITY & ~MF_NOCLIP
						debris.sprite = SPR_ROIA
						debris.rollspeed = rng*ANG1
						debris.frame = A
						debris.tics = 24
						debris.fuse = 24
						debris.rollangle = (rng*5)*ANG1
						P_InstaThrust(debris, angle+(d*ANG20), 24<<16+(rng<<16))
						P_SetObjectMomZ(debris, P_RandomRange(-10,10)<<16, false)
					end
				end						
			
				if not p
					t.flags = $|(s.ogflags or 0)
				end

				if s.target
					if t.superbrak 
						if (t.health > 5) and t.spcombod
							P_DamageMobj(t, s, s.target, 4)
						elseif (t.health > 3)
							P_DamageMobj(t, s, s.target, 3)
						elseif not ((t.health < 3) and not t.hyperbeampanic)
							P_DamageMobj(t, s, s.target, 2)
						end
					else
						P_DamageMobj(t, s, s.target, 2) --Generic damage.
					end
				elseif t.spcombod
					if t.superbrak
						if (t.health > 5)
							P_DamageMobj(t, s, s, 4)
						elseif not ((t.health < 3) and not t.hyperbeampanic)
							P_DamageMobj(t, s, s, 2) --Generic damage.
						end
					else
						P_DamageMobj(t, s, s, 2) --Generic damage.
					end
				end
				if t and t.valid
					t.spazershocked,t.barocket,t.spcombod = nil,nil,nil
					if p
						p.viewrollangle = 0
					end
					t.rollangle = 0 
					s.rocket = nil
				end
			end
			return --The end!				
		end
	end

	if (s.state == S_MPR9G) and (s.tics < 2)
		s.state = S_SAMSPAWNITEM2
	end
	if (s.state == S_SAMSPAWNITEM2)
		s.tics = 77
	end
end, MT_SPAZERSHOCK)

addHook("MobjThinker", function(s) if not s.valid return end --
	if not s.wavetwodcheck
		s.color = (s.color) or SKINCOLOR_MAGENTA
		s.samusshot = true
		s.wavetwodcheck = true
		if s.target and s.target.valid and (s.target.flags2 & MF2_TWOD)
			s.wavetwod = true
			if s.wave2
				s.z = $+(s.target.height/2)
				if not s.valid return end --
			end
		elseif (twodlevel)
			s.wavetwod = true
		end
	end
	if (s.state == S_WVSHOT1) or (s.state == S_WVSHOT2)
		--Experimental code, adding fancy trails to the wave shots.
		if (leveltime % 16 == 0) and not s.charged and (s.target and s.target.player)
			s.spindz = 0
			s.spinaxis,s.spinaxisz = 0,0
			s.verticalangle = R_PointToAngle2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), s.momz)
			local ang = leveltime*ANG10
			
			local ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_SAMLIGHTLINE)
			ghs.target = s
			ghs.scale = (s.scale*5)/10
			ghs.renderflags = RF_FULLBRIGHT
			ghs.blendmode = AST_ADD
			ghs.tics = 22
			ghs.spriteyoffset = -12<<16
			ghs.frame = A|FF_TRANS20
			ghs.destscale = 1
			ghs.color = SKINCOLOR_PURPLE
			ghs.tashu = s.target.player
		end
		
		--Back to normal
	--	s.rollangle = leveltime*ANG20 --speen
	
		if s.wavebeamtimer != nil // or (s.wavebeamtimer == 0)
			local MULT = ((s.wave2) and 1 or -1) * ((s.wavebeamtimer>5) and -1 or 1)
			if s.wavetwod --Jiggle up and down rather than left and right.
				P_SetObjectMomZ(s, -365355*MULT, true)
			else
				P_Thrust(s, s.angle-(ANGLE_90*MULT), FRACUNIT)				
			end
		end
		s.wavebeamtimer = (not s.wavebeamtimer) and 10 or max($-1,0)
		s.spriteyscale = (leveltime%2==0) and 49355 or FRACUNIT
		s.spritexscale = (leveltime%2==0) and 55355 or FRACUNIT
		if (s.state == S_WVSHOT1)
			if not s.wavenope
				A_SAMPARTICLE(s, MT_MPR1, 4, 5, -4, 4, s.color, P_RandomRange(9355, 34355))
			end
			local ghs = P_SpawnGhostMobj(s)
			ghs.scale = s.scale
			ghs.blendmode = AST_ADD
			ghs.destscale = 1
		--	ghs.rollangle = leveltime*ANG20
			ghs.colorized = true
			ghs.color = (leveltime%2) and SKINCOLOR_SUPERGOLD5 or SKINCOLOR_GRAVITYSUIT
		end
		if not s.plshottimer
			s.oldwavespeed = (abs(s.momx)+abs(s.momy)) / (2<<16)
			s.oldwavespeedz = s.momz
			s.plshottimer = 120
		end		
	else--if (s.state == S_WVXP1) 
		if not s.saldsalf
			s.spritexscale,s.spriteyscale = FRACUNIT,FRACUNIT
			s.destscale = 15<<16
			MonitorBreaker(s, s.target)
			s.scalespeed = $*3
			s.saldsalf = true
		end
	end
	if not s.valid return end --
	
	if s.plshottimer==1 or (s.floorz == s.ceilingz)
		s.state = S_NULL return --
	elseif s.plshottimer != nil
		s.plshottimer = $-1
		s.wavespeed = (abs(s.momx)+abs(s.momy)) / (2<<16)
		if (s.flags & MF_BOUNCE) and s.oldwavespeed != nil
			if (s.wavespeed < max(1, s.oldwavespeed-5) )
			or (s.momz != s.oldwavespeedz)
				s.flags = $ & ~(MF_BOUNCE|MF_GRENADEBOUNCE)
				for d = 1,3
					s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_MINECARTSPARK)
					local t = s.missilelight
					t.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
					t.scale = 6000 --Samus' scale divided by 15.
					t.tics,t.fuse = 23,23
					P_InstaThrust(t, (120*d*ANG1)+s.angle, (4+(d*5))<<16 )
					t.momz = (s.momz/2)+(5*s.scale*P_MobjFlip(s))
				end	
			end
		end
	end
end, MT_WVSHOT)

addHook("MobjThinker", function(s) if not s.valid return end
	s.samusshot = true
	if s.wavebeamtimer == nil
		s.color = (s.color) or SKINCOLOR_MAGENTA
		s.wavebeamtimer = 8
		if (s.state != S_WVXP1)
			P_Thrust(s, s.angle+ANGLE_90, 2<<16)
			local t = s.target
			if t and t.crystalflashtime
				s.CFversion = true
			end	
		end
	end
	if s.bufferguard 
		if s.health
			if (s.target == nil 
			or s.target and not s.target.health
			or s.target and not s.target.wavebuffering
			)
			and s.valid and s.health
				s.bufferguard = false
				s.flags = $ & ~(MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPHEIGHT)
				P_ExplodeMissile(s) return --
			else
				s.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPHEIGHT
			end
		end
	elseif (s.flags & MF_BOUNCE)
		s.flags = $ & ~(MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPHEIGHT)
	end
	
	if (s.state == S_WVSHOT1) or (s.state == S_WVSHOT2)
	
		if not s.wavebeamtimer
			s.wavebeamtimer = 11
		else
			s.wavebeamtimer = $-1
		end
		local MOMANG = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
		P_Thrust(s, MOMANG+ANGLE_90, (s.wavebeamtimer>5) and 2<<16 or -2<<16)
		
		if (s.state == S_WVSHOT1) and not (s.flags2 & MF2_DONTDRAW)
			local ghs = P_SpawnGhostMobj(s)
			ghs.scale = s.scale
			ghs.blendmode = AST_ADD
			ghs.destscale = 1
			if (leveltime%2==0)
				if (leveltime%4==0)
					ghs.rollangle = leveltime*ANG2
				end
				ghs.color,ghs.colorized = SKINCOLOR_SUPERGOLD5, true
				ghs.tics = 16
			end
			if not s.bufferguard or (leveltime % 3 == 0)
				local HEIGHT = (s.eflags & MFE_VERTICALFLIP) and s.height/2 or 0
				s.plexpand = P_SpawnMobj(s.x, s.y, s.z+HEIGHT, MT_PBEXPANDW)
				if s.plexpand
					local RNG = P_RandomRange(1, 4)
					s.plexpand.blendmode = AST_ADD
					s.plexpand.scale = $*((RNG>2) and 2 or 1)
					s.plexpand.scalespeed = $*RNG
					s.plexpand.destscale = $*20
				end
				if not s.bufferguard and not s.CFversion
					A_SAMPARTICLE(s, MT_MPR1, 4, 5, -4, 4, s.color, P_RandomRange(29355, 54355))
				end				
			end
		end
		
	else --if (s.state == S_WVXP1) 
		if s.saldsalf or (s.flags2 & MF2_DONTDRAW)
			return --
		end
	
		--The Wave Charge Shot explodes into tons of smaller shot, some which home into foes/monitors, some which are randomly scattered.
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -30, 30, 17, 50000)
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -30, 30, 17, 40000)
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 30, -30, 30, 17, 45000)
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -30, 30, 17, 47000)
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 30, -3, 3, 17, 60000)
		if not (s.CFversion)
			A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -15, 15, 17, 43000)
			A_SAMPARTICLE(s, MT_WVSHOT, 1, 30, -20, 20, 17, 42000)
		end
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 30, -20, 20, 17, 48000)
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -1, 1, 17, 54000)
		A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -5, 5, 17, 59000)
		s.destscale = s.scale*10
		s.scalespeed = $*3
		s.saldsalf = true
		
		--Fire off 1 homing bullet. Does not home onto players.
		if not s.CFversion
			s.shottarget,s.shottarget2 = nil,nil
			local lastdist,lastdist2
			searchBlockmap("objects", function(s, m)
				if m and m.valid and (m.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR)) and m.health  --Anything around?
					if not (m.subsector == s.subsector and (m.z < (s.floorz-5*s.scale)) )
						if P_CheckSight(s, m)
							if not s.shottarget or s.shottarget2
								if lastdist == nil
								or (R_PointToDist2(s.x, s.y, m.x, m.y) < lastdist)
									if m != s.shottarget2
										s.shottarget = m
										lastdist = R_PointToDist2(s.x, s.y, m.x, m.y)
									end
								end
							elseif lastdist2 == nil
							or (R_PointToDist2(s.x, s.y, m.x, m.y) < lastdist2)
								if m != s.shottarget
									s.shottarget2 = m
									lastdist2 = R_PointToDist2(s.x, s.y, m.x, m.y)
								end
							end
						end
					end
				end
			end, s, s.x-2200<<16, s.x+2200<<16, s.y-2200<<16, s.y+2200<<16)	
		end
		
		local wvhome = s.shottarget2
		local TOTAL = 0
		for i = 1,2
			if i==2 wvhome = s.shottarget end
			if wvhome and wvhome.valid
				local ghs = P_SpawnMissile(s, wvhome, MT_WVSHOT)
				if ghs and ghs.valid
					TOTAL = $+1
					ghs.target = s.target
				end
			end		
		end
		if TOTAL == 0 --Nothing found, then do old behaviour.
			A_SAMPARTICLE(s, MT_WVSHOT, 1, 30, -30, 30, 17, P_RandomRange(40501, 50701))
			A_SAMPARTICLE(s, MT_WVSHOT, 1, 40, -10, 10, 17, P_RandomRange(40000, 57000))
		end
		
		--Shiny explosion graphic.
		local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_THOK)
		ghs.color = SKINCOLOR_PURPLE
		ghs.sprite = SPR_MBOM
		ghs.frame = R|FF_TRANS30
		ghs.blendmode = AST_ADD
		ghs.renderflags = $|RF_FULLBRIGHT
		ghs.tics,ghs.fuse = 99,13
		P_SetObjectMomZ(ghs, 4<<16)
		ghs.scalespeed,ghs.destscale = $*3, 99<<16
		if (gametype == GT_COOP)
			P_RadiusAttack(s, s, 50<<16, DMG_ELECTRIC, false)
		end
		
		ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_THOK)
		ghs.flags2 = $|MF2_DONTDRAW ghs.tics = 99
		S_StartSound(ghs, sfx_wvxpz)
		S_StartSound(ghs, sfx_wvxpz)
		
		if not s.CFversion
			local t
			local ANG = P_RandomRange( 1,360)*ANG1
			local SCALE = s.scale/15
			local MOMZMULT = P_RandomRange(22500,65350)
			for d = 1,6
				s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_MINECARTSPARK)
				t = s.missilelight
				t.blendmode = AST_ADD
				t.scale = SCALE
				t.fuse = 30
				P_InstaThrust(t, ANG+(ANG60*d), P_RandomRange(4+d*2, 26-d)<<16)
				t.momz = 7*MOMZMULT*d
			end
		end

		s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_SAMMISSILELIGHT)
		local t = s.missilelight
		t.blendmode = AST_ADD
		t.scale = s.scale/70
		t.color = SKINCOLOR_SUPERGOLD5
		t.layers = 1	
	end
end, MT_WVCHARGESHOT)

local function RemoveStunner(s) if not (s and s.valid) return end
	if s.target and s.target.valid --Remove the stun effect, ofc.
		s.target.rollangle = 0
		s.target.waverstunned = nil
	end s.state = S_NULL return true --
end
addHook("MobjThinker", function(s) if not s.valid return end --
	s.dietime = (s.dietime==nil) and 149 or max($-1,0)
	local t = s.target
	if s.dietime == 0 or s.tics == 1
	or not (t and t.valid and t.health)
		RemoveStunner(s) return --
	end
	if s.spazerstunner --Technically not a stunner, but....
		s.spazerstunner = $-1
		if s.spazerstunnersetup == nil
			t.spazerdirect = ((t.spazerdirect==nil) or (t.spazerdirect==1)) and -1 or 1
			s.spazerstunnersetup = true
			s.spazerstunnera = t.angle
		end
		if s.spazerstunang != nil
			if not (t.flags2 & MF2_FRET) and t.tics != -1 and (t.tics < 24)	
			and not t.player and (t.flags & (MF_BOSS|MF_ENEMY|MF_SHOOTABLE))			
				t.tics = $+1
			end
			t.momx,t.momy = 0,0
			P_InstaThrust(t, s.spazerstunang, s.spazerstunner*95355)
			if (t.flags & MF_NOGRAVITY)
				s.spazerroll = s.spazerroll and $+(((ANG30/2)*(t.spazerdirect*2))) or ((ANG30/2)*(t.spazerdirect*2))
			end
			s.spazerstunnera = $+(ANGLE_45*t.spazerdirect)
			t.angle = s.spazerstunnera
			if (s.z < s.floorz+60<<16)
				S_StartSound(t, sfx_s3k7e)
				local RNGFRAME = P_RandomRange(0,2)
				local RADIUS = max(t.radius, 32*t.scale)
				local ANGLE = t.angle+ANGLE_90
				for i = -1,1
					local ghs = P_SpawnMobj(
					t.x+FixedMul(RADIUS*i, cos(ANGLE)),
					t.y+FixedMul(RADIUS*i, sin(ANGLE)),
					t.z, MT_SPINDUST)
					if ghs and ghs.valid
						ghs.frame = RNGFRAME
					end
				end	
			end
		end
		if (s.spazerstunner > 6) and (s.tics > 6)
			t.waverstunned = true
			if not (t.type > 53) --Lazy.
				t.color = SKINCOLOR_GREEN
				t.colorized = true
				s.icolorizedthem = true
			end
		else
			t.waverstunned = nil
			if s.icolorizedthem --Thanks.
				s.icolorizedthem = false
				t.color = SKINCOLOR_NONE
				t.colorized = false
			end
			if not s.spazerstunner
				if t and t.valid
					if s.spazerroll != nil
						s.rollangle = 0
					end
					t.waverstunned = nil
				end
				s.state = S_NULL --return
			end				
		end				
		return --
		
	else --ACTUAL Wave Beam Stunner!
	
		local ghs = P_SpawnGhostMobj(t)
		ghs.tics = 11
		ghs.blendmode = AST_ADD
		ghs.scalespeed = $/10*P_RandomRange(5,8)
		ghs.destscale = $*50
		ghs.colorized = true
		ghs.momx = P_RandomRange(-3,3)<<16 ghs.momy = P_RandomRange(-3,3)<<16
		ghs.momz = P_RandomRange(0,2)<<16*P_MobjFlip(t)
		if s.dietime % 4 == 0
			if not NoPushList(t)
				t.angle = $-ANG20
			end
			A_SAMPARTICLE(t, MT_MPR1, 4, 4, -2, 6, SKINCOLOR_GOLD, P_RandomRange(9355, 30355))
			A_SAMPARTICLE(t, MT_MPR1, 5, 3, -3, 6, SKINCOLOR_MAGENTA, P_RandomRange(35355, 65154))					
			P_TryMove (t, s.x+P_RandomRange(-9,9)<<16, s.y+P_RandomRange(-9,9)<<16, true)
			ghs.color = P_RandomRange(SKINCOLOR_SUPERPURPLE1, SKINCOLOR_SUPERPURPLE5)
		else
			t.angle = $+ANG10
			ghs.color = SKINCOLOR_GRAVITYSUIT
			if (s.dietime % 30 == 0)
				S_StartSound(t, sfx_wvbc)
				if t.samusHP and (t.samusHP > 1) --Slowly wittle down the HP to 1 max from the shocks.
					t.samusHP = $-1
				end
				local ghs = P_SpawnGhostMobj(t)
				ghs.renderflags = RF_NOCOLORMAPS|RF_FULLBRIGHT
				ghs.tics = 20
				ghs.scalespeed = FRACUNIT/3
				ghs.destscale = 50<<16
				ghs.color,ghs.colorized = SKINCOLOR_SUPERGOLD5, true
				local XSHIFT = FixedMul(P_RandomRange(6,22)<<16, cos(t.angle) )
				local YSHIFT = FixedMul(P_RandomRange(22,6)<<16, sin(t.angle) )
				P_TryMove (t, s.x+XSHIFT, s.y+YSHIFT , true)
				if not NoPushList(t)
					t.angle = $+((P_RandomRange( 4,5)==5) and ANG30*3 or -ANG30*3)
				end
				local ghs = P_SpawnMobj(t.x, t.y, t.z, MT_SAMUSZAP)
				ghs.renderflags = RF_NOCOLORMAPS|RF_FULLBRIGHT
				ghs.scale = s.scale*2
				ghs.color = SKINCOLOR_SUPERGOLD4
				ghs.morning = 4
			end			
		end
		if not (t.flags2 & MF2_FRET) and t.tics != -1 and (t.tics < 24)	
		and not t.player and (t.flags & (MF_BOSS|MF_ENEMY|MF_SHOOTABLE))
			t.tics = $+1
		end
		t.momx,t.momy = 0,0
		s.z = t.z+(t.height/2)

		if (s.tics > 6)
			t.waverstunned = true
			if not (t.type > MT_DRAGONBOMBER) 
			and not t.player and (t.flags & (MF_BOSS|MF_ENEMY|MF_SHOOTABLE)) --Lazy.
				t.color = SKINCOLOR_GRAVITYSUIT
				t.colorized = true
				s.icolorizedthem = true
			end
		else		
			t.waverstunned = nil
			if s.icolorizedthem
				s.icolorizedthem = false
				t.color = SKINCOLOR_NONE
				t.colorized = false
			end
		end
		if s.dietime == 0 or s.tics == 1
		or not (t and t.valid and t.health)
			RemoveStunner(s) --
		end
	end
end, MT_WAVESTUNNER)

addHook("MobjThinker", function(s) if not s.valid return end
	s.color = SKINCOLOR_CLOUDY
	s.samusshot = true
	
	if (s.state == S_ICSHOT1) or (s.state == S_ICSHOT2)
		s.shadowscale = 29876
	--  A_SAMPARTICLE(s, TYPE, XYOFFSET, XYMOM, minMOMZ, maxMOMZ, COLOR, SCALE, SPECIAL, customTARGET)
		local ghs = A_SAMPARTICLE(s, MT_MPR6, 0, 1, -2, 1, SKINCOLOR_CLOUDY, 58000) --Ice Flakes
		if ghs and ghs.valid
			ghs.fuse = 99
		end
		if (s.state == S_ICSHOT1) --Icy Smoke trail
			local ghs = A_SAMPARTICLE(s, MT_MPR7, 3, 0, -2, 1, SKINCOLOR_CLOUDY, P_RandomRange(20000, 45000)+50000)
			if ghs and ghs.valid
				ghs.spriteyoffset = $-21<<16
			end
		end
	elseif (s.state == S_ICXP1)
		s.shadowscale = 0
		if not s.saldsalf
			A_Samuskillstuff(s, 138<<16, 90<<16, s.target, false, false, true)		
			local RNG = P_RandomRange(11785,35355)*3
			
			A_SAMPARTICLE(s, MT_MPR7, 11, 7, -2, 3, s.color, P_RandomRange( 2, 6)*(RNG/2))
			A_SAMPARTICLE(s, MT_MPR7, 11, 7, -3, 3, s.color, P_RandomRange( 1, 3)*35355)
			A_SAMPARTICLE(s, MT_MPR7, 0, 6, -2, 3, s.color, 2*35355)
			A_SAMPARTICLE(s, MT_MPR7, 12, 7, -3, 4, s.color, RNG)
			A_SAMPARTICLE(s, MT_MPR7, 11, 6, -2, 3, s.color, P_RandomRange(3, 9)*(RNG/3))
			s.blendmode = AST_ADD
			s.saldsalf = true
	
			if s.z > s.ceilingz-55<<16 --Make a shiny effect!
			or s.z < s.floorz+55<<16
				local ghs = SamShinySplat(s,SKINCOLOR_SUPERSILVER5, 10)
				ghs.scale = $/3
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.destscale = $*99
				ghs.frame = A|FF_TRANS80
			end
		end
	elseif (s.state == S_ICXP4)
		if not s.saldsalf2
			s.destscale = s.scale*10
			s.renderflags = $|RF_FULLBRIGHT
			s.blendmode = AST_ADD
			P_SetObjectMomZ(s, FRACUNIT)
			s.saldsalf2 = true
		end
	end
end, MT_ICSHOT)

addHook("MobjThinker", function(s) if not s.valid return end
	if not s.fuse s.fuse = 99 end
end, MT_MPR6)

addHook("MobjThinker", function(s) if not s.valid return end
	if not P_IsObjectOnGround(s)
		if s.rollspeed != nil
			s.rollnewangle = s.rollnewangle and $+s.rollspeed or 1
			s.rollangle = s.rollnewangle
		end
	else
		if s.sprite == SPR_ROIA
			P_SetObjectMomZ(s, 5<<16)
			if leveltime%4==0
				s.rollangle = $-ANGLE_45
			end
		else
			s.momx,s.momy,s.momz = 0,0,0
			s.flags = $ & ~(MF_BOUNCE|MF_GRENADEBOUNCE)
		end
	end
end, MT_MPR8)

addHook("MobjThinker", function(s) if not s.valid return end
	if not s.saldsalf3
		s.shadowscale = 69956
		if not s.combograce
			s.destscale = $*4
		end
		s.color = SKINCOLOR_CLOUDY
		s.blendmode = AST_ADD
		s.samusshot,s.saldsalf3 = true,true
	end
	if (s.state == S_ICSHOT1) or (s.state == S_ICSHOT2)
		A_SAMPARTICLE(s, MT_MPR6, 1, 1, -2, 1, s.color, 90000)
		P_SetObjectMomZ(s, 9900, true)
		if (s.state == S_ICSHOT1)
			A_SAMPARTICLE(s, MT_MPR7, 3, 1, -2, 1, s.color, 96000)
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPANDI)
			ghs.scalespeed = $*P_RandomRange(3, 9)
			ghs.destscale = $*25
			ghs.blendmode = AST_ADD
		end
	elseif (s.state == S_ICXP1)	
		s.shadowscale = 0
		if not s.saldsalf and not s.combograce				
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_ICBRSOUND)
			S_StartSound(ghs, sfx_icbr)
			s.saldsalf = true
		
			if s.z > s.ceilingz-55<<16
			or s.z < s.floorz+55<<16
				local ghs = SamShinySplat(s,SKINCOLOR_ICY, 11)
				ghs.frame = A|FF_TRANS40|FF_FULLBRIGHT
				ghs.scalespeed = $*2 ghs.destscale = FRACUNIT*99
			end		
			if G_GametypeHasSpectators() --Don't be QUITE as generous in Match.
				A_Samuskillstuff(s, 305<<16, 160<<16, s.target, true)
			else
				A_Samuskillstuff(s, 370<<16, 180<<16, s.target, false, false, true)
			end	
			local CTABLE = {SKINCOLOR_SUPERSKY1, SKINCOLOR_SUPERSKY2, SKINCOLOR_SUPERSKY3, SKINCOLOR_SUPERSKY4,SKINCOLOR_SUPERSKY5,
			SKINCOLOR_SUPERSKY1, SKINCOLOR_SUPERSKY2, SKINCOLOR_SUPERSKY3, SKINCOLOR_SUPERSKY4,SKINCOLOR_SUPERSKY5,
			SKINCOLOR_SUPERSKY2, SKINCOLOR_SUPERSKY4, SKINCOLOR_SUPERSKY1}	
			if not s.icesummon
				A_samquake(s, 18<<16, 10, 1)
				for d = 1,12
					local ghs = A_SAMPARTICLE(s, MT_MPR7, P_RandomRange( 8,d*2), d*3, -2, min(12, (d*3/2)), CTABLE[d], ((d%2) and 5 or 7)<<16)
					if (d%2) and ghs and ghs.valid
						ghs.colorized = true
					end
				end
			else
				A_SAMPARTICLE(s, MT_MPR7, 9, 9, -2, 6, P_RandomRange( SKINCOLOR_SUPERSKY1, SKINCOLOR_SUPERSKY5), 4<<16)	
			end	
		end
	elseif (s.state == S_ICXP4) 
		if not s.saldsalf2
			s.destscale = s.scale*10
			s.saldsalf2 = true
			local CTABLE = {SKINCOLOR_SUPERSKY1, SKINCOLOR_SUPERSKY2, SKINCOLOR_SUPERSKY3, SKINCOLOR_SUPERSKY4,SKINCOLOR_SUPERSKY5,
			SKINCOLOR_SUPERSKY1, SKINCOLOR_SUPERSKY2, SKINCOLOR_SUPERSKY3, SKINCOLOR_SUPERSKY4,SKINCOLOR_SUPERSKY5,
			SKINCOLOR_SUPERSKY2, SKINCOLOR_SUPERSKY4, SKINCOLOR_SUPERSKY5, SKINCOLOR_SUPERSKY1}	
			if not s.icesummon
				if s.wallclipped and s.target
					local t = s.target
					P_Thrust(t, t.angle, -6<<16)
					P_MoveOrigin(s, t.x, t.y, t.z+(t.height/2))
				end			
				SamFaceReflect(s, 210<<16)
				for d = 1,8
					local ghs = A_SAMPARTICLE(s, MT_MPR6, 8, d*4, -2, d*2, CTABLE[d], (3+d)<<16)
					if ghs and ghs.valid
						ghs.fuse = 99
					end
				end
			else
				local ghs = A_SAMPARTICLE(s, MT_MPR6, 7, 11, -2, 6, P_RandomRange( SKINCOLOR_SUPERSKY1,SKINCOLOR_SUPERSKY5), 7<<16)
				if ghs and ghs.valid
					ghs.fuse = 99
				end				
			end
		end
	end
		
	if s.combograce
		s.combograce = $-1
		if not s.combograce
			s.flags = $ & ~(MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPHEIGHT)
		else
		/*	if not s.combowarped and s.icesummon and s.icesummon.valid
				if abs(s.z-s.icesummon.z) > 99<<16
					s.z = s.icesummon.z+5<<16
				end
				s.combowarped = true
			end */
			if (s.combograce > 8)
				s.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE & ~MF_NOCLIPHEIGHT
			else
				s.flags = $|MF_BOUNCE & ~(MF_NOCLIPHEIGHT|MF_GRENADEBOUNCE)
			end
		end
	end
	if s.romio and s.romio.valid
		s.flags = $|MF_NOGRAVITY
		P_MoveOrigin(s, s.romio.x, s.romio.y, s.romio.z+(s.romio.height/3))
		if s and s.valid and not s.romio.health
			s.state = S_NULL return --
		end
	end
end, MT_ICCHARGESHOT)

addHook("MobjThinker", function(s) if not s.valid return end --
	s.samusshot = true	
	if not s.saldsalf
		if not s.saldsalf3
			s.destscale = FRACUNIT
			s.saldsalf3 = true
			s.color = (s.color) or SKINCOLOR_WHITE
		end
		if s.health
			if not (s.z <= s.floorz) and not (s.z > s.ceilingz-150<<16)
				if (leveltime%2==0) or s.prevticx == nil
					s.prevticx,s.prevticy = s.x,s.y
				end
				s.prevticz = s.z
			end
			if not s.asfal and (s.z+s.height >= s.ceilingz-s.momz) and P_MobjFlip(s)==1
				s.asfal = true
				P_ExplodeMissile(s)
				if not (s and s.valid) return end --
			end
		end
	end	
	if (s.state == S_ICSHOT1) or (s.state == S_ICSHOT2)
		A_SAMPARTICLE(s, MT_MPR6, 1, 1, -2, 1, s.color, SAM.RNG(8500, 9935,s)*10)
		if (s.tics > 1)
			s.tics = $-1
		end
		if (s.state == S_ICSHOT1)
			A_SAMPARTICLE(s, MT_MPR7, 3, 1, -2, 1, s.color, SAM.RNG(9000, 9900,s)*30)
			A_SAMPARTICLE(s, MT_MPR6, 6, 10, -2, 7, s.color, P_RandomRange(8, 16)<<16)
			A_SAMPARTICLE(s, MT_MPR6, 8, 11, -2, 5, s.color, SAM.RNG(4, 16,s)<<16)
			A_SAMPARTICLE(s, MT_MPR6, 6, 10, -2, 6, s.color, P_RandomRange(8, 16)<<16)
			A_SAMPARTICLE(s, MT_MPR6, 8, 12, -2, 5, s.color, SAM.RNG(8, 16,s)<<16)
			A_SAMPARTICLE(s, MT_MPR6, 6, 11, -2, 6, s.color, P_RandomRange(4, 16)<<16)
			A_SAMPARTICLE(s, MT_MPR6, 8, 10, -2, 4, s.color, P_RandomRange(8, 16)<<16)
			A_SAMPARTICLE(s, MT_MPR6, 6, 12, -2, 5, s.color, P_RandomRange(8, 16)<<16)
			s.plexpand = P_SpawnMobj(s.x, s.y, s.z+(s.height*2), MT_PBEXPANDI)
			s.plexpand.scale = $*P_RandomRange(2,6)
			s.plexpand.scalespeed = $*P_RandomRange(6, 10)
			s.plexpand.destscale = $*25
		end
	elseif (s.state == S_ICCMXP4)	
		A_SAMPARTICLE(s, MT_MPR6, 6, 15, -2, 20, s.color, (P_RandomRange(8, 16))<<16)
		A_SAMPARTICLE(s, MT_MPR6, 8, 16, -2, 18, s.color, SAM.RNG(4, 16,s)<<16)
		A_SAMPARTICLE(s, MT_MPR6, 6, 15, -2, 19, s.color, (P_RandomRange(8, 16))<<16)
		A_SAMPARTICLE(s, MT_MPR6, 8, 17, -2, 18, s.color, SAM.RNG(8, 16,s)<<16)
		A_SAMPARTICLE(s, MT_MPR6, 6, 16, -2, 19, s.color, (P_RandomRange(4, 16))<<16)
		A_SAMPARTICLE(s, MT_MPR6, 8, 15, -2, 17, s.color, (P_RandomRange(8, 16))<<16)
		A_SAMPARTICLE(s, MT_MPR6, 6, 17, -2, 18, s.color, (P_RandomRange(8, 16))<<16)		
	elseif (s.state == S_ICCMXP1) or (s.state == S_ICCMXP2) --Initial explosion states.
		if not s.saldsalf
			A_Samuskillstuff(s, 370<<16, 220<<16, s.target, false, false, true)
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_ICBRSOUND)
			if s.prevticx != nil
				P_MoveOrigin(s, s.prevticx, s.prevticy, s.prevticz)
			end
			S_StartSound(ghs, sfx_icbr)
			s.scale = (s.target) and s.target.scale*3 or 280355
			A_SAMPARTICLE(s, MT_MPR7, 10, 9, -2, 7, s.color, P_RandomRange(6, 10)<<16)
			A_SAMPARTICLE(s, MT_MPR7, 8, 8, -2, 5, s.color, SAM.RNG(7, 10,s)<<16)
			A_SAMPARTICLE(s, MT_MPR7, 10, 9, -2, 6, s.color, P_RandomRange(6, 10)<<16)
			A_SAMPARTICLE(s, MT_MPR7, 8, 8, -2, 5, s.color, P_RandomRange(6, 10)<<16)
			A_SAMPARTICLE(s, MT_MPR7, 10, 9, -2, 6, s.color, P_RandomRange(6, 10)<<16)
			A_SAMPARTICLE(s, MT_MPR7, 8, 8, -2, 5, s.color, P_RandomRange(6, 10)<<16)
			A_SAMPARTICLE(s, MT_MPR7, 10, 9, -2, 5, s.color, P_RandomRange(7, 10)<<16)
			s.saldsalf = 1	
			P_StartQuake(10<<16, 8, table, nil)
			S_StartSound(s, sfx_iccm2)
			S_StartSound(s, sfx_iccm2)
			if not s.THROWTYPE
				if (s.z <= s.floorz+30<<16)
					s.THROWTYPE = "floor"
				elseif (s.z+s.height < s.ceilingz-230<<16)
					s.THROWTYPE = "sky"
				else
					s.THROWTYPE = "wall"
				end
			end			
		end	
	end

	if s.saldsalf
		s.saldsalf = $+1
		if s.addsaldsalf
			s.addsaldsalf = false
			s.saldsalf = $+100
		end
		if not (s.target and s.target.valid)
			s.scalespeed = 40000 --Disappear.
		end
		if (s.saldsalf%2==0) 
			if s.saldsalf == 220
				s.destscale = 5
				s.scalespeed = 2750
				s.saldsalf = 221
			end
		--	A_SAMPARTICLE(s, TYPE, XYOFFSET, XYMOM, minMOMZ, maxMOMZ, COLOR, SCALE, SPECIAL, customTARGET)
			if s.THROWTYPE == "floor"
				if (s.saldsalf%4==0) 
					A_SAMPARTICLE(s, MT_ICCHARGESHOT, 0, 52, 11, 50, s.color, P_RandomRange(8, 16)<<16, "ice", s.target)
				end
			elseif s.THROWTYPE == "sky"
				A_SAMPARTICLE(s, MT_ICCHARGESHOT, 0, 80, -22, -1, s.color, P_RandomRange(8, 16)<<16, "ice", s.target)
			end
		elseif (s.saldsalf % 3 == 0) --"Wall" version //s.THROWTYPE != "wall"  and 
			A_SAMPARTICLE(s, MT_ICCHARGESHOT, 0, 66, (s.THROWTYPE == "floor" and 6) or -4, (s.THROWTYPE == "sky" and -1) or 41, s.color, P_RandomRange(8, 16)<<16, "ice", s.target)
		end
		if s.valid
			if (s.saldsalf > 280) or (s.scale < 100)
				s.state = S_NULL return --
			elseif (s.saldsalf > 251)
				s.flags2 = $|MF2_SHADOW
			end			
		end
	end
end, MT_ICCHARGECOMBO)

--I cry right now.
addHook("MobjThinker", function(s) if not s.valid return end
	if (s.state == S_ICXP1)
		s.flags = $ & ~MF_SOLID
	end
end, MT_ICBLOCK)

local function RemoteFreeze(s) if not s.valid return end
	if s.tracer and s.tracer.frozenbox and s.tracer.health
		if not (s.frozencage and s.frozencage.valid)
			s.frozencage = P_SpawnMobj(s.x, s.y, s.z-s.height/3, MT_ICBLOCK)
			s.frozencage.scale = s.height/15
			s.frozenbox = true
		elseif (s.frozencage and s.frozencage.valid)
			local t = s.frozencage
			P_TryMove (s, t.x, t.y)
			s.tics,t.fuse = 16,2
			s.momx,s.momy,s.momz = 0,0,0
		end
	end 
end
local function RemoteFreezeFix(s) --Fix rare charged ice beam glitch
	if s.valid and s.frozencage and s.frozencage.valid
		P_RemoveMobj(s.frozencage) return --
	end 
end
addHook("MobjRemoved", RemoteFreezeFix, MT_CRUSHCLAW)
addHook("MobjRemoved", RemoteFreezeFix, MT_BANPSPRING)
addHook("MobjThinker", RemoteFreeze, MT_CRUSHCLAW)
addHook("MobjThinker", RemoteFreeze, MT_BANPSPRING)

addHook("MobjThinker", function(s) if not s.valid return end --
	if not (s.chozobox and s.chozobox.valid and s.samusshooter)
		s.state = S_NULL return --
	end
	local m = s.chozobox
	if m.frozenbox == nil
	and (m.flags & (MF_ENEMY|MF_BOSS)) and (m.flags & MF_SHOOTABLE)
		if (m.type == MT_SNAILER)
			m.lastsnailerz = m.z
		elseif (m.type == MT_DETON)
			m.state = m.info.spawnstate
		end
		if m.health == 1
			s.frozenboxstate = m.state
			s.frozenboxflags = m.flags
			s.frozenboxeflags = m.eflags
			s.frozenboxflags2 = m.flags2
			m.flags = MF_NOGRAVITY|MF_SCENERY
			m.momx,m.momy,m.momz = 0,0,0
			
			if m.target and m.target.player  and not (m.type == MT_DETON)
			and not ((m.flags == MF_BOSS|MF_SPECIAL|MF_BOUNCE) and (m.scale == 57000))
				m.target = nil
			end

			S_StartSound(m, sfx_icfr)
			s.frozentimer = 999
			s.frozencage = P_SpawnMobj(m.x, m.y, m.z-m.height/3, MT_ICBLOCK)
			s.frozencage.scale = m.height/15
			m.frozenbox = true return --
		end
	elseif s.frozencage
		local t = s.frozencage
		
		if m and m.valid and m.frozenbox
		
			P_TryMove(t, m.x, m.y)
			P_SetMobjStateNF(m, s.frozenboxstate)
			t.flags = $|MF_NOCLIPHEIGHT
			t.z = m.z-m.height/3
			m.flags = MF_NOGRAVITY|MF_SCENERY
			m.momx,m.momy,m.momz = 0,0,0
			m.tics = 16
			if (m.type == MT_SNAILER) and m.lastsnailerz != nil
				m.z = m.lastsnailerz
				P_MoveOrigin(t, m.x, m.y, m.z)
			end
			if t.refreshiceblock
				t.refreshiceblock = false
				t.state = S_ICBLOCK
				t.scale = m.height/15
				s.frozentimer = 999
				S_StartSound(t, sfx_icfr)
			end
			--test3dice , no longer a test.
			for d = 1,4
				local ghs = P_SpawnMobj(t.x+FixedMul(t.radius, cos(t.angle+(ANGLE_90*d))), t.y+FixedMul(t.radius, sin(t.angle+(ANGLE_90*d))), t.z, MT_THOK)
				ghs.sprite = SPR_ICXP
				ghs.renderflags = RF_SEMIBRIGHT|RF_PAPERSPRITE
				ghs.frame = F|FF_TRANS40
				ghs.angle = (t.angle+(ANGLE_90*d))+ANGLE_90
				ghs.scale = t.scale
				ghs.tics = 2
				if d == 1
					for i = 0,1,1
						local ths = P_SpawnMobj(ghs.x-(t.radius), ghs.y-(t.radius), t.z+(t.height*i), MT_THOK)
						ths.sprite = SPR_ICXP
						ths.frame = F|FF_TRANS40
						ths.renderflags = $|RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_NOSPLATROLLANGLE
						ths.scale = t.scale
						ths.tics = 2				 
					end								
				end
			end
			
			if s and t and m and m.valid and (t.icethisfool or ((m.health <= 0)))
				t.flags = MF_NOGRAVITY
				t.state = S_ICXP1
				t.destscale = $*2
				t.yarhar = P_SpawnMobj(t.x, t.y, t.z, MT_ICBRSOUND)
				S_StartSound(t.yarhar, sfx_icbr)
				if (m.type == MT_DETON) --You're weird.
					m.flags = MF_SHOOTABLE
					m.state = m.info.spawnstate
				else
					m.state = s.frozenboxstate
					m.flags = s.frozenboxflags
					m.flags = $|MF_SHOOTABLE
					m.eflags = s.frozenboxeflags
					m.flags2 = s.frozenboxflags2
				end
				
				local CLOSERANGE = false
				A_samquake(s, 12<<16, 10, 1000<<16)
				for z in players.iterate
					if z.mo and (FixedHypot(FixedHypot(m.x-z.mo.x, m.y-z.mo.y), m.z-z.mo.z) < 1000<<16)
						for d = 1,18						
							local ghs = P_SpawnMobj(
							t.x+((P_RandomRange(-70, 70))*t.scale),
							t.y+((P_RandomRange(-70, 70))*t.scale), t.z+t.height/2, MT_MPR8)
							ghs.color = SKINCOLOR_SKY
							ghs.target = t 
							local rng = P_RandomRange(500, 55000)
							local angrng = P_RandomRange(-50,50)*ANG1
							P_InstaThrust(ghs, z.mo.angle+(angrng), z.speed+13<<16)
							ghs.momz = (rng*18)+m.momz
							ghs.spriteyscale = $+(rng*3)
							ghs.spritexscale = $+(rng*3)
							ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE
							ghs.frame = A+P_RandomRange(0,1)|((FRACUNIT*2)+(P_RandomRange(0,5)<<16))
							ghs.blendmode = AST_ADD
							ghs.combograce = 14
							ghs.icesummon = s
							ghs.rollspeed = angrng
							ghs.rollnewangle = rng*ANG1
							CLOSERANGE = true 
						end
						if CLOSERANGE == true break end --
					end
				end
				if CLOSERANGE != true
					--Ice Shatter time!
					for d = 1,16
						local ghs = P_SpawnMobj(
						t.x+((P_RandomRange(-70, 70))*t.scale), 
						t.y+((P_RandomRange(-70, 70))*t.scale), t.z+t.height/2, MT_MPR8)
						ghs.color = SKINCOLOR_SKY
						ghs.target = t 
						ghs.momx = (P_RandomRange(-9,9,ghs))<<16+m.momx
						ghs.momy = (P_RandomRange(9,-10,ghs))<<16+m.momy
						
						local rng = P_RandomRange(500, 55000,s)
						
						ghs.momz = (rng*18)+m.momz
						ghs.spriteyscale = $+(rng*3)
						ghs.spritexscale = $+(rng*3)
						ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE
						ghs.frame = A+P_RandomRange(0,1) | ((FRACUNIT*2)+(P_RandomRange(0,5)<<16))
						ghs.blendmode = AST_ADD
						ghs.combograce = 14
						ghs.icesummon = s
						ghs.rollspeed = P_RandomRange(-46,46,ghs)*ANG1
						ghs.rollnewangle = rng*ANG1	
					end
				end
				local samusrng = P_RandomRange(1, 201)
				local FLOAT = (m.height*2/3)*P_MobjFlip(m)
				if (samusrng < 5)
					m.droppedsamitem = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGA)
				elseif (samusrng < 8)
					m.droppedsamitem = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_NRGB)
				elseif (samusrng < 70)
					m.droppedsamitem = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_MPKU)
				else
					local t = s.target local p = t and t.player				
					if (samusrng < 72)
						if p and p.samsupermissilesmax
							m.droppedsamitem = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_SPKU)
						end
					elseif (samusrng < 73)
						if p and p.sampwmax
							m.droppedsamitem = P_SpawnMobj(m.x, m.y, m.z+FLOAT, MT_PBOM)
						end
					end
				end
				if m.droppedsamitem and m.droppedsamitem.valid
					local MOVE = ((samusrng<100) and -samusrng or samusrng)*8000
					P_TryMove(m.droppedsamitem, m.droppedsamitem.x+MOVE+(6<<16), m.droppedsamitem.y+MOVE+(6<<16), true)
				end
				m.frozenbox = nil
				P_KillMobj(m, s, s.samusshooter)
				s.state = S_NULL return --
			end
		end
	end
	
	if not s.frozentimer s.state = S_NULL return end --
	
	s.frozentimer = $-1
	s.tics = 2
	s.flags2 = $|MF2_DONTDRAW --Lazy ahoy
	
	local ghs = P_SpawnMobjFromMobj(m, 0, 0, 0, MT_OVERLAY)		
	ghs.target = m
	ghs.sprite = m.sprite
	if m.skin
		ghs.skin = m.skin
		ghs.sprite2 = m.sprite2
	end
	ghs.frame = m.frame
	ghs.tics = 2
	ghs.rollangle = m.rollangle
	ghs.color,ghs.colorized = SKINCOLOR_SKY,true
	
	if s.frozentimer == 120 
		if s.frozencage
			s.frozencage.destscale = m.height/29
			s.frozencage.scalespeed = $/10
			s.frozencage.state = S_ICBLOCK2
		end
	elseif s.frozentimer == 1 and m and m.valid
		m.state = s.frozenboxstate
		m.flags = s.frozenboxflags
		m.flags = $|MF_SHOOTABLE
		m.eflags = s.frozenboxeflags
		m.flags2 = s.frozenboxflags2
		S_StartSound(m, sfx_icbf)
		m.frozenbox = nil
		if s.frozencage
			s.frozencage.blendmode = AST_ADD
			s.frozencage.state = S_ICXP1
		end
		s.state = S_NULL return --
	end
end, MT_FREEZETRACKER)

addHook("MobjLineCollide", function(s, i)
	return false --
end, MT_ICBLOCK)

addHook("MobjThinker", function(s)
	if s.gvtimer == nil or not s.samusshot
		s.samusshot = true
		s.gvtimer = 18
		if not s.gattlingvortex and not s.darkhyper
			s.color = SKINCOLOR_RED
		end
	end
	local FLAMEANGLE = R_PointToAngle2(s.x, s.y, s.x+s.momy, s.y+s.momy)
	if s.gattlingvortex and s.health
		if not (s.eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
			if s.gattlingvortex1
				if (leveltime % 2 == 0) and s.plshottimer
					A_SAMPARTICLE(s, MT_MINIEXP, 15, 20, -15, 15, SKINCOLOR_ORANGE, P_RandomRange(38355, 59355)*3)
				end
				if (s.gvtimer > 3) and (s.z+s.momz <= s.floorz+150<<16)
					local ghs = SamShinySplat(s,SKINCOLOR_FLAME, (s.gvtimer-3))
					ghs.frame = A|FF_TRANS70|FF_FULLBRIGHT
				end
			else			
				local sampng = P_RandomRange(1, 11)
				if (sampng < 5) and (leveltime % 2 == 0) and s.target
					local ghs = A_SAMPARTICLE(s, MT_MINIFIRE, 19, 1, -195, -176, s.color, P_RandomRange(48355, 64354)*2, nil, s.target)
					if ghs and ghs.valid and not ghs.fuse
						ghs.fuse = 160
					end
				end
			end
		end
	end
	if not s.darkhyper
		if (s.state == S_PLSHOT1)
			if (leveltime % 3 == 0) and s.gattlingvortex
				A_SAMPARTICLE(s, MT_MPR5, 6, 8, -2, 6, s.color, P_RandomRange(24355, 48355))
			else
				A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color, P_RandomRange(12355, 24355))
			end
			
			s.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
			if leveltime%3==0
				s.rollangle = leveltime*ANG30
			end
			if (s.gvtimer > 2)
				s.gvtimer = $-1	
				if (s.gvtimer > 12)
					s.spriteyscale = FRACUNIT/(s.gvtimer/4)
					s.spritexscale = FRACUNIT/(s.gvtimer/6)		
				elseif (s.gvtimer > 2)
					s.spriteyscale = FRACUNIT-(s.gvtimer*800)
					s.spritexscale = FRACUNIT-(s.gvtimer*900)
				end
				s.spriteyoffset = (8<<16)-(s.spriteyscale*8)
			else
				s.spritexscale,s.spriteyscale,s.spriteyoffset = FRACUNIT,FRACUNIT,0
			end
			SlideBeam(s, (not s.gattlingvortex) and 41<<16 or nil)
			if not s.gattlingvortex 
			or (s.plshottimer and s.plshottimer < 18)
			or s.gattlingvortex1 or (leveltime % 3 == 0) or (leveltime % 2 == 0)
			
				if s.ghs and s.ghs.valid --Not a local variable!!
					s.ghs.blendmode = s.blendmode
					if leveltime % 3 == 0
						s.ghs.rollangle = s.rollangle+ANGLE_90
					else
						s.ghs.rollangle = s.rollangle-ANGLE_90
					end
					s.ghs.spriteyscale = s.spriteyscale
					s.ghs.spritexscale = s.spritexscale
				end
				s.ghs = P_SpawnGhostMobj(s)
				s.ghs.scale = s.scale
				s.ghs.fuse = 10
				s.ghs.tics = 12
				s.ghs.scalespeed = $/3
				s.ghs.destscale = 1
				s.ghs.spriteyscale = s.spritexscale --Intentionally reverse x and yscale
				s.ghs.spritexscale = s.spriteyscale
				s.ghs.blendmode = s.blendmode
			--	s.ghs.rollangle = s.rollangle
			end
		elseif not s.saldsalf and (s.state == S_PLXP1)
			local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_THOK)
			ghs.flags2 = $|MF2_DONTDRAW ghs.tics = 99
			S_StartSound(ghs, sfx_plxpz)
			S_StartSound(ghs, sfx_plxpz)
			s.destscale = s.scale*15
			MonitorBreaker(s, s.target)
			s.scalespeed = $*2
			s.saldsalf = true
	--		SamusShotImpact(s)
			SamusBulletHole(s, s.scale+9900, SKINCOLOR_RED, true)
			
			if FLAMEANGLE != nil
				for d = -3,3
					local rng = P_RandomRange(-7,7)
					ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_THOK)
					ghs.sprite = SPR_MXP4
					ghs.blendmode = AST_ADD
					ghs.tics = 99
					ghs.scale = $/3 ghs.scalespeed = $*4
					ghs.destscale = $*99
					ghs.rollangle = $+(rng*ANG20)
					ghs.renderflags = $|RF_FULLBRIGHT //|RF_PAPERSPRITE
					ghs.angle = FLAMEANGLE+ANGLE_90+(rng*(ANG10))+(ANG20*d)
					P_SetObjectMomZ(ghs, d<<16+(2<<16), true)
					if d > 0 or s.gattlingvortex
						ghs.colorized = true
						ghs.color = s.color
					end					
					if s.gattlingvortex
						ghs.fuse = 16
						P_InstaThrust(ghs, ghs.angle, -40<<16)
					else
						ghs.fuse = 9
						P_InstaThrust(ghs, ghs.angle, -12<<16)						
					end
				end
			end
			if not s.gattlingvortex  --Open monitors easier, pls.
				searchBlockmap("objects", function(ref, m)
					if m.valid and (m.flags & (MF_MONITOR)) and m.health and (m.flags & (MF_SHOOTABLE))
						if not (s.x > m.x+120<<16) and not (s.x < m.x-120<<16)
						and not (s.y > m.y+120<<16) and not (s.y < m.y-120<<16)
						and not (s.z > m.z+120<<16) and not (s.z < m.z-120<<16)		
							A_SAMITEM(s, m)
						end
					end
				end, s, s.x-(120<<16), s.x+(120<<16), s.y-(120<<16), s.y+(120<<16))		
			end
			
			if s.gattlingvortex1
				A_Samuskillstuff(s, 90<<16, 80<<16, s.target, true)			
			end
		end
	else
	
		s.spritexscale,s.spriteyscale,s.spriteyoffset = FRACUNIT,FRACUNIT,0
		if not s.colorized
			s.colorized = true
			P_Thrust(s, P_RandomRange(1,359)*ANG1, P_RandomRange(-10,10)<<16)
			P_SetObjectMomZ(s, P_RandomRange(-5,5)<<16, true)
		end
		LeafSpawn(s, nil, true, 200)
		local ghs = P_SpawnGhostMobj(s)
		ghs.scale = s.scale
		ghs.blendmode = AST_ADD
		ghs.color = SKINCOLOR_COBALT
		P_Thrust(ghs, P_RandomRange(1,359)*ANG1, P_RandomRange(-30,30)<<16)
		P_SetObjectMomZ(ghs, P_RandomRange(-10,10)<<16, true)			
		ghs.destscale = $*P_RandomRange(1,6)
		if leveltime % 2 == 0
			A_SAMPARTICLE(s, MT_MPR5, 6, 8, -2, 6, SKINCOLOR_COBALT, P_RandomRange(24355, 48355))
			s.color = SKINCOLOR_JET
		else
			s.color = P_RandomRange(SKINCOLOR_SUPERSKY1, SKINCOLOR_SUPERSKY3)
		end
	end
	if not s.plshottimer
		s.plshottimer = 18
	else
		if (s.plshottimer == 1)
			s.state = S_NULL return	--
		end	
		s.plshottimer = $-1
	end
end, MT_PLSHOT)

addHook("MobjThinker", function(s) if not s.valid return end --
	if (s.eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
		s.state = S_NULL return --
	else
		if s.morning
			s.samusshot = true --SamusShot is NOT always added here!
			s.morning = $-1
			if s.morning == 1
				P_KillMobj(s) return --
			end
		end
		if s.fuse and (s.fuse < 11)
			s.samusshot = true
			s.spritexscale,s.spriteyscale = $+4000,$+4000
			s.TRANSvalue = s.TRANSvalue and min(FF_TRANS90, $+FF_TRANS10) or FF_TRANS10
			s.frame = ($ & ~FF_TRANSMASK)|(s.TRANSvalue)
		end
	end
end, MT_MINIFIRE)

local function FireCollide(s, m)
	if not (m and m.valid and s.health and m.health)
	or not (m.flags & (MF_BOSS|MF_ENEMY)) and not m.player
	or (m.type == s.type)
	or (m.type == MT_METROIDPART or m.type == MT_METROIDBOSS or m.type == MT_METROIDSLASH)
		return false --
	end
	if not (s.target == m)
	and not (s.z > m.z+m.height) 
	and not (m.z+m.height < s.z)
		if s.target
			if G_GametypeHasTeams() and m.player and m.player.ctfteam and s.target.player and s.target.player.ctfteam
			and m.player.ctfteam == s.target.player.ctfteam
				--
			else
				s.samusshot = true
				P_DamageMobj(m, s, s.target, 1)
				P_KillMobj(s, m, m)
			end
		else --if not s.target
			if s.fuse
				s.fuse = min($,11)
			end
			s.samusshot = true
			P_DamageMobj(m, s, s, 1)
			P_KillMobj(s, m, m)
		end
	end
	return false --
end
addHook("MobjCollide", FireCollide, MT_MINIFIRE)
addHook("MobjMoveCollide", FireCollide, MT_MINIFIRE)

addHook("MobjThinker", function(s) if not s.valid return end --
	if not s.morning s.state = S_NULL return end --
	s.morning = $-1
	s.blendmode = AST_ADD
	local samuszng = P_RandomRange(1,3)	
	if (samuszng < 2)
		if (s.state == S_SAMZAP1)
			s.state = S_SAMZAP3
		elseif (s.state == S_SAMZAP2)
			s.state = S_SAMZAP1
		elseif (s.state == S_SAMZAP3)
			s.state = S_SAMZAP2
		elseif (s.state == S_SAMZAP4)
			s.state = S_SAMZAP2
		end
	elseif (samuszng == 2)
		if (s.state == S_SAMZAP1)
			s.state = S_SAMZAP4
		elseif (s.state == S_SAMZAP2)
			s.state = S_SAMZAP3
		elseif (s.state == S_SAMZAP3)
			s.state = S_SAMZAP1
		elseif (s.state == S_SAMZAP4)
			s.state = S_SAMZAP3
		end
	else
		if (s.state == S_SAMZAP1)
			s.state = S_SAMZAP2
		elseif (s.state == S_SAMZAP2)
			s.state = S_SAMZAP4
		elseif (s.state == S_SAMZAP3)
			s.state = S_SAMZAP4
		elseif (s.state == S_SAMZAP4)
			s.state = S_SAMZAP1
		end
	end
end, MT_SAMUSZAP)

addHook("MobjThinker", function(s) if not s.valid return end --
	if not s.color
		s.color = SKINCOLOR_RED
	end	
	--Setup
	s.samusshot = true
	s.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
	
	--While charge shot is flying	
	if (s.state == S_PLSHOT1) or (s.state == S_PLSHOT2)
		if not (s.CFversion and (leveltime%3))
			A_SAMPARTICLE(s, MT_MPR5, 7, 5, -2, 8, s.color, P_RandomRange(32355, 54355)+20000)			
		end
		local ghs = P_SpawnGhostMobj(s) --Afterimages
		ghs.blendmode = AST_ADD
		ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS			

		local groundcrash = (SlideBeam(s)) and true or false
		if groundcrash --Fancy groundcrashing firewaves
			local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
			ghs.angle = s.angle+ANGLE_90
			ghs.sprite = SPR_PHAZ
			ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.spriteyscale = FRACUNIT/2
			ghs.spritexscale = 85000
			ghs.color = s.color
			ghs.colorized = true
			ghs.tics = 20
			if leveltime % 2 == 0
				ghs.fuse = 10
				ghs.frame = K|FF_PAPERSPRITE
				ghs.scalespeed = $*P_RandomRange(1,3)
			else
				ghs.fuse = 18
				ghs.frame = J|FF_TRANS20|FF_PAPERSPRITE
				ghs.blendmode = AST_ADD
				ghs.scalespeed = $/2
			end
			ghs.destscale = $*99
		end

		if (s.state == S_PLSHOT1) and not (s.CFversion and (leveltime%2))
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPAND)
			if ghs
				ghs.scale = $*P_RandomRange(2,3)
				ghs.scalespeed = $*P_RandomRange(7, 11)
				ghs.destscale = $*25
				ghs.blendmode = AST_ADD
			end
		
			A_SAMPARTICLE(s, MT_MINIEXP, 15, 20, -10, 10, s.color, P_RandomRange(38355, 59355)*3)
	
			ghs = P_SpawnMobj(s.x+FixedMul(-400<<16, cos(s.angle)), s.y+FixedMul(-400<<16, sin (s.angle)), s.z-(s.momz*2), MT_PBEXPAND)
			if ghs
				ghs.blendmode = AST_ADD
				ghs.scale = $*P_RandomRange(1,2)
				ghs.scalespeed = $*P_RandomRange(2, 4)
				ghs.destscale = $*25
				ghs.blendmode = AST_ADD
			end
		end
	elseif (s.state == S_PLXP1) --The shot exploded!
		if not s.saldsalf
			SamFaceReflect(s, 110<<16)
			SamusBulletHole(s, s.scale*3, SKINCOLOR_RED, true)
			
			s.scale = s.scale*2
			MonitorBreaker(s, s.target, s.scale*2)
			A_SAMUSEXPLOSIONS(s, 2, MT_SAMMISSILESMOKE, false, 50000, SKINCOLOR_RED)
			A_SAMPARTICLE(s, MT_MPR5, 7, 4, -2, 8, s.color, 99355)
			if not s.CFversion
				A_SAMPARTICLE(s, MT_MPR5, 7, 4, -2, 8, s.color, 94355)
				A_SAMPARTICLE(s, MT_MPR5, 7, 4, -2, 8, s.color, 99999)
				A_SAMPARTICLE(s, MT_MPR5, 7, 4, -2, 8, s.color, 97955)
			end
			s.destscale = s.scale*30
			s.scalespeed = $*6
			s.flags = $|MF_NOCLIPHEIGHT|MF_NOCLIP
			P_SetObjectMomZ(s, -85355)
			s.saldsalf = true
			if not s.CFversion
				searchBlockmap("objects", function(ref, m)
					if (m.flags & MF_MONITOR) and m.health and (m.flags & MF_SHOOTABLE)
						if not (s.x > m.x+180<<16) and not (s.x < m.x-180<<16)
						and not (s.y > m.y+180<<16) and not (s.y < m.y-180<<16)
						and not (s.z > m.z+180<<16) and not (s.z < m.z-180<<16)		
							A_SAMITEM(s, m)
						end
					end
				end, s, s.x-(180<<16), s.x+(180<<16), s.y-(180<<16), s.y+(180<<16))	
			end
		end
	end
	
	if not s.plshottimer
		local t = s.target
		if t and t.crystalflashtime and s.plshottimer == nil
			s.CFversion = true
		end
		s.plshottimer = 17
	else
		if s.plshottimer == 1
			s.state = S_NULL return --
		end
		s.plshottimer = $-1
	end
end, MT_PLCHARGESHOT)

--Disintegrate players and enemies to dust.
local function plasmadustspawn(s, d)

	local rng = P_RandomRange(3,12)
	local dust = P_SpawnMobj(
	s.dtxloc+P_RandomRange(0, s.dtradius>>16)*3*s.dtscale, 
	s.dtyloc+P_RandomRange(0, s.dtradius>>16)*3*s.dtscale,
	s.dtzloc+P_RandomRange(0, s.dtheight>>16)*2*s.dtscale, MT_THOK)
	dust.sprite = SPR_MPR9
	dust.renderflags = $|RF_FULLBRIGHT
	dust.shadowscale = 6000
	dust.tics = 3+rng
	dust.blendmode = AST_ADD
	dust.scale = (s.dtscale*10/rng)
	dust.frame = W|(FF_TRANS10*(rng/3))
	dust.angle = s.dtangle+ANGLE_90
	
	if d
		P_Thrust(dust, (((ANG1*4)*4)*d), (rng*4)<<16)
		P_SetObjectMomZ(s, (rng*2)*s.dtscale, true)
	else
		P_Thrust(dust, dust.angle+(P_RandomRange(-40,40)*ANG1), rng<<16)
		P_SetObjectMomZ(s, (rng-3)*s.dtscale, true)
	end
	if s.formershell and s.formershell.valid			
		local husk = s.formershell
		husk.tics = 4
		if s.plasmadust
			husk.color = SKINCOLOR_PLASMABURNED					
			--Flamey back gfx
			if (husk.fuse > 35)
				if leveltime % 3 == 0
					local rng = P_RandomRange(1,10)
					local ghs = P_SpawnMobjFromMobj(husk, 0, 0, rng<<16, MT_THOK)
					ghs.sprite = SPR_MXP4
					ghs.frame = S|FF_TRANS30+((rng/2)<<16)|FF_FULLBRIGHT
					ghs.dispoffset = -3
					ghs.tics = rng+3
					ghs.fuse = ghs.tics-1
					ghs.blendmode = AST_ADD
					ghs.scale = (husk.scale/15)*rng
					if rng % 3 == 0
						ghs.color = SKINCOLOR_SUPERGOLD5
						ghs.colorized = true
					elseif rng % 2 == 0
						ghs.color = SKINCOLOR_CRIMSON
						ghs.colorized = true					
					end
					ghs.rollangle = rng*ANG30
					ghs.scalespeed = $*rng
					ghs.destscale = $*99
				end
			end
		else
			husk.color = (s.hyperdust) and SKINCOLOR_WHITE or SKINCOLOR_BEIGE					
		end
	end
	if s.plasmadust
		if leveltime % 7 == 0 or rng == 4
			dust.color = SKINCOLOR_SUPERGOLD4
		elseif leveltime % 13 == 0
			dust.color = SKINCOLOR_CRIMSON
		else
			dust.color = SKINCOLOR_PLASMABURNED
			dust.blendmode = 0
		end
	elseif s.hyperdust
		dust.color = SKINCOLOR_WHITE
		dust.blendmode = AST_ADD
	else
		dust.color = SKINCOLOR_BEIGE				
	end
end

addHook("MobjThinker", function(s) if not s.valid return end --
	local t = s.target
	if t and t.valid --While our target's still here....
		if t and t.valid and t.player
			if t.crystalflashanim
				if s.formershell and s.formershell.valid
					s.formershell.state = S_NULL
				end
				if s.valid --WAIT, STOP, SON
					t.flags = $ & ~(MF_NOGRAVITY|MF_NOCLIPTHING)
					s.state = S_NULL return --
				end
			elseif S_OriginPlaying(t)
				S_StopSound(t)
			end
		end	
		t.momx,t.momy,t.momz = 0,0,0
		t.sprite2 = SPR2_DEAD
		t.frame = ($ & ~FF_FRAMEMASK)|FF_FULLBRIGHT
		t.flags = $|MF_NOGRAVITY|MF_NOCLIPTHING
		t.flags2 = $|MF2_DONTDRAW
	end
	if s.dtframe != nil
		if s.formershell and s.formershell.valid // and s.dusttracker and (t.tics < 9)
			if s.trnset == nil
				s.trnset = 0
				s.dtexplodepushd = (P_RandomRange(0,1)) and 1 or -1
			end
			if s.dtexplodepush
				s.dtexplodepush = $+1
				s.formershell.color = FlashMobjC[P_RandomRange(1,5)]
				s.formershell.colorized = true
				s.formershell.frame = s.selectedframe or 0
			
				--Rolling!
				s.dtrollangle = s.dtrollangle and $+(ANG30*s.dtexplodepushd) or (ANG30*s.dtexplodepushd)
				if (leveltime%2)
					s.formershell.rollangle = s.dtrollangle
				end
				s.formershell.angle = s.dtrollangle
				
				if (s.dtexplodepush > 12)
					P_SetObjectMomZ(s.formershell, -FRACUNIT/2, true)
				end
				if P_IsObjectOnGround(s.formershell)
				 	if not s.waitatic
						s.waitatic = true
					elseif s.formershell.valid
						s.ghs = P_SpawnMobj(s.formershell.x, s.formershell.y, s.formershell.z, MT_SONIC3KBOSSEXPLODE)
						s.ghs.scale = s.formershell.scale*3
						S_StartSound(s.ghs, sfx_mtrdb)
						s.formershell.state = S_NULL
						s.state = S_NULL return --
					end
				end
			else
				s.formershell.frame = s.selectedframe|(s.trnset)|FF_FULLBRIGHT	
			end
			if s.superdisintegrate and (s.formershell.fuse > 82) and (s.formershell.fuse % 2 == 0)
				s.ghs3 = P_SpawnGhostMobj(s.formershell)
				s.ghs3.rollangle = P_RandomRange(1,359)*ANG1
				s.ghs3.color = SKINCOLOR_SUPERGOLD3
				s.ghs3.colorized = true
			end
			if not s.dtexplodepush and (s.formershell.fuse % 6 == 0) and not (s.trnset == FF_TRANS90)
				if not s.trnplus
					s.trnplus = true
				else
					if s.superdisintegrate and not s.scalespeeddoubled
						s.formershell.scalespeed = $*2
						s.scalespeeddoubled = true
					end				
				s.trnset = $+FRACUNIT
				end
			end
			s.dtxloc = s.formershell.x s.dtyloc = s.formershell.y s.dtzloc = s.formershell.z
			P_MoveOrigin(s, s.formershell.x, s.formershell.y, s.formershell.z)
			s.tics = s.formershell.tics
			s.fuse = s.formershell.fuse
			
			if not s.dtexplodepush --I mean, they're dead, right??
				if not s.firstdboom
					s.firstdboom = true
					for d = 1,45
						plasmadustspawn(s, d)
					end
				else
					plasmadustspawn(s)
				end
			end
		end
	end
end, MT_DUSTTRACKER)

addHook("MobjThinker", function(s) if not s.valid return end --
	s.samusshot = true
	s.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
	s.flags2 = $|MF2_RAILRING
	s.blendmode = AST_ADD
	if s.darkhyper
		s.color = (leveltime % 3 == 0) and SKINCOLOR_COBALT or SKINCOLOR_SKY
		s.colorized = true
	end	
	if s.truehyper
		if not s.truehyperspawn

			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_HBSHOT)
			ghs.target = s.target
			ghs.eflags = s.eflags ghs.flags2 = s.flags2 ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE ghs.thfuse = 40
			ghs.scale = s.scale ghs.angle = s.angle+(ANG2*1)
			ghs.momz = s.momz-10<<16
			P_Thrust(ghs, s.angle+(ANG2*1), FixedMul(ghs.info.speed, s.target.scale))

			ghs = P_SpawnMobj(s.x, s.y, s.z, MT_HBSHOT)
			ghs.target = s.target
			ghs.eflags = s.eflags ghs.flags2 = s.flags2 ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE ghs.thfuse = 40
			ghs.scale = s.scale ghs.angle = s.angle+(ANG2*3)
			ghs.momz = s.momz+10<<16
			P_Thrust(ghs, s.angle+(ANG2*3), FixedMul(ghs.info.speed, s.target.scale))

			ghs = P_SpawnMobj(s.x, s.y, s.z, MT_HBSHOT)
			ghs.target = s.target
			ghs.eflags = s.eflags ghs.flags2 = s.flags2 ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE ghs.thfuse = 40
			ghs.scale = s.scale ghs.angle = s.angle-(ANG2*3)
			ghs.momz = s.momz-10<<16
			P_Thrust(ghs, s.angle-(ANG2*3), FixedMul(ghs.info.speed, s.target.scale))

			ghs = P_SpawnMobj(s.x, s.y, s.z, MT_HBSHOT)
			ghs.target = s.target
			ghs.eflags = s.eflags ghs.flags2 = s.flags2 ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE ghs.thfuse = 40
			ghs.scale = s.scale ghs.angle = s.angle-(ANG2*5)
			ghs.momz = s.momz+10<<16
			P_Thrust(ghs, s.angle-(ANG2*5), FixedMul(ghs.info.speed, s.target.scale))

			s.truehyperspawn = true
		end
	end

	if s.thfuse
		s.thfuse = $-1
		if (s.thfuse == 36 or s.thfuse == 10) and not (s.flags & MF_BOUNCE)
		or (s.thfuse == 29 or s.thfuse == 17) and (s.flags & MF_BOUNCE)
			if s.target
				s.pwbomb2 = P_SpawnMobj(s.x, s.y, s.z, MT_SAMSUPERMISSILE)
				s.pwbomb2.target = s.target
				s.pwbomb2.smhyper = true
				if s.pwbomb2 and s.pwbomb2.health
					P_ExplodeMissile(s.pwbomb2)
				end
			end
		end
		if s.valid and s.thfuse == 1 and s.health
			s.momx,s.momy,s.momz = 0,0,0
			P_KillMobj(s) return --
		end
	end
	
	if (s.state == S_HBSHOT3) or (s.state == S_PLSHOT2) or (s.state == S_PLSHOT1)
		if (s.state == S_HBSHOT3) and not s.saldsalf2
			A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color,99355)
			A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color,99355)
			A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color,99355)
			A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color,99355)
			A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color,99355)
			A_SAMPARTICLE(s, MT_MPR5, 6, 5, -2, 6, s.color,99355)
			P_SpawnGhostMobj(s)
			s.saldsalf2 = true
		end		
		A_SAMPARTICLE(s, MT_MPR1, 9, 6, -2, 6, s.color, P_RandomRange(42355, 64355))
		if s.darkhyper
			local ghs = P_SpawnGhostMobj(s)
			ghs.blendmode = AST_ADD
			ghs.tics = 24
			ghs.fuse = 24
			ghs.color = P_RandomRange(SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERSILVER5)
			ghs.scale = $/P_RandomRange(1,2)
			ghs.scalespeed = $/P_RandomRange(2,8)
			ghs.destscale = s.scalespeed+1
		else
			local ghs = P_SpawnGhostMobj(s)
			ghs.blendmode = AST_ADD
			ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
		end


		if (leveltime % 2 == 0)
		
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPANDW)
			if ghs
				ghs.scale = $*P_RandomRange(1,3)
				ghs.blendmode = AST_ADD
				ghs.scalespeed = $*P_RandomRange(1, 8)
				ghs.destscale = $*20
				if s.darkhyper
					ghs.colorized = true
					ghs.color = SKINCOLOR_JET
				end
			end
			local ghs = P_SpawnMobj(s.x+FixedMul(-400<<16, cos(s.angle)), s.y+FixedMul(-400<<16, sin (s.angle)), s.z-(s.momz*2), MT_PBEXPAND)
			if ghs
				ghs.blendmode = AST_ADD
				ghs.scale = $*P_RandomRange(1,2)
				ghs.scalespeed = $*P_RandomRange(2, 4)
				ghs.destscale = $*25
				if s.darkhyper
					ghs.colorized = true
					ghs.color = SKINCOLOR_JET
				end				
			end
		else
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPANDI)
			if ghs
				ghs.blendmode = AST_ADD
				ghs.scale = $*P_RandomRange(1,3)
				ghs.scalespeed = $*P_RandomRange(3, 9)
				ghs.destscale = $*25
				if s.darkhyper
					ghs.colorized = true
					ghs.color = SKINCOLOR_SUPERSKY2
				end		
			end
		end
	elseif not s.saldsalf and (s.state == S_HBXP1) 
		s.saldsalf = true
		if s.wallclipped and s.target
			local t = s.target
			P_Thrust(t, t.angle, -9<<16)
			P_MoveOrigin(s, t.x, t.y, t.z+(t.height/2))
		end		
		
		SamFaceReflect(s, 500<<16)
		
		for i = -2,3
			local ghs
			if i < 0
				ghs = P_SpawnMobj(s.x, s.y, s.z, MT_THOK)
				ghs.flags = $ & ~MF_NOCLIPHEIGHT
			else
				ghs = P_SpawnMobj(s.x, s.y, s.z+(45*i)<<16, MT_THOK)
			end
			ghs.scale = s.scale/10
			ghs.tics = 24+(i*2)
			ghs.sprite = SPR_HBXP
			ghs.frame = E|FF_TRANS60|FF_FULLBRIGHT
			if i < 1
				ghs.scalespeed = $*(-2*(i))
			else
				ghs.momz = i*(4<<16)
				ghs.scalespeed = $/i
				ghs.frame = C|FF_TRANS80|FF_FULLBRIGHT
			end
			ghs.destscale = 99<<16
			ghs.color = P_RandomRange(SKINCOLOR_SUPERGOLD1, SKINCOLOR_SUPERPURPLE2)
		end
	
		s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_SAMMISSILELIGHT)
		s.missilelight.scale = s.scale/10
		s.missilelight.blendmode = AST_ADD
		s.missilelight.scalespeed = $*10/7
		s.missilelight.color = s.color
		s.missilelight.layers = 4
	
		if s.darkhyper
			S_StartSound(nil, sfx_bgxpld)
			S_StartSound(nil, sfx_smexp) S_StartSound(s, sfx_smexp)
			S_StartSound(nil, sfx_brakrx)
			P_StartQuake(80<<16, 28)
			for z in players.iterate
				if z.mo and z.mo.health
					if (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < 125<<16)
						P_DamageMobj(z.mo, s, s.target) --Don't get near this thing...
					end
				end
			end
		end			
	elseif not s.saldsalf3 and (s.state == S_HBXP5)
		A_SAMUSEXPLOSIONS(s, 28, MT_SAMMISSILESMOKE, false, 1)	
		if not s.darkhyper
			P_StartQuake(10<<16, 16)
		end
		s.destscale = s.scale*3
		s.scalespeed = $/2
		A_samquake(s, 33<<16, 23, 650<<16)
		for z in players.iterate
			if z.mo
				if (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < 650<<16)
					P_SamFP(z, PAL_RECYCLE, 4) --Ouch, too close to the flashing explosion.
				end
			end
		end
		if (s.flags & MF_BOUNCE)
			s.momx,s.momy,s.momz = 0,0,0
		end
		if s.truehyper and s.target
			s.pwbomb = P_SpawnMobj(s.x, s.y, s.z, MT_SAMPOWERBOMB)
			s.pwbomb.target = s.target
			s.pwbomb.thcolors = s
			if s.pwbomb and s.pwbomb.valid and s.pwbomb.health
				P_KillMobj(s.pwbomb)
			end
		end
		if not s.darkhyper
			if G_GametypeHasSpectators()
				A_Samuskillstuff(s, 550<<16, 375<<16, s.target, false, true)
			else
				A_Samuskillstuff(s, 650<<16, 450<<16, s.target, false, true)
			end
		end
		s.saldsalf3 = true
	end
	if s.valid and s.pwbomb and s.pwbomb.valid and s.pwbomb.health and s.target
		s.pwbomb.target = s.target
		P_ExplodeMissile(s.pwbomb)
	end
	if s.saldsalf
		if s.darkhyper
			LeafSpawn(s, nil, true, 550)
		else
			A_SAMPARTICLE(s, MT_MPR4, 45, 16, -1, 14, s.color, P_RandomRange(39355, 59355)+10000)
			if leveltime % 11 == 0
				if s.z > s.ceilingz-95<<16
				or s.z < s.floorz+95<<16
					local ghs = SamShinySplat(s,s.color, 20)
					ghs.frame = A|FF_TRANS50|FF_FULLBRIGHT
					ghs.scale = $*2 ghs.destscale = FRACUNIT*99
				end
			end
		end
	end
	if not s.darkhyper
		if s.wavebeamtimer or (s.wavebeamtimer == 0)
			if (s.wavebeamtimer > 16)
				s.color = SKINCOLOR_SKY
			elseif (s.wavebeamtimer > 14)
				s.color = SKINCOLOR_BLUE
			elseif (s.wavebeamtimer > 12)
				s.color = SKINCOLOR_MAGENTA
			elseif (s.wavebeamtimer > 10)
				s.color = SKINCOLOR_PINK
			elseif (s.wavebeamtimer > 8)
				s.color = SKINCOLOR_CLOUDY
			elseif (s.wavebeamtimer > 6)
				s.color = SKINCOLOR_GOLD
			elseif (s.wavebeamtimer > 4)
				s.color = 29
			elseif (s.wavebeamtimer > 2)
				s.color = 32
			else
				s.color = SKINCOLOR_EMERALD
			end
		end
		if not s.wavebeamtimer
			s.wavebeamtimer = 18
		else
			s.wavebeamtimer = $-1
		end
	else --if s.darkhyper
		LeafSpawn(s, nil, true, 450)
		s.color = (leveltime % 3 == 0) and SKINCOLOR_COBALT or SKINCOLOR_SKY
		s.colorized = true
	end
end, MT_HBSHOT)

local function SpiderGrow(s) --Spiderball grows other objects too that mapthingspawn fucks up with.
	if s.valid and not s.saldsalfy
		s.scale = FRACUNIT*5/2
		s.saldsalfy = true
		for m in mobjs.iterate(mobjs)
			if m and m.valid and not m.saldsalf
				if (m.type == MT_VRST) or (m.type == MT_GVST) or (m.type == MT_SATK)
				or (m.type == MT_MHBM) or (m.type == MT_CHBM) or (m.type == MT_SJMP)
					m.saldsalf = true
					if (m.type == MT_SJMP)
						m.scale = 43570
					else
						m.scale = FRACUNIT*5/2
					end
				end
			end
		end
	end
end

local function QuickGrow(s)
	if s.valid and not s.saldsalf
		s.scale = s.scale*5/2
		s.saldsalf = true
	end
end
addHook("MobjThinker", SpiderGrow, MT_SPDRBL)
addHook("MobjThinker", QuickGrow, MT_MHBM)
addHook("MobjThinker", QuickGrow, MT_GVST) --Welp, MobjSpawn has let me down, this is a shame....
addHook("MobjThinker", QuickGrow, MT_VRST)
addHook("MobjThinker", QuickGrow, MT_SATK)
addHook("MobjThinker", function(s)
	if not s.saldsalfy
		s.scale = s.scale*2
		s.saldsalfy = true
	end
end, MT_SPBL)
addHook("MobjThinker", function(s)
	if s.valid and not s.saldsalf
		s.scale = 43570
		s.saldsalf = true
	end
end, MT_SJMP)
addHook("MobjThinker", function(s)
	if s.valid and not s.saldsalf
		s.scale = s.scale*3
		s.saldsalf = true
	end
end, MT_CHBM)

addHook("MobjThinker", function(s) if not s.valid return end
	if (s.state == S_SAMEXPLODE21)
		if not s.color
			s.color = SKINCOLOR_BEIGE
		elseif (s.color == SKINCOLOR_VARIASUIT)
			s.tics = 1
		end
	end
end, MT_SAMEXPLODE2)

addHook("MobjThinker", function(s) if not s.valid return end
	s.samusshot = true
	if not s.sambombgrow
		s.scale = $*3
		s.sambombgrow = true
		s.shadowscale = FRACUNIT/5
	elseif (s.state == S_SAMMORPHBOMB5) and not s.saldsalf
		s.scale = $*2
		s.shadowscale = 0
		s.blendmode = AST_ADD		
		A_SAMUSEXPLOSIONS(s, 2, MT_SAMSHATTERFOF, false, 9000)
		if s.target --bomb floors below you. It just feels right this way.
			local sectorz = R_PointInSubsector(s.x, s.y).sector
			for fof in sectorz.ffloors()
				if (fof.flags & FF_EXISTS) and (fof.flags & (FF_STRONGBUST|FF_BUSTUP))
				and not (s.z-99<<16 >= fof.topheight)
				and not (s.z+99<<16+s.height < fof.bottomheight)
					EV_CrumbleChain(sectorz, fof)						
				end
			end
		end
		A_Samuskillstuff(s, 250<<16, 200<<16, s.target, false, false, true)
		s.saldsalf = true
		S_StartSound(s, sfx_mbbmbx)
		
		local ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_SAMAUTOFRAME)
		ghs.sprite = SPR_MBOM
		ghs.spritexscale,ghs.spriteyscale = 11000,11000	
		ghs.sttspeed = 2
		ghs.sttfade = 12
		ghs.tics = 15
		ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
		ghs.blendmode = AST_ADD
		ghs.frame = J|FF_FULLBRIGHT|FF_TRANS40
		ghs.destscale = $*99
	end
end, MT_SAMMORPHBOMB)

addHook("MobjThinker", function(s) if not s.valid return end --
	if not s.target
		s.state = S_NULL return --
	end
	if not s.sambombgrow
		s.scale = $*4
		s.shadowscale = 28000
		s.sambombgrow = true
		s.samusshot = true
		s.pwtimer = 13
	end
	if not s.saldsalf and (s.state == S_SAMMBOP8)
		s.scale = s.scale*2
		s.pwbomb = P_SpawnMobj(s.x, s.y, s.z, MT_SAMPOWERBOMB)
		s.pwbomb.target = s.target
		S_StartSound(s.pwbomb, sfx_pwbmb)
		s.saldsalf = true
	end
	if s.pwtimer
		if s.pwtimer == 1
			local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPANDW)
			ghs.blendmode = AST_ADD
			ghs.scale = $*P_RandomRange(1,3)
			ghs.scalespeed = $*P_RandomRange(1, 8)
			ghs.destscale = $*20
			
			ghs = P_SpawnMobj(s.x, s.y, s.z, MT_PBEXPAND)
			ghs.blendmode = AST_ADD
			ghs.scale = $*P_RandomRange(1,2)
			ghs.scalespeed = $*P_RandomRange(2, 4)
			ghs.destscale = $*25
		end
		s.pwtimer = $-1
	end
end, MT_SAMMBOP)

local function LineShatter(s, dist) --Used to make missile wall destruction feel more responsive.
	if not s.valid return end
	local line = {}
	searchBlockmap("lines", function(m, linedef)
		local x,y = P_ClosestPointOnLine(m.x, m.y, linedef)
		if not (R_PointToDist2(m.x, m.y, x, y) < dist) return end --return is "continue" in SearchBlockMaps
		table.insert(line, linedef)
	end, s, s.x-dist, s.x+dist, s.y-dist, s.y+dist)
	for i = 1, #line
		if line[i].valid
			local backfront = {line[i].frontsector, line[i].backsector}
			for d = 1, #backfront
				for fof in backfront[d].ffloors()
					if fof.valid and (fof.flags & FF_BUSTUP) and (fof.flags & FF_EXISTS)
						if ((abs(s.z-fof.topheight) <= dist) or (abs(s.z-fof.bottomheight) <= dist))
						and ((s.type == MT_SAMSUPERMISSILE) or not (fof.flags & FF_STRONGBUST))
							EV_CrumbleChain(nil, fof)
						end
            		end
        		end
			end
		end
	end
end

local function PowerCollide(s, m) if not s.valid return false end
	if m and m.player
		return false --
	end
end
addHook("MobjCollide", PowerCollide, MT_SAMMBOP)
addHook("MobjMoveCollide",PowerCollide, MT_SAMMBOP)
addHook("MobjCollide", PowerCollide, MT_SAMPOWERBOMB)
addHook("MobjMoveCollide", PowerCollide, MT_SAMPOWERBOMB)

addHook("MobjThinker", function(s) if not s.valid return end
	s.samusshot = true
	s.spritexscale,s.spriteyscale = 95000,95000
	
	if not ((s.state == S_SAMMISSILEE) or (s.state == S_SAMMISSILEE2))
	and not s.missiledisabled
		s.shadowscale = FRACUNIT
		s.sam_mtimer = s.sam_mtimer and $+1 or 1
		
		local t,p = s.target,s.target and s.target.player
		--Flashy line stuff! 1.3 is a bit rushed, so calculations are not 100% correct...
		if t and not t.crystalflashtime and p and not p.crystalflashtime
			if s.spindz == nil
				s.spindz = 30
				if s.spinaxisz == nil
					s.spinaxisz = 60
				end
			else
				s.spinaxisz = s.spinaxisz and $+s.spindz or 1
				if s.spinaxisz > 180
					s.spinaxisz = 180
					s.spindz = -30
				elseif s.spinaxisz < -180
					s.spindz = 30
					s.spinaxisz = -180
				end				
			end
		
			if s.spinaxis and s.spinaxis <= 150
				s.spinaxis = 150
			else
				s.spinaxis = s.spinaxis and $-15 or 301
			end
			
			--s is the missile
	--		s.verticalangle = R_PointToAngle2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), s.momz)
			s.verticalangle = R_PointToAngle2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), s.momz)
	--		R_PointToDist2(s.x, s.y, s.x+s.momx, t.y), ((t.z+(t.height/2)) - s.z)
			--Now spawn it correctly. You can assume the spinaxis is 40.
			local ang = leveltime*ANG10
			local ghs = P_SpawnMobj(
			s.x+FixedMul(s.spinaxis*s.scale, cos(ang)),
			s.y+FixedMul(s.spinaxis*s.scale, sin(ang)),
	 		s.z+(s.spinaxisz*s.scale),
			MT_SAMLIGHTLINE)
			ghs.tashu = p
			
			ghs = P_SpawnMobj(
			s.x+FixedMul(40*s.scale, cos(ang)),
			s.y+FixedMul(40*s.scale, sin(ang)),
			s.z+(s.scale*8),
			MT_SAMLIGHTLINE)
			
			if (leveltime%2==0)
				ghs.lvl2spawn = true
			end
			ghs.target = s
			ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.blendmode = AST_ADD
			ghs.scale = s.scale/9
			ghs.tics = 22
			ghs.frame = A|FF_TRANS70
			ghs.color = SKINCOLOR_WHITE		
			ghs.tashu = p
		end
		
		if (s.sam_mtimer > 8) and multiplayer --Missile racing sound.
			for z in players.iterate
				if SAM_displayplayer(z) and z.mo and z.mo.valid 
				and not S_SoundPlaying(s, sfx_msfrsz)				
				and not (z.mo == s.target) 
					local dist = FixedHypot(FixedHypot((s.x+s.momx)-z.mo.x, (s.y+s.momy)-z.mo.y), s.z-z.mo.z)
					if ((dist < 1000<<16) or (s.seekermissile and (dist < 2000<<16)))		
						S_StartSound(s, sfx_msfrsz)
					end
				end
			end
		end
		
		local ghs = P_SpawnMobj(
		s.x+FixedMul(-15<<16, cos(s.angle)), 
		s.y+FixedMul(-15<<16, sin(s.angle)), s.z, MT_SAMMISSILESMOKE)
		if ghs and ghs.valid
			ghs.destscale = $/2
			ghs.scalespeed = $/6
			if (s.sam_mtimer > 5) 
				ghs.colorized = true
				ghs.flags2 = $|MF2_SHADOW
				ghs.color = SKINCOLOR_SKY
				ghs.blendmode = AST_ADD	
				ghs.tics = $/2
			elseif P_RandomRange(0,1)
				ghs.frame = $|FF_TRANS70
			end
		end
			
	elseif (s.state == S_SAMMISSILEE) --Initial missile explosion effect
	
		if s.wallclipped and s.target
			local t = s.target
			P_Thrust(t, t.angle, -3<<16)
			P_MoveOrigin(s, t.x, t.y, t.z+(t.height/2))
		end
		
		SamFaceReflect(s, 210<<16)
		s.shadowscale = 0
	//	A_SAMUSEXPLOSIONS(s, 5, MT_BOSSEXPLODE, false, 90000, SKINCOLOR_SKY)
		A_SAMUSEXPLOSIONS(s, 8, MT_SAMSHATTERFOF, false, 9000)
	//	A_SAMUSEXPLOSIONS(s, 3, MT_SAMMISSILESMOKE, 8<<16, 180000, SKINCOLOR_SKY)

		local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_THOK)
		ghs.sprite = SPR_MXP4
		ghs.frame = Y|FF_FULLBRIGHT|FF_TRANS40
		P_SetObjectMomZ(ghs, FRACUNIT, true)
		ghs.blendmode = AST_ADD
		ghs.scale = s.scale/3
		ghs.tics = 39
		ghs.fuse = 20
		ghs.scalespeed = $*3
		ghs.destscale = $*99
		ghs.dispoffset = 3
	
		s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_SAMMISSILELIGHT)
		s.missilelight.scale = s.scale/10
		s.missilelight.blendmode = AST_ADD
		s.missilelight.color = SKINCOLOR_SUPERSILVER1
		s.missilelight.layers = 2
		LineShatter(s, 64<<16)
		
		if G_GametypeHasSpectators()
			A_Samuskillstuff(s, 268<<16, 145<<16, s.target, true)
		else
			A_Samuskillstuff(s, 310<<16, 185<<16, s.target, true)
		end
		
		--Splat to help with 3D explosion radius
		if s.z > s.ceilingz-70<<16
		or s.z < s.floorz+70<<16
			local ghs = SamShinySplat(s,SKINCOLOR_SKY, 16)
			ghs.frame = A|FF_TRANS70|FF_FULLBRIGHT
		end
		A_samquake(s, 9<<16, 9, 500<<16)
		
		S_StartSound(s, sfx_misxp2)
		s.state = S_SAMMISSILEE2
		
	elseif s.state == S_SAMMISSILEE2 
		if (s.tics > 18) and (leveltime % 4 == 0) --Explosion continously gives off light flicker, Prime 2 style.
		
			local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_THOK)
			ghs.sprite = SPR_MXP4
			ghs.frame = Y|FF_FULLBRIGHT|FF_TRANS10
			ghs.blendmode = AST_ADD
			ghs.scale = (s.scale*(9+(s.tics/6)))/P_RandomRange(4,11)
			ghs.rollangle = leveltime*ANG20
			P_SetObjectMomZ(ghs, -FRACUNIT, true)
			ghs.fuse = 8 ghs.tics = 99
			ghs.scalespeed = $*2
			ghs.destscale = $*99
			ghs.dispoffset = 3
		end
	end
end, MT_SAMMISSILE)

addHook("MobjThinker", function(s) if not s.valid return end
	if s.target and s.target.valid
	and (s.target.state != S_SAMMISSILEE) and (s.target.state != S_SAMSUPERMISSILEE)
		local t = s.target
	
		A_FaceTarget(s) --Always face missile for calculation purposes.
		
		local finang = leveltime*(ANG1*27)
			
		if not s.yuldorbspawned --Set this once.
			s.yuldorbspawned = true
			s.scalespeed = $/16
			s.destscale = $*2
		end
		
		
		if s.lvl2spawn
			P_MoveOrigin(s, t.x-t.momx+FixedMul(t.spinaxis*s.scale, cos(finang)), t.y-t.momy+FixedMul(t.spinaxis*s.scale, sin(finang)),
			t.z-t.momz+(t.height/2)+(t.spinaxisz*s.scale*-1) )
		else
			P_MoveOrigin(s, t.x-t.momx-FixedMul(t.spinaxis*s.scale, cos(finang)), t.y-t.momy-FixedMul(t.spinaxis*s.scale, sin(finang)),
			t.z-t.momz+(t.height/2)+(t.spinaxisz*s.scale) )
		end
		
		if (s.tics < 16) --Fading effect
			if not (s.frame & FF_TRANS90)
			and (s.tics % 2 == 0)
				s.frame = $+FRACUNIT
			end 
		end
				
		--Lightline! Spawn in relation to your last known x, since momx and momy don't really apply with teleportation.
		if s.valid and s.yuprevx != nil --Make sure there IS a comparison to be made.		
			local renderer
			if (t.player == consoleplayer)
				renderer = CV_FindVar("renderer").value
			end
			for d = 1,8
			
				local lightline = P_SpawnMobj(
				FixedMul((FRACUNIT-(6535*d)) , s.x)+FixedMul((6535*d) , s.yuprevx), --x position
				FixedMul((FRACUNIT-(6535*d)) , s.y)+FixedMul((6535*d) , s.yuprevy), --y position
				FixedMul((FRACUNIT-(6535*d)) , s.z)+FixedMul((6535*d) , s.yuprevz), --z position
				MT_THOK)
				lightline.blendmode = AST_ADD
				lightline.scale = s.scale/2
				lightline.scalespeed = $/12
				lightline.destscale = lightline.scalespeed+1
				lightline.color = s.color
				
				if renderer == 1
					lightline.frame = $|FF_FULLBRIGHT & ~FF_TRANSMASK
				else
					lightline.frame = $|FF_TRANS90|FF_FULLBRIGHT & ~FF_TRANS50
				end					
				if s.tashu and not SAM_displayplayer(s.tashu)
					lightline.flags2 = $|MF2_DONTDRAW
				end
			end
		end
		s.yuprevx,s.yuprevy,s.yuprevz = s.x,s.y,s.z --Where were we last?
		if s.tashu and not SAM_displayplayer(s.tashu)	
			s.flags2 = $|MF2_DONTDRAW
		end
		if s.yulddisengage --Are we told to fade away gracefully?
			if (leveltime % 8 == 0)
				if not (s.frame & FF_TRANS90)
					s.frame = $+FRACUNIT
				elseif s.valid
					s.state = S_NULL
				return
				end
			end
		end	
	elseif s.valid --No target. Bai, bish.
		s.state = S_NULL
	end
end, MT_SAMLIGHTLINE)

addHook("MobjThinker", function(s) if not s.valid return end
/* --Wave beam sparks
		if s.sparklight
			if not s.setup
			s.color = P_RandomRange(SKINCOLOR_SUPERGOLD1, SKINCOLOR_SUPERGOLD4)
			s.flags = MF_BOUNCE|MF_GRENADEBOUNCE
			s.frame = A|FF_TRANS20|FF_FULLBRIGHT
			s.setup = true
			end
			
			s.ghs = P_SpawnGhostMobj(s)
			s.ghs.tics = 14 s.ghs.fuse = 14
		return
		end */
--Main light
			
	if not s.setup
		s.setup = true
		s.frame = A|FF_TRANS90|FF_FULLBRIGHT
		s.tics = 13
		s.destscale = 999<<16
		s.blendmode = AST_ADD
		if not s.mlight2
			for d = 1,(s.layers or 2)
				s.mlight2 = P_SpawnMobj(s.x, s.y, s.z, MT_SAMMISSILELIGHT)
				local t = s.mlight2
				t.setup = true
				t.secondmlight = true
				t.scale = (s.scale/2)*d
				t.scalespeed = s.scalespeed+((s.scalespeed/3)*d)
				t.tics = 13+(s.layers or 2)
				t.destscale = 999<<16
				t.momz = t.scalespeed*30 --Otherwise it goes downwards for some reason
				t.sprite = SPR_OILF
				t.frame = A|FF_TRANS90|FF_FULLBRIGHT
				if s.crystalflashl or s.superlayered
					for z in players.iterate
						if z.sam_software and (z == consoleplayer)
							t.flags2 = $|MF2_DONTDRAW
							s.flags2 = $|MF2_DONTDRAW
						end
					end
				end					
				if s.crystalflashlt
					t.crystalflashlt = s.crystalflashlt
				end
				if s.tokenlight
					if P_RandomRange(0,10)
						t.colorized = true
						t.color = P_RandomRange(SKINCOLOR_SUPERSILVER1, SKINCOLOR_SUPERTAN5)
					end
				elseif s.crystalflashl					
					if d == 6 or not (d % 2 == 0)
						t.colorized = true
						t.color = SKINCOLOR_SUPERSILVER1
					else
						t.colorized = true
						t.color = SKINCOLOR_SUPERRED3
					end
				elseif s.layers == 2
					t.frame = A|FF_TRANS70|FF_FULLBRIGHT
					if d == 2
						t.colorized = true
						t.color = SKINCOLOR_SUPERSKY1
					end
				elseif s.layers == 4 and d == 4
					t.colorized = true
					t.color = SKINCOLOR_SUPERSKY3
				end
			end
		end
	else
		if s.crystalflashlt and s.crystalflashlt.valid
			P_MoveOrigin(s, s.crystalflashlt.x, s.crystalflashlt.y, s.crystalflashlt.z+s.crystalflashlt.height/2)
		end
		if s.tics == 4 and s.secondmlight
			s.frame = A|FF_TRANS90|FF_FULLBRIGHT
		end
	end
end, MT_SAMMISSILELIGHT)

local function FofShattering(s) if not s.valid return end
	local sector = R_PointInSubsector(s.x, s.y).sector
	shatterfof(s, sector)
	if ( R_PointInSubsector(s.x+(s.momx/2), s.y+(s.momy/2)).sector != sector )
		sector = R_PointInSubsector(s.x+(s.momx/2), s.y + (s.momy/2)).sector
		shatterfof(s, sector)
	end
end
addHook("MobjThinker", FofShattering, MT_SAMEXPLODE1)
addHook("MobjThinker", FofShattering, MT_SAMSHATTERFOF)

addHook("MobjThinker", function(s) if not s.valid return end
	s.samusshot = true
	s.spriteyscale = FRACUNIT*2
	s.spritexscale = s.spriteyscale
	if s.darkhyper --Phazon Missile
		LeafSpawn(s, nil, true, 200)		
		s.color = (leveltime%3==0) and SKINCOLOR_COBALT or SKINCOLOR_SKY
		s.colorized = true
	end	
	if s.stimer == nil
		s.stimer = 1
	elseif s.stimer
		s.stimer = $+1
	end
	if (s.state == S_SAMSUPERMISSILE1) and not s.missiledisabled
		s.shadowscale = FRACUNIT
		if multiplayer
			--Super Missile racing sound.
			for z in players.iterate
				if SAM_displayplayer(z) and z.mo and z.mo.valid and not (z.mo == s.target)
					if not S_SoundPlaying(s, sfx_smsh)
						S_StartSound(s, sfx_smsh)
					end
					if not S_SoundPlaying(s, sfx_msfrsz) and (s.stimer >= 5)				
						if (FixedHypot(FixedHypot((s.x+s.momx)-z.mo.x, (s.y+s.momy)-z.mo.y), s.z-z.mo.z) < 2000<<16)
							S_StartSound(s, sfx_msfrsz)	
							S_StartSound(s, sfx_msfrsz)
						end
					end
				end
			end
		end
		if (s.stimer >= 5)
			s.ghs = P_SpawnMobj(s.x+FixedMul(-15<<16, cos(s.angle)), s.y+FixedMul(-15<<16, sin (s.angle)), s.z, MT_SAMMISSILESMOKE)
			if s.ghs and s.ghs.valid and (leveltime % 2 == 0)
				s.ghs.blendmode = AST_ADD
			end	
			if (s.stimer > 16)
				P_SpawnMobj(s.x+FixedMul(-52<<16, cos(s.angle)), s.y+FixedMul(-52<<16, sin (s.angle)), s.z, MT_SAMMISSILESMOKE)
				s.ghs = P_SpawnMobj(s.x+FixedMul(-15<<16, cos(s.angle)), s.y+FixedMul(-15<<16, sin (s.angle)), s.z, MT_SAMMISSILESMOKE)
				if s.ghs and s.ghs.valid
					s.ghs.blendmode = AST_ADD
				end
			end
		end
		
		s.momx,s.momy,s.momz = $*25/24,$*25/24,$*25/24 --Gradually speed up
		
		local t = s.target local p = t and t.player
		if p
			if s.spindz == nil
				s.spindz = 30
				if s.spinaxisz == nil
					s.spinaxisz = 90
				end
			else
				s.spinaxisz = s.spinaxisz and $+s.spindz or 1
				if s.spinaxisz > 180
					s.spinaxisz = 180
					s.spindz = -30
				elseif s.spinaxisz < -180
					s.spindz = 30
					s.spinaxisz = -180
				end
			end
			if s.spinaxis and s.spinaxis <= 150
				s.spinaxis = 150
			else
				s.spinaxis = s.spinaxis and $-15 or 301
			end	
			
			s.verticalangle = R_PointToAngle2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), s.momz)
			local ang = leveltime*ANG10
			local ghs = P_SpawnMobj(
			s.x+FixedMul(s.spinaxis*s.scale, cos(ang)),
			s.y+FixedMul(s.spinaxis*s.scale, sin(ang)),
			s.z+(s.spinaxisz*s.scale),
			MT_SAMLIGHTLINE)
			ghs.tashu = p
			
			local ang = leveltime*ANG10	
			local ghs = P_SpawnMobj(
			s.x+FixedMul(40*s.scale, cos(ang)),
			s.y+FixedMul(40*s.scale, sin(ang)),
			s.z+(s.scale*8),
			MT_SAMLIGHTLINE)
			if leveltime % 2 == 0
				ghs.lvl2spawn = true
			end
			ghs.target = s
			ghs.scale = s.scale/9
			ghs.blendmode = AST_ADD
			ghs.tics = 22
			ghs.frame = A|FF_FULLBRIGHT|FF_TRANS50
			ghs.color = SKINCOLOR_SUPERGOLD5
			ghs.tashu = p
		end

	elseif (s.state == S_SAMSUPERMISSILEE)
		if s.wallclipped and s.target
			local t = s.target
			P_Thrust(t, t.angle, -9<<16)
			P_MoveOrigin(s, t.x, t.y, t.z+(t.height/2))
		end		
		s.shadowscale = 0
		A_SAMUSEXPLOSIONS(s, 5, MT_SAMEXPLODE1, 5<<16, 144000, true)
		A_SAMUSEXPLOSIONS(s, 7, MT_SAMMISSILESMOKE, 50<<16, 650000)
		A_SAMUSEXPLOSIONS(s, 12, MT_SAMEXPLODE1, false, 1001, true)
		A_SAMUSEXPLOSIONS(s, 20, MT_SAMMISSILESMOKE, false, 9001)
		
		s.missilelight = P_SpawnMobj(s.x, s.y, s.z+s.height/2, MT_SAMMISSILELIGHT)
		s.missilelight.scale = s.scale/4
		s.missilelight.scalespeed = $*10/7
		s.missilelight.color = SKINCOLOR_SUPERSILVER1
		s.missilelight.layers = 6
		
		local ghs
		--Splat to help with 3D explosion radius
		if s.z > s.ceilingz-70<<16
		or s.z < s.floorz+70<<16
			ghs = SamShinySplat(s, SKINCOLOR_RED, 16)
			ghs.frame = A|FF_TRANS40|FF_FULLBRIGHT
			ghs.scale = $*2
			ghs.destscale = $*99
			ghs.scalespeed = $*3
		end
		for d = 1, 29
			ghs = P_SpawnMobj(
			s.x + FixedMul((100 + d*7 * s.scale), cos(s.angle)),
			s.y + FixedMul((100 + d*7 * s.scale), sin(s.angle)),
			s.z + (d * 3 * s.scale), MT_THOK
			)
			ghs.eflags = s.eflags
			ghs.sprite = SPR_MPR9
			P_SetObjectMomZ(ghs, (30 - d) << 16)
		
			ghs.frame = (d%2==0) and (V|FF_TRANS40|FF_FULLBRIGHT) or (W|FF_TRANS10|FF_FULLBRIGHT)
			ghs.scale = (d%2==0) and (d*2) or (d*3)
			ghs.color = (d%2==0) and SKINCOLOR_RED or SKINCOLOR_SUPERGOLD3
		
			ghs.rollangle = d*ANG20
			ghs.blendmode = AST_ADD
			ghs.destscale = d*99
			ghs.fuse = 8+d
			ghs.tics = 99
		end
		
		for d = 1, 16
			ghs = P_SpawnMobjFromMobj(s,0,0,0,MT_THOK)
			ghs.sprite = SPR_PHAZ
			ghs.spriteyscale,ghs.spritexscale = FRACUNIT,95000
			ghs.renderflags,ghs.blendmode = RF_FULLBRIGHT|RF_NOCOLORMAPS|RF_PAPERSPRITE, AST_ADD
			P_SetObjectMomZ(ghs, 5<<16)
			P_InstaThrust(ghs, ANGLE_22h*d, 36<<16)
			ghs.angle = R_PointToAngle2(ghs.x, ghs.y,ghs.x+ghs.momx, ghs.y+ghs.momy)+ANGLE_90
			ghs.tics = 99
			ghs.fuse = (d%2) and 15 or 21
			ghs.frame = (d%2) and K|FF_TRANS60 or J|FF_TRANS70
			ghs.scalespeed = (d%2) and d*P_RandomRange(1, 3) or d/2
			ghs.color = (d%2) and SKINCOLOR_SUPERORANGE5 or SKINCOLOR_RED
			ghs.colorized = true
			ghs.destscale = 99<<16
		end

		SamFaceReflect(s, 500<<16)
		LineShatter(s, 90<<16)
	
		if not s.darkhyper
			if G_GametypeHasSpectators()
				A_Samuskillstuff(s, 520<<16, 325<<16, s.target, false, true)
			else
				A_Samuskillstuff(s, 750<<16, 500<<16, s.target, false, true)
			end
		end
		A_samquake(s, 14<<16, 13, 3000<<16)
		for z in players.iterate
			if z.mo
				if (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < 3000<<16)
				or (s.target and z.mo == s.target) --May as well always let the shooter know if it hit.
					if s.darkhyper and (FixedHypot(FixedHypot(s.x-z.mo.x, s.y-z.mo.y), s.z-z.mo.z) < 235<<16)
						P_DamageMobj(z.mo, s, s.target) --Big explosion, dodge, Samus!
					end
				end
			end
		end
		S_StartSound(s, sfx_smexp)
		s.state = S_SAMEXPLODE11
	end
end, MT_SAMSUPERMISSILE)

addHook("MobjThinker", function(p) if not p.valid return end
	if p.target and p.target.player
		local t = p.target
		if p.srdcr == nil
			p.srdcr = 1
			p.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
		end
		if p.gravitysuitjustgot
			P_MoveOrigin(p, t.x+FixedMul(-2<<16, cos(t.angle)), t.y+FixedMul(-2<<16, sin (t.angle)), t.z)
		elseif (p.state >= S_SAMPOWERBOMB2) and (p.state < S_SAMPOWERBOMB5)
			WindStorm(p)		
		end
		if p.state == S_SAMPOWERBOMB1
		
			if not p.gravitysuitjustgot
				S_StartSound(p, sfx_smexp)
				SamFaceReflect(p, 900<<16)
			end 
			S_StartSound(p, sfx_pwbmb)		
			p.scale = FRACUNIT*10
			p.flags2 = $|MF2_EXPLOSION
			p.color = SKINCOLOR_YELLOW
			
			--Splat to help with 3D explosion radius

			local ghs = SamShinySplat(p,SKINCOLOR_SUPERGOLD5, 66)
			ghs.frame = A|FF_TRANS20|FF_FULLBRIGHT
			ghs.scale = $/2
			ghs.destscale = $*99
			ghs.scalespeed = $*2
			
			if G_GametypeHasSpectators() 
				if not p.gravitysuitjustgot
					A_Samuskillstuff(p, 420<<16, 340<<16, t, false, true)
				end
			else
				A_Samuskillstuff(p, 500<<16, 400<<16, t, false, true)
			end
			p.missilelight = P_SpawnMobj(p.x, p.y, p.z+p.height, MT_SAMMISSILELIGHT)
			p.missilelight.scale = FRACUNIT/30
			p.missilelight.color = SKINCOLOR_SUPERSILVER1
			p.missilelight.layers = 8
			P_StartQuake(18<<16, 10)
			
		elseif p.state == S_SAMPOWERBOMB1A
			p.scale = p.scale+12001
			p.blendmode = AST_ADD
			if not p.phase
				p.scale = FRACUNIT
				p.phase = 1
				for z in players.iterate
					if p.gravitysuitjustgot and z.mo and p.target == z.mo
						if (z.sam_gravitysuit == 1)
							if z.customsuitc2 and not (z.customsuitc2 > #skincolors - 1)
								z.mo.sam_flashfade = 35
								z.mo.sam_flashfadecolor = p.customsuitc2
							end	
						else
							if z.customsuitc3 and not (z.customsuitc3 > #skincolors - 1)
								z.mo.sam_flashfade = 35
								z.mo.sam_flashfadecolor = z.customsuitc3		
							end
						end				
					elseif z.mo and (FixedHypot(FixedHypot(z.mo.x-p.x, z.mo.y-p.y), z.mo.z-p.z) <= 1150<<16)
						P_SamFP(z, PAL_MIXUP, 6)
						z.mo.sam_flashfade = 40
						z.mo.sam_flashfadecolor = SKINCOLOR_SUPERGOLD5
					end
				end
				A_SAMUSEXPLOSIONS(p, 20, MT_SPARK, 65<<16, 6000)
				if not p.gravitysuitjustgot
					A_SAMUSEXPLOSIONS(p, 10, MT_IVSP, 75<<16, 199000)
					A_SAMUSEXPLOSIONS(p, 17, MT_IVSP, 5<<16, 900)
					A_SAMUSEXPLOSIONS(p, 8, MT_SAMMISSILESMOKE, 90<<16, 192500)
					A_SAMUSEXPLOSIONS(p, 2, MT_EXPLODE, 71<<16, 90)
					A_SAMUSEXPLOSIONS(p, 5, MT_SAMSHATTERFOF, false, 9000, true)
					A_SAMUSEXPLOSIONS(p, 4, MT_BOSSEXPLODE, 38<<16, 292500)
					A_SAMUSEXPLOSIONS(p, 8, MT_SAMEXPLODE1, false, 1, true)
				end
				
				local ghs = P_SpawnMobjFromMobj(p, 0, 0, 0, MT_SAMAUTOFRAME)
				ghs.sprite = SPR_MBOM
				ghs.scale = FRACUNIT*4
				ghs.colorized = true
				ghs.spriteyscale = 12000
				ghs.spritexscale = 12000	
				ghs.sttspeed = 12
				ghs.sttfade = 15
				ghs.tics = 80
				ghs.color = SKINCOLOR_ORANGE
				ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.blendmode = AST_ADD
				ghs.frame = J|FF_TRANS40
				ghs.destscale = $*99
				ghs.scalespeed = $*5
			end
			
		elseif p.state == S_SAMPOWERBOMB2
			p.scale = p.scale+15500
			
			if p.phasetim == nil
				p.phasetim = 8
			else
				if p.phasetim == 1
					A_SAMUSEXPLOSIONS(p, 18, MT_SPARK, 5<<16, 100)
					A_SAMUSEXPLOSIONS(p, 23, MT_SPARK, 30<<16, 8000)
					A_SAMUSEXPLOSIONS(p, 16, MT_SPARK, 54<<16, 15000)
					A_SAMUSEXPLOSIONS(p, 12, MT_SPARK, 67<<16, 20000)
				end
				p.phasetim = $-1
			end
			if not (p.phase and p.phase >= 2)
				P_StartQuake(6<<16, 35)
				p.color = SKINCOLOR_YELLOW
				if G_GametypeHasSpectators() 
					if not p.gravitysuitjustgot
						p.phase = 2
						A_Samuskillstuff(p, 750<<16, 480<<16, t, false, true)
					end
				else
					p.phase = 2
					A_Samuskillstuff(p, 800<<16, 700<<16, t, false, true)
				end
			end	
			
		elseif p.state == S_SAMPOWERBOMB3
			p.color = (p.thcolors) and SKINCOLOR_BLUE or SKINCOLOR_SUPERSILVER5
			p.scale = p.scale+29000
			if G_GametypeHasSpectators() 
				for z in players.iterate
					if z.mo and z.mo != t and (FixedHypot(FixedHypot(z.mo.x-p.x, z.mo.y-p.y), z.mo.z-p.z) <= 3900<<16)
						if not (G_GametypeHasTeams() and t.player.ctfteam == z.mo.player.ctfteam)
							P_Thrust(z.mo, R_PointToAngle2(p.x, p.y, z.mo.x, z.mo.y), 3<<16)
						end
					end
				end
			end			
			if not (p.phase and p.phase >= 3)
				A_SAMUSEXPLOSIONS(p, 19, MT_SPARK, 120<<16, 5500)
				A_SAMUSEXPLOSIONS(p, 28, MT_SPARK, 20<<16, 20)
				if not p.gravitysuitjustgot
					A_SAMUSEXPLOSIONS(p, 25, MT_IVSP, 45<<16, 15000)
					A_SAMUSEXPLOSIONS(p, 10, MT_BOSSEXPLODE, 98<<16, 100)
					A_SAMUSEXPLOSIONS(p, 10, MT_SAMSHATTERFOF, false, 9000, true)
					A_SAMUSEXPLOSIONS(p, 14, MT_SAMMISSILESMOKE, 75<<16, 100)
					A_SAMUSEXPLOSIONS(p, 14, MT_SAMEXPLODE1, false, 7000, true)
				end
				p.phase = 3
			
				local ghs = P_SpawnMobjFromMobj(p, 0, 0, 0, MT_SAMAUTOFRAME)
				ghs.sprite = SPR_MBOM
				ghs.scale = FRACUNIT*5
				ghs.spritexscale,ghs.spriteyscale = 24000,24000
				ghs.sttspeed = 6
				ghs.sttfade = 15
				ghs.tics = 40
				ghs.color = SKINCOLOR_RED
				ghs.colorized = true
				ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.blendmode = AST_ADD
				ghs.frame = J|FF_TRANS80
				ghs.destscale = $*99
				ghs.scalespeed = $*5
				
				for d = 1,16
					local ghs = P_SpawnMobjFromMobj(p, 0,0,0, MT_THOK)
					ghs.sprite = SPR_PHAZ
					ghs.spriteyscale = FRACUNIT
					ghs.spritexscale = 95000
					ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
					ghs.blendmode = AST_ADD
					ghs.colorized = true
					ghs.tics = 99
					P_SetObjectMomZ(ghs, 85356)
					P_InstaThrust(ghs, (ANGLE_45/2)*d, 65<<16)
					ghs.angle = R_PointToAngle2(ghs.x, ghs.y, ghs.x+ghs.momx, ghs.y+ghs.momy)+ANGLE_90
					if d % 2 == 0
						ghs.fuse = 20
						ghs.frame = K|FF_TRANS20|FF_PAPERSPRITE|FF_FULLBRIGHT
						ghs.scalespeed = $*P_RandomRange(1,3)
						ghs.color = SKINCOLOR_SUPERGOLD3
					else
					
						ghs.fuse = 28
						ghs.frame = J|FF_TRANS40|FF_PAPERSPRITE|FF_FULLBRIGHT
						ghs.scalespeed = $/2
						ghs.color = SKINCOLOR_SUPERGOLD5
						end
					ghs.scalespeed = $*2
					ghs.destscale = $*99
				end
			
			end
			if leveltime % 2 == 0
				for d = 1,729,43
					local ghs = P_SpawnMobj(
					p.x+FixedMul(((10+d)<<16),cos(d*(ANG1+9909))),
					p.y+FixedMul(((10+d)<<16),sin(d*(ANG1+9909))),
					p.z, MT_THOK)
					
					ghs.eflags = p.eflags
					ghs.flags = $|MF_BOUNCE|MF_GRENADEBOUNCE & ~MF_NOCLIPHEIGHT
					ghs.sprite = SPR_MPR9
					local rng = P_RandomRange(-30,30)*ANG1
					P_SetObjectMomZ(ghs, d*3000)
					P_InstaThrust(ghs, R_PointToAngle2(p.x, p.y, ghs.x, ghs.y)+rng, (d/20)<<16)
					if d % 2 == 0
						ghs.frame = V|FF_TRANS60|FF_FULLBRIGHT
						ghs.scale = $*2
						ghs.color = SKINCOLOR_SUPERGOLD3
					else
						ghs.frame = W|FF_TRANS20|FF_FULLBRIGHT
						ghs.scale = $*3
						ghs.color = SKINCOLOR_SUPERSKY3
					end
					ghs.rollangle = d*ANG2
					ghs.blendmode = AST_ADD
					ghs.destscale = $*99
					ghs.fuse = 5+(d/20)
					ghs.tics = 99
				end
			end	
		elseif p.state == S_SAMPOWERBOMB4

			p.color = (p.thcolors) and SKINCOLOR_SUPERGOLD5 or SKINCOLOR_SUPERSILVER5
			p.scale = p.scale+44500

			if not (p.phase and p.phase >= 4)
				if G_GametypeHasSpectators() 
					if not p.gravitysuitjustgot
						A_Samuskillstuff(p, 1830<<16, 1150<<16, t, false, true)
					end
				else
					A_Samuskillstuff(p, 2250<<16, 1300<<16, t, false, true)
				end
				p.phase = 4
			end
			if not p.gravitysuitjustgot
				SamFaceReflect(p, 950<<16)
				if G_GametypeHasSpectators() 
					for z in players.iterate
						if z.mo and z.mo != t and (FixedHypot(FixedHypot(z.mo.x-p.x, z.mo.y-p.y), z.mo.z-p.z) <= 2300<<16)
							if not (G_GametypeHasTeams() and t.player.ctfteam == z.mo.player.ctfteam)
								P_Thrust(z.mo, R_PointToAngle2(p.x, p.y, z.mo.x, z.mo.y), FRACUNIT)
							end
						end
					end
				end
			end

		elseif p.state == S_SAMPOWERBOMB5
		
			p.color = (p.thcolors) and SKINCOLOR_SUPERGOLD5 or SKINCOLOR_SUPERSILVER5
			p.phase = 6
			p.scale = p.scale+27000
			
		elseif p.state == S_SAMPOWERBOMB6
			p.scale = p.scale+16000
		end
	end
end, MT_SAMPOWERBOMB)

addHook("MobjThinker", function(s) if not s.valid return end --
	if (P_CheckDeathPitCollide(s)) or s.samptimer == 1
		s.state = S_NULL return --
	end
	if not s.samptimer
		s.samptimer = (s.spazersummon) and P_RandomRange(6, 18) or P_RandomRange(10, 50)
	else
		s.samptimer = $-1
	end
end, MT_MPR1)

/*addHook("MobjThinker", function(s)
	if P_CheckDeathPitCollide(s)
		s.state = S_NULL return --
	end
end, MT_MPR4)*/

addHook("MobjThinker", function(s) if not s.valid return end --
	if (P_CheckDeathPitCollide(s)) or s.samptimer == 1
		s.state = S_NULL return --
	end
	if not s.samptimer
		s.samptimer = P_RandomRange(110, 150)
	else
		s.samptimer = $-1
	end
	if abs(s.momx)+abs(s.momy) < 2<<16
		s.tics = $+1	
	end
end, MT_MPR2)

addHook("MobjThinker", function(s) if not s.valid return end
	if  (P_CheckDeathPitCollide(s)) or s.samptimer == 1
		s.state = S_NULL return --	
	end
	if not s.samptimer
		s.samptimer = P_RandomRange(110, 150)
	else
		s.samptimer = $-1
	end
	if abs(s.momx)+abs(s.momy) < 25250
		s.tics = $+1	
	end
end, MT_MPR3)

addHook("MobjThinker", function(s) if not s.valid return end
	if (P_CheckDeathPitCollide(s)) or s.samptimer == 1
		s.state = S_NULL return --	
	end
	if not s.samptimer
		s.samptimer = P_RandomRange(18, 100)
	else
		s.samptimer = $-1
	end
end, MT_MPR5)

addHook("MobjThinker", function(s) if not s.valid return end
	if gamemap == 25
		if (SAMUSCAMPAIGN == true)
			s.flags2 = $|MF2_DONTDRAW
			if s.tracer
				s.tracer.flags2 = $|MF2_DONTDRAW
			end
		end
	end
end, MT_METALSONIC_RACE)

//Samus' Lights thinker. But switch to custom lights for SAMP sprites!
addHook("MobjThinker", function(s) if not s.valid return end
	local t = s.tracer --Not target!
	if t and t.valid and t.player
		if (t.sprite == SPR_SAMU and t.frame != 0)
			s.flags2 = $|MF2_DONTDRAW
		else
			if (t.sprite != SPR_PLAY) // or not t.player.sam_gravitysuit
				s.flags2 = $|MF2_DONTDRAW return --
			elseif (s.flags2 & MF2_DONTDRAW)
				s.flags2 = $ & ~MF2_DONTDRAW --	
			end
			s.tics = 3
			s.angle = t.player.drawangle
			s.eflags = t.eflags
			s.mirrored = t.mirrored
			s.skin = "samuslights"
			s.sprite = t.sprite
			s.sprite2 = t.sprite2
			s.frame = t.frame
			s.scale = t.scale
			s.spritexscale = t.spritexscale
			s.spriteyscale = t.spriteyscale
			s.color = SKINCOLOR_SUPERSILVER1
			s.rollangle = t.rollangle
		end
	end
end, MT_SAMUSLIGHTS)

addHook("MobjThinker", function(s) if not s.valid return end
	local t = s.target 
	if not (t and t.valid and YouAreSamus(t) and t.player and t.health)
		s.state = S_NULL return --
	end local p = t.player
	
	if P_IsObjectOnGround(s) --The OBJECT must be on the ground, not the actual player!
	and not p.sammorphed --Morphed Samus can't do anything with this.
	and not (p.sam_screwattacking or t.sam_screwattackfling)
	and not p.powers[pw_nocontrol] 
	and p.sam_power_grip --Just making sure...

		if (t.eflags & MFE_VERTICALFLIP)
		and ((t.ceilingz+40<<16) > s.ceilingz)
		and (t.z+24<<16 > s.z)
		and (t.floorz < (s.ceilingz-20<<16))
		and (t.z < t.ceilingz+40<<16) 
		
		or ((t.floorz-40<<16) < s.floorz)
		and (t.z-24<<16 < s.z)  
		and (t.ceilingz > (s.floorz+20<<16)) 
		and (t.z > t.floorz+40<<16) 
		
			local fofy = false
			if s.subsector and s.subsector.sector 
				for fof in s.subsector.sector.ffloors()
					if (fof.flags & FF_EXISTS)
						if ((fof.flags & FF_BLOCKOTHERS) and not (fof.flags & FF_BLOCKPLAYER))
						and (t.floorz < fof.topheight)
							if not (t.z+5*t.scale > fof.topheight)
								if not (t.eflags & MFE_VERTICALFLIP)
								and not (fof.topheight > t.z+t.height+(230*t.scale))
									return
								end
							end
						end
					end
					fofy = true
				end
			end
			if (p.samspbscharge > 125)
				t.sam_ldspeed = 80<<16
			else
				t.sam_ldspeed = min(80<<16, max(abs(t.momx)+abs(t.momy), 8<<16))
			end				
			
			t.momx,t.momy,t.momz = 0,0,0
			t.z = (t.eflags & MFE_VERTICALFLIP) and s.z+10<<16 or s.z-56<<16
			
			S_StopSoundByID(s, sfx_sjmp)
			
			t.state = S_PLAY_RIDE
			t.spriteyoffset = -6<<16
			t.spriteyscale = 72355
			t.sam_geton = 0
			A_samquake(s, 30<<16, 2, 1)
			
			CancelScrewAttack(t,p)
			p.sams_jumpcd,p.sams_morphcd,p.sams_screwattackcd = 6,6,6
			p.sam_spacejumped = true
			
			t.sam_ldclmb = 30
			p.aiming = 1901<<16+3
			S_StartSound(s, sfx_samclb)
			
			t.sam_ldforce = 15<<16
			
			local pmomz = 0
			if s.pmomz and (s.pmomz*P_MobjFlip(t) > 1)
				pmomz = s.pmomz
				pmomz = (pmomz<0) and $/-2 or $

				t.sam_ldforce = min($+(pmomz+FRACUNIT), 10<<16)
				t.momz = (pmomz+FRACUNIT)
			elseif t.pmomz  and (t.pmomz*P_MobjFlip(t) > 1)
				pmomz = t.pmomz
				pmomz = (pmomz<0) and $/-2 or $
				t.sam_ldforce = min($+(pmomz+FRACUNIT), 10<<16)
				t.momz = (pmomz+FRACUNIT)
			end					
			
			if not (fofy and (s.subsector == t.subsector))
				t.angle = R_PointToAngle2(t.x, t.y, s.x, s.y)
				t.sam_ledgeupangle = t.angle
			end
			p.powers[pw_nocontrol] = max($,2)
			p.pflags = $|PF_JUMPED|PF_FULLSTASIS & ~(PF_THOKKED|PF_SPINNING|PF_STARTJUMP|PF_STARTDASH)
		end
	end
end, MT_PWGRPLD)

--Okay! No way around it, then!
local function AddSamusShot(s) if not s.valid return end
	s.samusshot = true
end
addHook("MobjSpawn", AddSamusShot, MT_PBCHARGESHOT)
addHook("MobjSpawn", AddSamusShot, MT_SPCHARGESHOT)
addHook("MobjSpawn", AddSamusShot, MT_WVCHARGESHOT)
addHook("MobjSpawn", AddSamusShot, MT_ICCHARGESHOT)
addHook("MobjSpawn", AddSamusShot, MT_PLCHARGESHOT)

addHook("MobjSpawn", AddSamusShot, MT_SAMMISSILE)
addHook("MobjSpawn", AddSamusShot, MT_SAMSUPERMISSILE) --Used as base for the Power Beam combo too.
addHook("MobjSpawn", AddSamusShot, MT_SPCHARGECOMBO)
addHook("MobjSpawn", AddSamusShot, MT_ICCHARGECOMBO)
addHook("MobjSpawn", AddSamusShot, MT_SAMPOWERBOMB)
addHook("MobjSpawn", AddSamusShot, MT_SAMMORPHBOMB)

addHook("MobjSpawn", AddSamusShot, MT_PBSHOT)
addHook("MobjSpawn", AddSamusShot, MT_SPSHOT)
addHook("MobjSpawn", AddSamusShot, MT_WVSHOT) --This and MT_WVCHARGESHOT are both also used for the Wave Beam Combo.
addHook("MobjSpawn", AddSamusShot, MT_ICSHOT)
addHook("MobjSpawn", AddSamusShot, MT_PLSHOT) --Used for Gattling Vortex Combo too.
addHook("MobjSpawn", AddSamusShot, MT_HBSHOT)